aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorAneesh V <aneesh@ti.com>2011-06-28 11:34:34 -0500
committerNishanth Menon <nm@ti.com>2011-06-29 13:31:01 -0700
commit31e972b0df4c97226045edb8938eb8d98775a957 (patch)
tree5a79fcd6873c10583d39b8f93d47967abe9fb6d6 /arch
parentfc1dec3f80bdf1c9c184079aabbee0d0145f6520 (diff)
downloadkernel_samsung_tuna-31e972b0df4c97226045edb8938eb8d98775a957.zip
kernel_samsung_tuna-31e972b0df4c97226045edb8938eb8d98775a957.tar.gz
kernel_samsung_tuna-31e972b0df4c97226045edb8938eb8d98775a957.tar.bz2
OMAP4: Add EMIF driver support
This patch adds EMIF driver registration support with hwmod. This patch adds auto-generated header files for EMIF and DMM IP blocks. The scripts are updated accordingly We now have a set of APIs for: Add a set of APIs for the following: 1. Calculating the values of emif configuration registers based on the organization of memory in the device, the AC timing parameters of the memory device, data from JESD209-2 - the LPDDR2 spec, and the frequency at which the LPDDR2 interface is operating. 2. Updating the EMIF settings on: a. frequency change b. voltage ramp c. temperature change OMAP4 EMIF driver also supports the lppddr2 thermal management support as expected by JEDEC standards. [girishsg@ti.com: Helped in fixing the comments] Signed-off-by: Girish S G <girishsg@ti.com> [vvardhan@ti.com: contributed towards thermal support] Signed-off-by: Vibhore Vardhan <vvardhan@ti.com> [b-cousson@ti.com, santosh.shilimkar@ti.com: contributed for hwmod and basic driver support, Thermal] Signed-off-by: Benoit Cousson <b-cousson@ti.com> Signed-off-by: Santosh Shilimkar <santosh.shilimkar@ti.com> Signed-off-by: Aneesh V <aneesh@ti.com>
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/mach-omap2/Makefile1
-rw-r--r--arch/arm/mach-omap2/dpll44xx.c4
-rw-r--r--arch/arm/mach-omap2/emif.c1253
-rw-r--r--arch/arm/mach-omap2/include/mach/emif-44xx.h526
-rw-r--r--arch/arm/mach-omap2/include/mach/emif.h292
-rw-r--r--arch/arm/mach-omap2/include/mach/lpddr2-jedec.h147
-rw-r--r--arch/arm/mach-omap2/lpddr2_jedec_data.c132
-rw-r--r--arch/arm/mach-omap2/omap_hwmod_44xx_data.c106
8 files changed, 2460 insertions, 1 deletions
diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
index 86c48b2..023f828 100644
--- a/arch/arm/mach-omap2/Makefile
+++ b/arch/arm/mach-omap2/Makefile
@@ -15,6 +15,7 @@ clock-common = clock.o clock_common_data.o \
obj-$(CONFIG_ARCH_OMAP2) += $(omap-2-3-common) $(hwmod-common)
obj-$(CONFIG_ARCH_OMAP3) += $(omap-2-3-common) $(hwmod-common)
obj-$(CONFIG_ARCH_OMAP4) += prm44xx.o $(hwmod-common)
+obj-$(CONFIG_ARCH_OMAP4) += emif.o lpddr2_jedec_data.o
obj-$(CONFIG_OMAP_MCBSP) += mcbsp.o
diff --git a/arch/arm/mach-omap2/dpll44xx.c b/arch/arm/mach-omap2/dpll44xx.c
index 9327596..0804f4a 100644
--- a/arch/arm/mach-omap2/dpll44xx.c
+++ b/arch/arm/mach-omap2/dpll44xx.c
@@ -18,6 +18,7 @@
#include <plat/clock.h>
#include <plat/common.h>
+#include <mach/emif.h>
#include <mach/omap4-common.h>
#include "clock.h"
@@ -67,10 +68,11 @@ int omap4_core_dpll_m2_set_rate(struct clk *clk, unsigned long rate)
clkdm_wakeup(l3_emif_clkdm);
/*
- * TODO: Program EMIF timing parameters in EMIF shadow registers
+ * Program EMIF timing parameters in EMIF shadow registers
* for targetted DRR clock.
* DDR Clock = core_dpll_m2 / 2
*/
+ omap_emif_setup_registers(validrate >> 1, LPDDR2_VOLTAGE_STABLE);
/*
* FREQ_UPDATE sequence:
diff --git a/arch/arm/mach-omap2/emif.c b/arch/arm/mach-omap2/emif.c
new file mode 100644
index 0000000..923118f
--- /dev/null
+++ b/arch/arm/mach-omap2/emif.c
@@ -0,0 +1,1253 @@
+/*
+ * OMAP4 EMIF platform driver
+ *
+ * Copyright (C) 2010 Texas Instruments, Inc.
+ *
+ * Santosh Shilimkar <santosh.shilimkar@ti.com>
+ * Aneesh V <aneesh@ti.com>
+ * Vibhore Vardhan <vvardhan@ti.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 <linux/init.h>
+#include <linux/module.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include <plat/omap_hwmod.h>
+#include <plat/omap_device.h>
+#include <mach/emif-44xx.h>
+#include <mach/emif.h>
+#include <mach/lpddr2-jedec.h>
+#include <mach/omap4-common.h>
+
+/* Utility macro for masking and setting a field in a register/variable */
+#define mask_n_set(reg, shift, msk, val) \
+ (reg) = (((reg) & ~(msk))|(((val) << (shift)) & msk))
+
+struct emif_instance {
+ void __iomem *base;
+ u16 irq;
+ struct platform_device *pdev;
+};
+static struct emif_instance emif[EMIF_NUM_INSTANCES];
+static struct emif_regs *emif_curr_regs[EMIF_NUM_INSTANCES];
+static struct emif_regs *emif1_regs_cache[EMIF_MAX_NUM_FREQUENCIES];
+static struct emif_regs *emif2_regs_cache[EMIF_MAX_NUM_FREQUENCIES];
+static struct emif_device_details *emif_devices[2];
+static u32 emif_temperature_level[EMIF_NUM_INSTANCES] = { SDRAM_TEMP_NOMINAL,
+ SDRAM_TEMP_NOMINAL
+};
+
+static u32 emif_notify_pending;
+static u32 emif_thermal_handling_pending;
+static u32 T_den, T_num;
+
+static struct omap_device_pm_latency omap_emif_latency[] = {
+ [0] = {
+ .deactivate_func = omap_device_idle_hwmods,
+ .activate_func = omap_device_enable_hwmods,
+ .flags = OMAP_DEVICE_LATENCY_AUTO_ADJUST,
+ },
+};
+
+static void do_cancel_out(u32 *num, u32 *den, u32 factor)
+{
+ while (1) {
+ if (((*num) / factor * factor == (*num)) &&
+ ((*den) / factor * factor == (*den))) {
+ (*num) /= factor;
+ (*den) /= factor;
+ } else
+ break;
+ }
+}
+
+static void cancel_out(u32 *num, u32 *den)
+{
+ do_cancel_out(num, den, 2);
+ do_cancel_out(num, den, 3);
+ do_cancel_out(num, den, 5);
+ do_cancel_out(num, den, 7);
+ do_cancel_out(num, den, 11);
+ do_cancel_out(num, den, 13);
+ do_cancel_out(num, den, 17);
+}
+
+/*
+ * Get the period in ns (in fraction form) for a given frequency:
+ * Getting it in fraction form is for better accuracy in integer arithmetics
+ * freq_hz - input: frequency in Hertz
+ * den_limit - input: upper limit for denominator. see the description of
+ * EMIF_PERIOD_DEN_LIMIT for more details
+ * period_den - output: pointer to denominator of period in ns
+ * period_num - output: pointer to numerator of period in ns
+ */
+static void get_period(u32 freq_hz, u32 den_limit, u32 *period_num,
+ u32 *period_den)
+{
+ *period_num = 1000000000; /* 10^9 to convert the period to 'ns' */
+ *period_den = freq_hz;
+ cancel_out(period_num, period_den);
+ /* make sure den <= den_limit at the cost of some accuracy */
+ while ((*period_den) > den_limit) {
+ *period_num /= 2;
+ *period_den /= 2;
+ }
+}
+
+/*
+ * Calculate the period of DDR clock from frequency value and set the
+ * denominator and numerator in global variables for easy access later
+ */
+static void set_ddr_clk_period(u32 freq)
+{
+ get_period(freq, EMIF_PERIOD_DEN_LIMIT, &T_num, &T_den);
+}
+
+/*
+ * Convert time in nano seconds to number of cycles of DDR clock
+ */
+static u32 ns_2_cycles(u32 ns)
+{
+ return ((ns * T_den) + T_num - 1) / T_num;
+}
+
+/*
+ * ns_2_cycles with the difference that the time passed is 2 times the actual
+ * value(to avoid fractions). The cycles returned is for the original value of
+ * the timing parameter
+ */
+static u32 ns_x2_2_cycles(u32 ns)
+{
+ return ((ns * T_den) + T_num * 2 - 1) / (T_num * 2);
+}
+
+/*
+ * Find addressing table index based on the device's type(S2 or S4) and
+ * density
+ */
+static s8 addressing_table_index(u8 type, u8 density, u8 width)
+{
+ u8 index;
+ if (unlikely((density > LPDDR2_DENSITY_8Gb) ||
+ (width == LPDDR2_IO_WIDTH_8)))
+ return -1;
+
+ /*
+ * Look at the way ADDR_TABLE_INDEX* values have been defined
+ * in emif.h compared to LPDDR2_DENSITY_* values
+ * The table is layed out in the increasing order of density
+ * (ignoring type). The exceptions 1GS2 and 2GS2 have been placed
+ * at the end
+ */
+ if ((type == LPDDR2_TYPE_S2) && (density == LPDDR2_DENSITY_1Gb))
+ index = ADDR_TABLE_INDEX1GS2;
+ else if ((type == LPDDR2_TYPE_S2) && (density == LPDDR2_DENSITY_2Gb))
+ index = ADDR_TABLE_INDEX2GS2;
+ else
+ index = density;
+
+ pr_debug("emif: addressing table index %d", index);
+
+ return index;
+}
+
+/*
+ * Find the the right timing table from the array of timing
+ * tables of the device using DDR clock frequency
+ */
+static const struct lpddr2_timings *get_timings_table(
+ const struct lpddr2_timings * const *device_timings, u32 freq)
+{
+ u32 i, temp, freq_nearest;
+ const struct lpddr2_timings *timings = NULL;
+
+ emif_assert(freq <= MAX_LPDDR2_FREQ);
+ emif_assert(device_timings);
+
+ /*
+ * Start with the maximum allowed frequency - that is always safe
+ */
+ freq_nearest = MAX_LPDDR2_FREQ;
+ /*
+ * Find the timings table that has the max frequency value:
+ * i. Above or equal to the DDR frequency - safe
+ * ii. The lowest that satisfies condition (i) - optimal
+ */
+ for (i = 0; i < MAX_NUM_SPEEDBINS; i++) {
+ if (device_timings[i]) {
+ temp = device_timings[i]->max_freq;
+ if ((temp >= freq) && (temp <= freq_nearest)) {
+ freq_nearest = temp;
+ timings = device_timings[i];
+ }
+ }
+ }
+ pr_debug("emif: timings table: %d", freq_nearest);
+ return timings;
+}
+
+/*
+ * Finds the value of emif_sdram_config_reg
+ * All parameters are programmed based on the device on CS0.
+ * If there is a device on CS1, it will be same as that on CS0 or
+ * it will be NVM. We don't support NVM yet.
+ * If cs1_device pointer is NULL it is assumed that there is no device
+ * on CS1
+ */
+static u32 get_sdram_config_reg(const struct lpddr2_device_info *cs0_device,
+ const struct lpddr2_device_info *cs1_device,
+ const struct lpddr2_addressing *addressing,
+ u8 RL)
+{
+ u32 config_reg = 0;
+
+ mask_n_set(config_reg, OMAP44XX_REG_SDRAM_TYPE_SHIFT,
+ OMAP44XX_REG_SDRAM_TYPE_MASK, cs0_device->type + 4);
+
+ mask_n_set(config_reg, OMAP44XX_REG_IBANK_POS_SHIFT,
+ OMAP44XX_REG_IBANK_POS_MASK,
+ EMIF_INTERLEAVING_POLICY_MAX_INTERLEAVING);
+
+ mask_n_set(config_reg, OMAP44XX_REG_NARROW_MODE_SHIFT,
+ OMAP44XX_REG_NARROW_MODE_MASK, cs0_device->io_width);
+
+ mask_n_set(config_reg, OMAP44XX_REG_CL_SHIFT, OMAP44XX_REG_CL_MASK, RL);
+
+ mask_n_set(config_reg, OMAP44XX_REG_ROWSIZE_SHIFT,
+ OMAP44XX_REG_ROWSIZE_MASK,
+ addressing->row_sz[cs0_device->io_width]);
+
+ mask_n_set(config_reg, OMAP44XX_REG_IBANK_SHIFT,
+ OMAP44XX_REG_IBANK_MASK, addressing->num_banks);
+
+ mask_n_set(config_reg, OMAP44XX_REG_EBANK_SHIFT,
+ OMAP44XX_REG_EBANK_MASK,
+ (cs1_device ? EBANK_CS1_EN : EBANK_CS1_DIS));
+
+ mask_n_set(config_reg, OMAP44XX_REG_PAGESIZE_SHIFT,
+ OMAP44XX_REG_PAGESIZE_MASK,
+ addressing->col_sz[cs0_device->io_width]);
+
+ return config_reg;
+}
+
+static u32 get_sdram_ref_ctrl(u32 freq,
+ const struct lpddr2_addressing *addressing)
+{
+ u32 ref_ctrl = 0, val = 0, freq_khz;
+ freq_khz = freq / 1000;
+ /*
+ * refresh rate to be set is 'tREFI * freq in MHz
+ * division by 10000 to account for khz and x10 in t_REFI_us_x10
+ */
+ val = addressing->t_REFI_us_x10 * freq_khz / 10000;
+ mask_n_set(ref_ctrl, OMAP44XX_REG_REFRESH_RATE_SHIFT,
+ OMAP44XX_REG_REFRESH_RATE_MASK, val);
+
+ /* enable refresh */
+ mask_n_set(ref_ctrl, OMAP44XX_REG_INITREF_DIS_SHIFT,
+ OMAP44XX_REG_INITREF_DIS_MASK, 1);
+ return ref_ctrl;
+}
+
+static u32 get_sdram_tim_1_reg(const struct lpddr2_timings *timings,
+ const struct lpddr2_min_tck *min_tck,
+ const struct lpddr2_addressing *addressing)
+{
+ u32 tim1 = 0, val = 0;
+ val = max(min_tck->tWTR, ns_x2_2_cycles(timings->tWTRx2)) - 1;
+ mask_n_set(tim1, OMAP44XX_REG_T_WTR_SHIFT, OMAP44XX_REG_T_WTR_MASK,
+ val);
+
+ if (addressing->num_banks == BANKS8)
+ val = (timings->tFAW * T_den + 4 * T_num - 1) / (4 * T_num) - 1;
+ else
+ val = max(min_tck->tRRD, ns_2_cycles(timings->tRRD)) - 1;
+
+ mask_n_set(tim1, OMAP44XX_REG_T_RRD_SHIFT, OMAP44XX_REG_T_RRD_MASK,
+ val);
+
+ val = ns_2_cycles(timings->tRASmin + timings->tRPab) - 1;
+ mask_n_set(tim1, OMAP44XX_REG_T_RC_SHIFT, OMAP44XX_REG_T_RC_MASK, val);
+
+ val = max(min_tck->tRAS_MIN, ns_2_cycles(timings->tRASmin)) - 1;
+ mask_n_set(tim1, OMAP44XX_REG_T_RAS_SHIFT, OMAP44XX_REG_T_RAS_MASK,
+ val);
+
+ val = max(min_tck->tWR, ns_2_cycles(timings->tWR)) - 1;
+ mask_n_set(tim1, OMAP44XX_REG_T_WR_SHIFT, OMAP44XX_REG_T_WR_MASK, val);
+
+ val = max(min_tck->tRCD, ns_2_cycles(timings->tRCD)) - 1;
+ mask_n_set(tim1, OMAP44XX_REG_T_RCD_SHIFT, OMAP44XX_REG_T_RCD_MASK,
+ val);
+ val = max(min_tck->tRP_AB, ns_2_cycles(timings->tRPab)) - 1;
+ mask_n_set(tim1, OMAP44XX_REG_T_RP_SHIFT, OMAP44XX_REG_T_RP_MASK, val);
+
+ return tim1;
+}
+
+/*
+ * Finds the de-rated value for EMIF_SDRAM_TIM1 register
+ * All the de-rated timings are limited to this register
+ * Adds 2ns instead of 1.875ns to the affected timings as
+ * we can not use float.
+ */
+static u32 get_sdram_tim_1_reg_derated(const struct lpddr2_timings *timings,
+ const struct lpddr2_min_tck *min_tck,
+ const struct lpddr2_addressing
+ *addressing)
+{
+ u32 tim1 = 0, val = 0;
+ val = max(min_tck->tWTR, ns_x2_2_cycles(timings->tWTRx2)) - 1;
+ mask_n_set(tim1, OMAP44XX_REG_T_WTR_SHIFT, OMAP44XX_REG_T_WTR_MASK,
+ val);
+
+ if (addressing->num_banks == BANKS8)
+ /*
+ * tFAW is approximately 4 times tRRD. So add 1.875*4 = 7.5 ~ 8
+ * to tFAW for de-rating
+ */
+ val = ((timings->tFAW + 8) * T_den + 4 * T_num - 1)
+ / (4 * T_num) - 1;
+ else
+ val = max(min_tck->tRRD, ns_2_cycles(timings->tRRD + 2)) - 1;
+
+ mask_n_set(tim1, OMAP44XX_REG_T_RRD_SHIFT, OMAP44XX_REG_T_RRD_MASK,
+ val);
+
+ val = ns_2_cycles(timings->tRASmin + timings->tRPab + 2) - 1;
+ mask_n_set(tim1, OMAP44XX_REG_T_RC_SHIFT, OMAP44XX_REG_T_RC_MASK, val);
+
+ val = max(min_tck->tRAS_MIN, ns_2_cycles(timings->tRASmin + 2)) - 1;
+ mask_n_set(tim1, OMAP44XX_REG_T_RAS_SHIFT, OMAP44XX_REG_T_RAS_MASK,
+ val);
+
+ val = max(min_tck->tWR, ns_2_cycles(timings->tWR)) - 1;
+ mask_n_set(tim1, OMAP44XX_REG_T_WR_SHIFT, OMAP44XX_REG_T_WR_MASK, val);
+
+ val = max(min_tck->tRCD, ns_2_cycles(timings->tRCD + 2)) - 1;
+ mask_n_set(tim1, OMAP44XX_REG_T_RCD_SHIFT, OMAP44XX_REG_T_RCD_MASK,
+ val);
+ val = max(min_tck->tRP_AB, ns_2_cycles(timings->tRPab + 2)) - 1;
+ mask_n_set(tim1, OMAP44XX_REG_T_RP_SHIFT, OMAP44XX_REG_T_RP_MASK, val);
+
+ return tim1;
+}
+
+static u32 get_sdram_tim_2_reg(const struct lpddr2_timings *timings,
+ const struct lpddr2_min_tck *min_tck)
+{
+ u32 tim2 = 0, val = 0;
+ val = max(min_tck->tCKE, timings->tCKE) - 1;
+ mask_n_set(tim2, OMAP44XX_REG_T_CKE_SHIFT, OMAP44XX_REG_T_CKE_MASK,
+ val);
+
+ val = max(min_tck->tRTP, ns_x2_2_cycles(timings->tRTPx2)) - 1;
+ mask_n_set(tim2, OMAP44XX_REG_T_RTP_SHIFT, OMAP44XX_REG_T_RTP_MASK,
+ val);
+
+ /*
+ * tXSRD = tRFCab + 10 ns. XSRD and XSNR should have the
+ * same value
+ */
+ val = ns_2_cycles(timings->tXSR) - 1;
+ mask_n_set(tim2, OMAP44XX_REG_T_XSRD_SHIFT, OMAP44XX_REG_T_XSRD_MASK,
+ val);
+ mask_n_set(tim2, OMAP44XX_REG_T_XSNR_SHIFT, OMAP44XX_REG_T_XSNR_MASK,
+ val);
+
+ val = max(min_tck->tXP, ns_x2_2_cycles(timings->tXPx2)) - 1;
+ mask_n_set(tim2, OMAP44XX_REG_T_XP_SHIFT, OMAP44XX_REG_T_XP_MASK, val);
+
+ return tim2;
+}
+
+static u32 get_sdram_tim_3_reg(const struct lpddr2_timings *timings,
+ const struct lpddr2_min_tck *min_tck,
+ const struct lpddr2_addressing *addressing)
+{
+ u32 tim3 = 0, val = 0;
+ val = min(timings->tRASmax * 10 / addressing->t_REFI_us_x10 - 1, 0xF);
+ mask_n_set(tim3, OMAP44XX_REG_T_RAS_MAX_SHIFT,
+ OMAP44XX_REG_T_RAS_MAX_MASK, val);
+
+ val = ns_2_cycles(timings->tRFCab) - 1;
+ mask_n_set(tim3, OMAP44XX_REG_T_RFC_SHIFT, OMAP44XX_REG_T_RFC_MASK,
+ val);
+
+ val = ns_x2_2_cycles(timings->tDQSCKMAXx2) - 1;
+ mask_n_set(tim3, OMAP44XX_REG_T_TDQSCKMAX_SHIFT,
+ OMAP44XX_REG_T_TDQSCKMAX_MASK, val);
+
+ val = ns_2_cycles(timings->tZQCS) - 1;
+ mask_n_set(tim3, OMAP44XX_REG_ZQ_ZQCS_SHIFT,
+ OMAP44XX_REG_ZQ_ZQCS_MASK, val);
+
+ val = max(min_tck->tCKESR, ns_2_cycles(timings->tCKESR)) - 1;
+ mask_n_set(tim3, OMAP44XX_REG_T_CKESR_SHIFT,
+ OMAP44XX_REG_T_CKESR_MASK, val);
+
+ return tim3;
+}
+
+static u32 get_zq_config_reg(const struct lpddr2_device_info *cs1_device,
+ const struct lpddr2_addressing *addressing,
+ bool volt_ramp)
+{
+ u32 zq = 0, val = 0;
+ if (volt_ramp)
+ val =
+ EMIF_ZQCS_INTERVAL_DVFS_IN_US * 10 /
+ addressing->t_REFI_us_x10;
+ else
+ val =
+ EMIF_ZQCS_INTERVAL_NORMAL_IN_US * 10 /
+ addressing->t_REFI_us_x10;
+ mask_n_set(zq, OMAP44XX_REG_ZQ_REFINTERVAL_SHIFT,
+ OMAP44XX_REG_ZQ_REFINTERVAL_MASK, val);
+
+ mask_n_set(zq, OMAP44XX_REG_ZQ_ZQCL_MULT_SHIFT,
+ OMAP44XX_REG_ZQ_ZQCL_MULT_MASK, REG_ZQ_ZQCL_MULT - 1);
+
+ mask_n_set(zq, OMAP44XX_REG_ZQ_ZQINIT_MULT_SHIFT,
+ OMAP44XX_REG_ZQ_ZQINIT_MULT_MASK, REG_ZQ_ZQINIT_MULT - 1);
+
+ mask_n_set(zq, OMAP44XX_REG_ZQ_SFEXITEN_SHIFT,
+ OMAP44XX_REG_ZQ_SFEXITEN_MASK, REG_ZQ_SFEXITEN_ENABLE);
+
+ /*
+ * Assuming that two chipselects have a single calibration resistor
+ * If there are indeed two calibration resistors, then this flag should
+ * be enabled to take advantage of dual calibration feature.
+ * This data should ideally come from board files. But considering
+ * that none of the boards today have calibration resistors per CS,
+ * it would be an unnecessary overhead.
+ */
+ mask_n_set(zq, OMAP44XX_REG_ZQ_DUALCALEN_SHIFT,
+ OMAP44XX_REG_ZQ_DUALCALEN_MASK, REG_ZQ_DUALCALEN_DISABLE);
+
+ mask_n_set(zq, OMAP44XX_REG_ZQ_CS0EN_SHIFT,
+ OMAP44XX_REG_ZQ_CS0EN_MASK, REG_ZQ_CS0EN_ENABLE);
+
+ mask_n_set(zq, OMAP44XX_REG_ZQ_CS1EN_SHIFT,
+ OMAP44XX_REG_ZQ_CS1EN_MASK, (cs1_device ? 1 : 0));
+
+ return zq;
+}
+
+static u32 get_temp_alert_config(const struct lpddr2_device_info *cs1_device,
+ const struct lpddr2_addressing *addressing,
+ bool is_derated)
+{
+ u32 alert = 0, interval;
+ interval =
+ TEMP_ALERT_POLL_INTERVAL_MS * 10000 / addressing->t_REFI_us_x10;
+ if (is_derated)
+ interval *= 4;
+ mask_n_set(alert, OMAP44XX_REG_TA_REFINTERVAL_SHIFT,
+ OMAP44XX_REG_TA_REFINTERVAL_MASK, interval);
+
+ mask_n_set(alert, OMAP44XX_REG_TA_DEVCNT_SHIFT,
+ OMAP44XX_REG_TA_DEVCNT_MASK, TEMP_ALERT_CONFIG_DEVCT_1);
+
+ mask_n_set(alert, OMAP44XX_REG_TA_DEVWDT_SHIFT,
+ OMAP44XX_REG_TA_DEVWDT_MASK, TEMP_ALERT_CONFIG_DEVWDT_32);
+
+ mask_n_set(alert, OMAP44XX_REG_TA_SFEXITEN_SHIFT,
+ OMAP44XX_REG_TA_SFEXITEN_MASK, 1);
+
+ mask_n_set(alert, OMAP44XX_REG_TA_CS0EN_SHIFT,
+ OMAP44XX_REG_TA_CS0EN_MASK, 1);
+
+ mask_n_set(alert, OMAP44XX_REG_TA_CS1EN_SHIFT,
+ OMAP44XX_REG_TA_CS1EN_MASK, (cs1_device ? 1 : 0));
+
+ return alert;
+}
+
+static u32 get_read_idle_ctrl_reg(bool volt_ramp)
+{
+ u32 idle = 0, val = 0;
+ if (volt_ramp)
+ val = ns_2_cycles(READ_IDLE_INTERVAL_DVFS) / 64 - 1;
+ else
+ /*Maximum value in normal conditions - suggested by hw team */
+ val = 0x1FF;
+ mask_n_set(idle, OMAP44XX_REG_READ_IDLE_INTERVAL_SHIFT,
+ OMAP44XX_REG_READ_IDLE_INTERVAL_MASK, val);
+
+ mask_n_set(idle, OMAP44XX_REG_READ_IDLE_LEN_SHIFT,
+ OMAP44XX_REG_READ_IDLE_LEN_MASK, EMIF_REG_READ_IDLE_LEN_VAL);
+
+ return idle;
+}
+
+static u32 get_ddr_phy_ctrl_1(u32 freq, u8 RL)
+{
+ u32 phy = 0, val = 0;
+
+ mask_n_set(phy, OMAP44XX_REG_READ_LATENCY_SHIFT,
+ OMAP44XX_REG_READ_LATENCY_MASK, RL + 2);
+
+ if (freq <= 100000000)
+ val = EMIF_DLL_SLAVE_DLY_CTRL_100_MHZ_AND_LESS;
+ else if (freq <= 200000000)
+ val = EMIF_DLL_SLAVE_DLY_CTRL_200_MHZ;
+ else
+ val = EMIF_DLL_SLAVE_DLY_CTRL_400_MHZ;
+ mask_n_set(phy, OMAP44XX_REG_DLL_SLAVE_DLY_CTRL_SHIFT,
+ OMAP44XX_REG_DLL_SLAVE_DLY_CTRL_MASK, val);
+
+ /* Other fields are constant magic values. Hardcode them together */
+ mask_n_set(phy, OMAP44XX_EMIF_DDR_PHY_CTRL_1_BASE_VAL_SHIFT,
+ OMAP44XX_EMIF_DDR_PHY_CTRL_1_BASE_VAL_MASK,
+ EMIF_DDR_PHY_CTRL_1_BASE_VAL);
+
+ phy >>= OMAP44XX_REG_DDR_PHY_CTRL_1_SHIFT;
+
+ return phy;
+}
+
+/*
+ * Get the temperature level of the EMIF instance:
+ * Reads the MR4 register of attached SDRAM parts to find out the temperature
+ * level. If there are two parts attached(one on each CS), then the temperature
+ * level for the EMIF instance is the higher of the two temperatures.
+ */
+static u32 get_temperature_level(u32 emif_nr)
+{
+ u32 temp, tmp_temperature_level;
+ bool cs1_used;
+ void __iomem *base;
+
+ base = emif[emif_nr].base;
+
+ temp = __raw_readl(base + OMAP44XX_EMIF_SDRAM_CONFIG);
+ cs1_used = (temp & OMAP44XX_REG_EBANK_MASK) ? true : false;
+
+ /* Read mode register 4 */
+ __raw_writel(LPDDR2_MR4, base + OMAP44XX_EMIF_LPDDR2_MODE_REG_CFG);
+ tmp_temperature_level = __raw_readl(base +
+ OMAP44XX_EMIF_LPDDR2_MODE_REG_DATA);
+
+ tmp_temperature_level = (tmp_temperature_level &
+ MR4_SDRAM_REF_RATE_MASK) >>
+ MR4_SDRAM_REF_RATE_SHIFT;
+
+ if (cs1_used) {
+ __raw_writel(LPDDR2_MR4 | OMAP44XX_REG_CS_MASK,
+ base + OMAP44XX_EMIF_LPDDR2_MODE_REG_CFG);
+ temp = __raw_readl(base + OMAP44XX_EMIF_LPDDR2_MODE_REG_DATA);
+ temp = (temp & MR4_SDRAM_REF_RATE_MASK)
+ >> MR4_SDRAM_REF_RATE_SHIFT;
+ tmp_temperature_level = max(temp, tmp_temperature_level);
+ }
+
+ /* treat everything less than nominal(3) in MR4 as nominal */
+ if (unlikely(tmp_temperature_level < SDRAM_TEMP_NOMINAL))
+ tmp_temperature_level = SDRAM_TEMP_NOMINAL;
+
+ /* if we get reserved value in MR4 persist with the existing value */
+ if (unlikely(tmp_temperature_level == SDRAM_TEMP_RESERVED_4))
+ tmp_temperature_level = emif_temperature_level[emif_nr];
+
+ return tmp_temperature_level;
+}
+
+/*
+ * Program EMIF shadow registers:
+ * Sets the shadow registers using pre-caulated register values
+ * When volt_state indicates that this function is called just before
+ * a voltage scaling, set only the registers relevant for voltage scaling
+ * Otherwise, set all the registers relevant for a frequency change
+ */
+static void setup_registers(u32 emif_nr, struct emif_regs *regs, u32 volt_state)
+{
+ u32 temp, zq, read_idle;
+ void __iomem *base = emif[emif_nr].base;
+
+ __raw_writel(regs->ref_ctrl, base + OMAP44XX_EMIF_SDRAM_REF_CTRL_SHDW);
+
+ __raw_writel(regs->sdram_tim2, base + OMAP44XX_EMIF_SDRAM_TIM_2_SHDW);
+ __raw_writel(regs->sdram_tim3, base + OMAP44XX_EMIF_SDRAM_TIM_3_SHDW);
+ /*
+ * Do not change the RL part in PHY CTRL register
+ * RL is not changed during DVFS
+ */
+ temp = __raw_readl(base + OMAP44XX_EMIF_DDR_PHY_CTRL_1_SHDW);
+ mask_n_set(temp, OMAP44XX_REG_DDR_PHY_CTRL_1_SHDW_SHIFT,
+ OMAP44XX_REG_DDR_PHY_CTRL_1_SHDW_MASK,
+ regs->emif_ddr_phy_ctlr_1_final);
+ __raw_writel(temp, base + OMAP44XX_EMIF_DDR_PHY_CTRL_1_SHDW);
+ __raw_writel(EMIF_PWR_MGMT_CTRL_SHDW,
+ base + OMAP44XX_EMIF_PWR_MGMT_CTRL_SHDW);
+
+ __raw_writel(regs->temp_alert_config,
+ base + OMAP44XX_EMIF_TEMP_ALERT_CONFIG);
+
+ /*
+ * When voltage ramps zq calibration and forced read idle should
+ * happen more often.
+ */
+ if (volt_state == LPDDR2_VOLTAGE_RAMPING) {
+ zq = regs->zq_config_volt_ramp;
+ read_idle = regs->read_idle_ctrl_volt_ramp;
+ } else {
+ zq = regs->zq_config_normal;
+ read_idle = regs->read_idle_ctrl_normal;
+ }
+ __raw_writel(zq, base + OMAP44XX_EMIF_ZQ_CONFIG);
+ __raw_writel(read_idle, base + OMAP44XX_EMIF_READ_IDLE_CTRL_SHDW);
+
+ /*
+ * Reading back the last written register to ensure all writes are
+ * complete
+ */
+ temp = __raw_readl(base + OMAP44XX_EMIF_READ_IDLE_CTRL_SHDW);
+}
+
+/*
+ * setup_temperature_sensitive_regs() - set the timings for temperature
+ * sensitive registers. This happens once at initialization time based
+ * on the temperature at boot time and subsequently based on the temperature
+ * alert interrupt. Temperature alert can happen when the temperature
+ * increases or drops. So this function can have the effect of either
+ * derating the timings or going back to nominal values.
+ */
+static void setup_temperature_sensitive_regs(u32 emif_nr,
+ struct emif_regs *regs)
+{
+ u32 tim1, ref_ctrl, temp_alert_cfg;
+ void __iomem *base = emif[emif_nr].base;
+ u32 temperature = emif_temperature_level[emif_nr];
+
+ if (unlikely(temperature == SDRAM_TEMP_HIGH_DERATE_REFRESH)) {
+ tim1 = regs->sdram_tim1;
+ ref_ctrl = regs->ref_ctrl_derated;
+ temp_alert_cfg = regs->temp_alert_config_derated;
+ } else if (unlikely(temperature ==
+ SDRAM_TEMP_HIGH_DERATE_REFRESH_AND_TIMINGS)) {
+ tim1 = regs->sdram_tim1_derated;
+ ref_ctrl = regs->ref_ctrl_derated;
+ temp_alert_cfg = regs->temp_alert_config_derated;
+ } else {
+ /*
+ * Nominal timings - you may switch back to the
+ * nominal timings if the temperature falls
+ */
+ tim1 = regs->sdram_tim1;
+ ref_ctrl = regs->ref_ctrl;
+ temp_alert_cfg = regs->temp_alert_config;
+ }
+
+ __raw_writel(tim1, base + OMAP44XX_EMIF_SDRAM_TIM_1_SHDW);
+ __raw_writel(temp_alert_cfg, base + OMAP44XX_EMIF_TEMP_ALERT_CONFIG);
+ __raw_writel(ref_ctrl, base + OMAP44XX_EMIF_SDRAM_REF_CTRL_SHDW);
+
+ /* read back last written register to ensure write is complete */
+ __raw_readl(base + OMAP44XX_EMIF_SDRAM_REF_CTRL_SHDW);
+}
+
+static irqreturn_t handle_temp_alert(void __iomem *base, u32 emif_nr)
+{
+ u32 old_temperature_level;
+ old_temperature_level = emif_temperature_level[emif_nr];
+ emif_temperature_level[emif_nr] = get_temperature_level(emif_nr);
+
+ if (unlikely(emif_temperature_level[emif_nr] == old_temperature_level))
+ return IRQ_HANDLED;
+
+ emif_notify_pending |= (1 << emif_nr);
+ if (likely(emif_temperature_level[emif_nr] < old_temperature_level)) {
+ /* Temperature coming down - defer handling to thread */
+ emif_thermal_handling_pending |= (1 << emif_nr);
+ } else if (likely(emif_temperature_level[emif_nr] !=
+ SDRAM_TEMP_VERY_HIGH_SHUTDOWN)) {
+ /* Temperature is going up - handle immediately */
+ setup_temperature_sensitive_regs(emif_nr,
+ emif_curr_regs[emif_nr]);
+ /*
+ * EMIF de-rated timings register needs to be setup using
+ * freq update method only
+ */
+ omap4_prcm_freq_update();
+ }
+ return IRQ_WAKE_THREAD;
+}
+
+static void setup_volt_sensitive_registers(u32 emif_nr, struct emif_regs *regs,
+ u32 volt_state)
+{
+ u32 zq, read_idle;
+ void __iomem *base = emif[emif_nr].base;
+ /*
+ * When voltage ramps zq calibration and forced read idle should
+ * happen more often.
+ */
+ if (volt_state == LPDDR2_VOLTAGE_RAMPING) {
+ zq = regs->zq_config_volt_ramp;
+ read_idle = regs->read_idle_ctrl_volt_ramp;
+ } else {
+ zq = regs->zq_config_normal;
+ read_idle = regs->read_idle_ctrl_normal;
+ }
+ __raw_writel(zq, base + OMAP44XX_EMIF_ZQ_CONFIG);
+ __raw_writel(read_idle, base + OMAP44XX_EMIF_READ_IDLE_CTRL_SHDW);
+
+ /* read back last written register to ensure write is complete */
+ __raw_readl(base + OMAP44XX_EMIF_READ_IDLE_CTRL_SHDW);
+
+ return;
+}
+
+/*
+ * Interrupt Handler for EMIF1 and EMIF2
+ */
+static irqreturn_t emif_interrupt_handler(int irq, void *dev_id)
+{
+ void __iomem *base;
+ irqreturn_t ret = IRQ_HANDLED;
+ u32 sys, ll;
+ u8 emif_nr = EMIF1;
+
+ if (emif[EMIF2].irq == irq)
+ emif_nr = EMIF2;
+
+ base = emif[emif_nr].base;
+
+ /* Save the status and clear it */
+ sys = __raw_readl(base + OMAP44XX_EMIF_IRQSTATUS_SYS);
+ ll = __raw_readl(base + OMAP44XX_EMIF_IRQSTATUS_LL);
+ __raw_writel(sys, base + OMAP44XX_EMIF_IRQSTATUS_SYS);
+ __raw_writel(ll, base + OMAP44XX_EMIF_IRQSTATUS_LL);
+ /*
+ * Handle temperature alert
+ * Temperature alert should be same for both ports
+ * So, it's enough to process it for only one of the ports
+ */
+ if (sys & OMAP44XX_REG_TA_SYS_MASK)
+ ret = handle_temp_alert(base, emif_nr);
+
+ if (sys & OMAP44XX_REG_ERR_SYS_MASK)
+ pr_err("EMIF: Access error from EMIF%d SYS port - %x",
+ emif_nr, sys);
+
+ if (ll & OMAP44XX_REG_ERR_LL_MASK)
+ pr_err("EMIF Error: Access error from EMIF%d LL port - %x",
+ emif_nr, ll);
+
+ return ret;
+}
+
+static irqreturn_t emif_threaded_isr(int irq, void *dev_id)
+{
+ u8 emif_nr = EMIF1;
+ if (emif[EMIF2].irq == irq)
+ emif_nr = EMIF2;
+
+ if (emif_thermal_handling_pending & (1 << emif_nr)) {
+ setup_temperature_sensitive_regs(emif_nr,
+ emif_curr_regs[emif_nr]);
+ /*
+ * EMIF de-rated timings register needs to be setup using
+ * freq update method only
+ */
+ omap4_prcm_freq_update();
+ /* clear the bit */
+ emif_thermal_handling_pending &= ~(1 << emif_nr);
+ }
+ if (emif_notify_pending & (1 << emif_nr)) {
+ sysfs_notify(&(emif[emif_nr].pdev->dev.kobj), NULL,
+ "temperature");
+ kobject_uevent(&(emif[emif_nr].pdev->dev.kobj), KOBJ_CHANGE);
+ /* clear the bit */
+ emif_notify_pending &= ~(1 << emif_nr);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int __init setup_emif_interrupts(u32 emif_nr)
+{
+ u32 temp;
+ void __iomem *base = emif[emif_nr].base;
+ /* Clear any pendining interrupts */
+ __raw_writel(0xFFFFFFFF, base + OMAP44XX_EMIF_IRQSTATUS_SYS);
+ __raw_writel(0xFFFFFFFF, base + OMAP44XX_EMIF_IRQSTATUS_LL);
+
+ /* Enable the relevant interrupts for both LL and SYS */
+ temp = OMAP44XX_REG_EN_TA_SYS_MASK | OMAP44XX_REG_EN_ERR_SYS_MASK;
+ __raw_writel(temp, base + OMAP44XX_EMIF_IRQENABLE_SET_SYS);
+ __raw_writel(temp, base + OMAP44XX_EMIF_IRQENABLE_SET_LL);
+
+ /* Dummy read to make sure writes are complete */
+ __raw_readl(base + OMAP44XX_EMIF_IRQENABLE_SET_LL);
+
+ /* setup IRQ handlers */
+ return request_threaded_irq(emif[emif_nr].irq,
+ emif_interrupt_handler,
+ emif_threaded_isr,
+ IRQF_SHARED, emif[emif_nr].pdev->name,
+ emif[emif_nr].pdev);
+}
+
+static ssize_t emif_temperature_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ u32 temperature;
+ if (dev == &(emif[EMIF1].pdev->dev))
+ temperature = emif_temperature_level[EMIF1];
+ else if (dev == &(emif[EMIF2].pdev->dev))
+ temperature = emif_temperature_level[EMIF2];
+ else
+ return 0;
+
+ return snprintf(buf, 20, "%u\n", temperature);
+}
+static DEVICE_ATTR(temperature, S_IRUGO, emif_temperature_show, NULL);
+
+static int __devinit omap_emif_probe(struct platform_device *pdev)
+{
+ int id;
+ struct resource *res;
+
+ if (!pdev)
+ return -EINVAL;
+
+ id = pdev->id;
+ emif[id].pdev = pdev;
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!res) {
+ pr_err("EMIF %i Invalid IRQ resource\n", id);
+ return -ENODEV;
+ }
+
+ emif[id].irq = res->start;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ pr_err("EMIF%i Invalid mem resource\n", id);
+ return -ENODEV;
+ }
+
+ emif[id].base = ioremap(res->start, SZ_1M);
+ if (!emif[id].base) {
+ pr_err("Could not ioremap EMIF%i\n", id);
+ return -ENOMEM;
+ }
+
+ pr_info("EMIF%d is enabled with IRQ%d\n", id, emif[id].irq);
+
+ return 0;
+}
+
+static int emif_init(struct omap_hwmod *oh, void *user)
+{
+ char *name = "omap_emif";
+ struct omap_device *od;
+ static int id;
+
+ od = omap_device_build(name, id, oh, NULL, 0, omap_emif_latency,
+ ARRAY_SIZE(omap_emif_latency), false);
+ WARN(IS_ERR(od), "Can't build omap_device for %s:%s.\n",
+ name, oh->name);
+ id++;
+ return 0;
+
+}
+
+static void emif_calculate_regs(const struct emif_device_details *devices,
+ u32 freq, struct emif_regs *regs)
+{
+ u32 temp;
+ const struct lpddr2_addressing *addressing;
+ const struct lpddr2_timings *timings;
+ const struct lpddr2_min_tck *min_tck;
+ const struct lpddr2_device_info *cs0_device = devices->cs0_device;
+ const struct lpddr2_device_info *cs1_device = devices->cs1_device;
+
+ emif_assert(devices);
+ emif_assert(regs);
+ /*
+ * You can not have a device on CS1 without one on CS0
+ * So configuring EMIF without a device on CS0 doesn't
+ * make sense
+ */
+ emif_assert(cs0_device);
+ emif_assert(cs0_device->type != LPDDR2_TYPE_NVM);
+ /*
+ * If there is a device on CS1 it should be same type as CS0
+ * (or NVM. But NVM is not supported in this driver yet)
+ */
+ emif_assert((cs1_device == NULL) ||
+ (cs1_device->type == LPDDR2_TYPE_NVM) ||
+ (cs0_device->type == cs1_device->type));
+ emif_assert(freq <= MAX_LPDDR2_FREQ);
+
+ set_ddr_clk_period(freq);
+
+ /*
+ * The device on CS0 is used for all timing calculations
+ * There is only one set of registers for timings per EMIF. So, if the
+ * second CS(CS1) has a device, it should have the same timings as the
+ * device on CS0
+ */
+ timings = get_timings_table(cs0_device->device_timings, freq);
+ emif_assert(timings);
+ min_tck = cs0_device->min_tck;
+
+ temp =
+ addressing_table_index(cs0_device->type, cs0_device->density,
+ cs0_device->io_width);
+ emif_assert((temp >= 0));
+ addressing = &(lpddr2_jedec_addressing_table[temp]);
+ emif_assert(addressing);
+
+ regs->RL_final = timings->RL;
+ /*
+ * Initial value of EMIF_SDRAM_CONFIG corresponds to the base
+ * frequency - 19.2 MHz
+ */
+ regs->sdram_config_init =
+ get_sdram_config_reg(cs0_device, cs1_device, addressing,
+ RL_19_2_MHZ);
+
+ regs->sdram_config_final = regs->sdram_config_init;
+ mask_n_set(regs->sdram_config_final, OMAP44XX_REG_CL_SHIFT,
+ OMAP44XX_REG_CL_MASK, timings->RL);
+
+ regs->ref_ctrl = get_sdram_ref_ctrl(freq, addressing);
+ regs->ref_ctrl_derated = regs->ref_ctrl / 4;
+
+ regs->sdram_tim1 = get_sdram_tim_1_reg(timings, min_tck, addressing);
+
+ regs->sdram_tim1_derated =
+ get_sdram_tim_1_reg_derated(timings, min_tck, addressing);
+
+ regs->sdram_tim2 = get_sdram_tim_2_reg(timings, min_tck);
+
+ regs->sdram_tim3 = get_sdram_tim_3_reg(timings, min_tck, addressing);
+
+ regs->read_idle_ctrl_normal =
+ get_read_idle_ctrl_reg(LPDDR2_VOLTAGE_STABLE);
+
+ regs->read_idle_ctrl_volt_ramp =
+ get_read_idle_ctrl_reg(LPDDR2_VOLTAGE_RAMPING);
+
+ regs->zq_config_normal =
+ get_zq_config_reg(cs1_device, addressing, LPDDR2_VOLTAGE_STABLE);
+
+ regs->zq_config_volt_ramp =
+ get_zq_config_reg(cs1_device, addressing, LPDDR2_VOLTAGE_RAMPING);
+
+ regs->temp_alert_config =
+ get_temp_alert_config(cs1_device, addressing, false);
+
+ regs->temp_alert_config_derated =
+ get_temp_alert_config(cs1_device, addressing, true);
+
+ regs->emif_ddr_phy_ctlr_1_init =
+ get_ddr_phy_ctrl_1(EMIF_FREQ_19_2_MHZ, RL_19_2_MHZ);
+
+ regs->emif_ddr_phy_ctlr_1_final =
+ get_ddr_phy_ctrl_1(freq, regs->RL_final);
+
+ /* save the frequency in the struct to act as a tag when cached */
+ regs->freq = freq;
+
+ pr_debug("Calculated EMIF configuration register values "
+ "for %d MHz", freq / 1000000);
+ pr_debug("sdram_config_init\t\t: 0x%08x\n", regs->sdram_config_init);
+ pr_debug("sdram_config_final\t\t: 0x%08x\n", regs->sdram_config_final);
+ pr_debug("sdram_ref_ctrl\t\t: 0x%08x\n", regs->ref_ctrl);
+ pr_debug("sdram_ref_ctrl_derated\t\t: 0x%08x\n",
+ regs->ref_ctrl_derated);
+ pr_debug("sdram_tim_1_reg\t\t: 0x%08x\n", regs->sdram_tim1);
+ pr_debug("sdram_tim_1_reg_derated\t\t: 0x%08x\n",
+ regs->sdram_tim1_derated);
+ pr_debug("sdram_tim_2_reg\t\t: 0x%08x\n", regs->sdram_tim2);
+ pr_debug("sdram_tim_3_reg\t\t: 0x%08x\n", regs->sdram_tim3);
+ pr_debug("emif_read_idle_ctrl_normal\t: 0x%08x\n",
+ regs->read_idle_ctrl_normal);
+ pr_debug("emif_read_idle_ctrl_dvfs\t: 0x%08x\n",
+ regs->read_idle_ctrl_volt_ramp);
+ pr_debug("zq_config_reg_normal\t: 0x%08x\n", regs->zq_config_normal);
+ pr_debug("zq_config_reg_dvfs\t\t: 0x%08x\n", regs->zq_config_volt_ramp);
+ pr_debug("temp_alert_config\t: 0x%08x\n", regs->temp_alert_config);
+ pr_debug("emif_ddr_phy_ctlr_1_init\t: 0x%08x\n",
+ regs->emif_ddr_phy_ctlr_1_init);
+ pr_debug("emif_ddr_phy_ctlr_1_final\t: 0x%08x\n",
+ regs->emif_ddr_phy_ctlr_1_final);
+}
+
+/*
+ * get_regs() - gets the cached emif_regs structure for a given EMIF instance
+ * (emif_nr) for a given frequency(freq):
+ *
+ * As an optimization, only one cache array(that of EMIF1) if both EMIF1 and
+ * EMIF2 has identical devices
+ *
+ * If we do not have an entry corresponding to the frequency given, we
+ * allocate a new entry and calculate the values
+ */
+static struct emif_regs *get_regs(u32 emif_nr, u32 freq)
+{
+ int i;
+ struct emif_regs **regs_cache;
+ struct emif_regs *regs = NULL;
+
+ /*
+ * If EMIF2 has the same devices as EMIF1 use the register
+ * cache of EMIF1
+ */
+ if ((emif_nr == EMIF1) ||
+ ((emif_nr == EMIF2)
+ && (emif_devices[EMIF1] == emif_devices[EMIF2])))
+ regs_cache = emif1_regs_cache;
+ else
+ regs_cache = emif2_regs_cache;
+
+ for (i = 0; i < EMIF_MAX_NUM_FREQUENCIES && regs_cache[i]; i++) {
+ if (regs_cache[i]->freq == freq) {
+ regs = regs_cache[i];
+ break;
+ }
+ }
+
+ /*
+ * If we don't have an entry for this frequency in the cache create one
+ * and calculate the values
+ */
+ if (!regs) {
+ regs = kmalloc(sizeof(struct emif_regs), GFP_ATOMIC);
+ if (!regs)
+ return NULL;
+ emif_calculate_regs(emif_devices[emif_nr], freq, regs);
+
+ /*
+ * Now look for an un-used entry in the cache and save the
+ * newly created struct. If there are no free entries
+ * over-write the last entry
+ */
+ for (i = 0; i < EMIF_MAX_NUM_FREQUENCIES && regs_cache[i]; i++)
+ ;
+
+ if (i >= EMIF_MAX_NUM_FREQUENCIES) {
+ pr_warning("emif: emif regs_cache full - more number"
+ " of frequencies used than expected!!");
+ i = EMIF_MAX_NUM_FREQUENCIES - 1;
+ kfree(regs_cache[i]);
+ }
+ regs_cache[i] = regs;
+ }
+ return regs;
+}
+
+static int do_emif_setup_registers(u32 emif_nr, u32 freq, u32 volt_state)
+{
+ struct emif_regs *regs;
+ regs = get_regs(emif_nr, freq);
+ if (!regs)
+ return -ENOMEM;
+
+ emif_curr_regs[emif_nr] = regs;
+ setup_registers(emif_nr, regs, volt_state);
+ setup_temperature_sensitive_regs(emif_nr, regs);
+
+ return 0;
+}
+
+static int do_setup_device_details(u32 emif_nr,
+ const struct emif_device_details *devices)
+{
+ if (!emif_devices[emif_nr]) {
+ emif_devices[emif_nr] =
+ kmalloc(sizeof(struct emif_device_details), GFP_KERNEL);
+ if (!emif_devices[emif_nr])
+ return -ENOMEM;
+ *emif_devices[emif_nr] = *devices;
+ }
+
+ return 0;
+}
+
+/*
+ * Initialize the temperature level and setup the sysfs nodes
+ * and uvent for temperature monitoring
+ */
+static void init_temperature(u32 emif_nr)
+{
+ if (!emif_devices[emif_nr])
+ return;
+
+ emif_temperature_level[emif_nr] = get_temperature_level(emif_nr);
+ WARN_ON(device_create_file(&(emif[emif_nr].pdev->dev),
+ &dev_attr_temperature));
+ kobject_uevent(&(emif[emif_nr].pdev->dev.kobj), KOBJ_ADD);
+
+ if (emif_temperature_level[emif_nr] == SDRAM_TEMP_VERY_HIGH_SHUTDOWN)
+ pr_emerg("EMIF %d: SDRAM temperature exceeds operating"
+ "limit.. Needs shut down!!!", emif_nr + 1);
+}
+
+/*
+ * omap_emif_device_init needs to be done before
+ * ddr reconfigure function call.
+ * Hence omap_emif_device_init is a postcore_initcall.
+ */
+static int __init omap_emif_device_init(void)
+{
+ /*
+ * To avoid code running on other OMAPs in
+ * multi-omap builds
+ */
+ if (!cpu_is_omap44xx())
+ return -ENODEV;
+
+ return omap_hwmod_for_each_by_class("emif", emif_init, NULL);
+}
+postcore_initcall(omap_emif_device_init);
+
+static struct platform_driver omap_emif_driver = {
+ .probe = omap_emif_probe,
+ .driver = {
+ .name = "omap_emif",
+ },
+};
+
+static int __init omap_emif_register(void)
+{
+ return platform_driver_register(&omap_emif_driver);
+}
+postcore_initcall(omap_emif_register);
+
+/*
+ * omap_emif_notify_voltage - setup the voltage sensitive
+ * registers based on the voltage situation (voltage ramping or stable)
+ * read_idle_ctrl and zq_config are the registers that are voltage sensitive
+ * They need to have a very safe value(more frequent zq calibration and
+ * read idle forcing) when voltage is scaling and can have a more relaxed
+ * nominal value(frequency dependent) when voltage is stable
+ */
+int omap_emif_notify_voltage(u32 volt_state)
+{
+ if (likely(emif_curr_regs[EMIF1]))
+ setup_volt_sensitive_registers(EMIF1, emif_curr_regs[EMIF1],
+ volt_state);
+
+ if (likely(emif_curr_regs[EMIF2]))
+ setup_volt_sensitive_registers(EMIF2, emif_curr_regs[EMIF2],
+ volt_state);
+
+ if (unlikely(!emif_curr_regs[EMIF1] && !emif_curr_regs[EMIF2])) {
+ pr_err("emif: voltage state notification came before the"
+ " initial setup - ignoring the notification");
+ return -EINVAL;
+ }
+
+ /*
+ * EMIF read-idle control needs to be setup using
+ * freq update method only
+ */
+ return omap4_prcm_freq_update();
+}
+
+/*
+ * omap_emif_setup_registers - setup the shadow registers for a given
+ * frequency. This will be typically followed by a FREQ_UPDATE procedure
+ * to lock at the new frequency and this will update the EMIF main registers
+ * with shadow register values
+ */
+int omap_emif_setup_registers(u32 freq, u32 volt_state)
+{
+ int err = 0;
+ if (likely(emif_devices[EMIF1]))
+ err = do_emif_setup_registers(EMIF1, freq, volt_state);
+ if (likely(!err && emif_devices[EMIF2]))
+ err = do_emif_setup_registers(EMIF2, freq, volt_state);
+ return err;
+}
+
+/*
+ * omap_emif_setup_device_details - save the SDRAM device details passed
+ * from the board file
+ */
+int omap_emif_setup_device_details(const struct emif_device_details
+ *emif1_devices,
+ const struct emif_device_details
+ *emif2_devices)
+{
+ if (emif1_devices)
+ BUG_ON(do_setup_device_details(EMIF1, emif1_devices));
+
+ /*
+ * If memory devices connected to both the EMIFs are identical
+ * (which is normally the case), then no need to calculate the
+ * registers again for EMIF1 and allocate the structure for registers
+ */
+ if (emif2_devices && (emif1_devices != emif2_devices))
+ BUG_ON(do_setup_device_details(EMIF2, emif2_devices));
+ else if (emif2_devices) {
+ emif_devices[EMIF2] = emif_devices[EMIF1];
+ /* call for temperature related setup */
+ BUG_ON(do_setup_device_details(EMIF2, emif2_devices));
+ }
+
+ return 0;
+}
+
+/*
+ * omap_init_emif_timings - reprogram EMIF timing parameters
+ *
+ * Sets the CORE DPLL3 M2 divider to the same value that it's at
+ * currently. This has the effect of setting the EMIF DDR AC timing
+ * registers to the values currently defined by the kernel.
+ */
+static int __init omap_init_emif_timings(void)
+{
+ struct clk *dpll_core_m2_clk;
+ int ret;
+ long rate;
+
+ /*
+ * Setup the initial temperatures sysfs nodes etc.
+ * Subsequent updates to temperature is done through interrupts
+ */
+ init_temperature(EMIF1);
+ init_temperature(EMIF2);
+
+ /* FREQ_UPDATE sequence isn't supported on early vesion */
+ if (omap_rev() == OMAP4430_REV_ES1_0)
+ return -EINVAL;
+
+ dpll_core_m2_clk = clk_get(NULL, "dpll_core_m2_ck");
+ if (!dpll_core_m2_clk)
+ pr_err("Could not get LPDDR2 clock - dpll_core_m2_ck\n");
+
+ rate = clk_get_rate(dpll_core_m2_clk);
+ pr_info("Reprogramming LPDDR2 timings to %ld Hz\n", rate >> 1);
+
+ ret = clk_set_rate(dpll_core_m2_clk, rate);
+ if (ret)
+ pr_err("Unable to set LPDDR2 rate to %ld:\n", rate);
+
+ /* registers are setup correctly - now enable interrupts */
+ if (emif_devices[EMIF1])
+ ret = setup_emif_interrupts(EMIF1);
+ if (!ret && emif_devices[EMIF2])
+ ret = setup_emif_interrupts(EMIF2);
+
+ clk_put(dpll_core_m2_clk);
+
+ return ret;
+}
+late_initcall(omap_init_emif_timings);
diff --git a/arch/arm/mach-omap2/include/mach/emif-44xx.h b/arch/arm/mach-omap2/include/mach/emif-44xx.h
new file mode 100644
index 0000000..97d2ab1
--- /dev/null
+++ b/arch/arm/mach-omap2/include/mach/emif-44xx.h
@@ -0,0 +1,526 @@
+/*
+ * OMAP44xx EMIF registers and bitfields
+ *
+ * Copyright (C) 2009-2010 Texas Instruments, Inc.
+ *
+ * Benoit Cousson (b-cousson@ti.com)
+ * Santosh Shilimkar (santosh.shilimkar@ti.com)
+ *
+ * This file is automatically generated from the OMAP hardware databases.
+ * We respectfully ask that any modifications to this file be coordinated
+ * with the public linux-omap@vger.kernel.org mailing list and the
+ * authors above to ensure that the autogeneration scripts are kept
+ * up-to-date with the file contents.
+ *
+ * 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 __ARCH_ARM_MACH_OMAP2_EMIF_44XX_H
+#define __ARCH_ARM_MACH_OMAP2_EMIF_44XX_H
+
+
+/* Base address */
+#define OMAP44XX_EMIF1 0x4c000000
+#define OMAP44XX_EMIF2 0x4d000000
+
+/* Registers offset */
+#define OMAP44XX_EMIF_MOD_ID_REV 0x0000
+#define OMAP44XX_EMIF_STATUS 0x0004
+#define OMAP44XX_EMIF_SDRAM_CONFIG 0x0008
+#define OMAP44XX_EMIF_SDRAM_CONFIG_2 0x000c
+#define OMAP44XX_EMIF_SDRAM_REF_CTRL 0x0010
+#define OMAP44XX_EMIF_SDRAM_REF_CTRL_SHDW 0x0014
+#define OMAP44XX_EMIF_SDRAM_TIM_1 0x0018
+#define OMAP44XX_EMIF_SDRAM_TIM_1_SHDW 0x001c
+#define OMAP44XX_EMIF_SDRAM_TIM_2 0x0020
+#define OMAP44XX_EMIF_SDRAM_TIM_2_SHDW 0x0024
+#define OMAP44XX_EMIF_SDRAM_TIM_3 0x0028
+#define OMAP44XX_EMIF_SDRAM_TIM_3_SHDW 0x002c
+#define OMAP44XX_EMIF_LPDDR2_NVM_TIM 0x0030
+#define OMAP44XX_EMIF_LPDDR2_NVM_TIM_SHDW 0x0034
+#define OMAP44XX_EMIF_PWR_MGMT_CTRL 0x0038
+#define OMAP44XX_EMIF_PWR_MGMT_CTRL_SHDW 0x003c
+#define OMAP44XX_EMIF_LPDDR2_MODE_REG_DATA 0x0040
+#define OMAP44XX_EMIF_LPDDR2_MODE_REG_CFG 0x0050
+#define OMAP44XX_EMIF_OCP_CONFIG 0x0054
+#define OMAP44XX_EMIF_OCP_CFG_VAL_1 0x0058
+#define OMAP44XX_EMIF_OCP_CFG_VAL_2 0x005c
+#define OMAP44XX_EMIF_IODFT_TLGC 0x0060
+#define OMAP44XX_EMIF_IODFT_CTRL_MISR_RSLT 0x0064
+#define OMAP44XX_EMIF_IODFT_ADDR_MISR_RSLT 0x0068
+#define OMAP44XX_EMIF_IODFT_DATA_MISR_RSLT_1 0x006c
+#define OMAP44XX_EMIF_IODFT_DATA_MISR_RSLT_2 0x0070
+#define OMAP44XX_EMIF_IODFT_DATA_MISR_RSLT_3 0x0074
+#define OMAP44XX_EMIF_PERF_CNT_1 0x0080
+#define OMAP44XX_EMIF_PERF_CNT_2 0x0084
+#define OMAP44XX_EMIF_PERF_CNT_CFG 0x0088
+#define OMAP44XX_EMIF_PERF_CNT_SEL 0x008c
+#define OMAP44XX_EMIF_PERF_CNT_TIM 0x0090
+#define OMAP44XX_EMIF_READ_IDLE_CTRL 0x0098
+#define OMAP44XX_EMIF_READ_IDLE_CTRL_SHDW 0x009c
+#define OMAP44XX_EMIF_IRQ_EOI 0x00a0
+#define OMAP44XX_EMIF_IRQSTATUS_RAW_SYS 0x00a4
+#define OMAP44XX_EMIF_IRQSTATUS_RAW_LL 0x00a8
+#define OMAP44XX_EMIF_IRQSTATUS_SYS 0x00ac
+#define OMAP44XX_EMIF_IRQSTATUS_LL 0x00b0
+#define OMAP44XX_EMIF_IRQENABLE_SET_SYS 0x00b4
+#define OMAP44XX_EMIF_IRQENABLE_SET_LL 0x00b8
+#define OMAP44XX_EMIF_IRQENABLE_CLR_SYS 0x00bc
+#define OMAP44XX_EMIF_IRQENABLE_CLR_LL 0x00c0
+#define OMAP44XX_EMIF_ZQ_CONFIG 0x00c8
+#define OMAP44XX_EMIF_TEMP_ALERT_CONFIG 0x00cc
+#define OMAP44XX_EMIF_OCP_ERR_LOG 0x00d0
+#define OMAP44XX_EMIF_DDR_PHY_CTRL_1 0x00e4
+#define OMAP44XX_EMIF_DDR_PHY_CTRL_1_SHDW 0x00e8
+#define OMAP44XX_EMIF_DDR_PHY_CTRL_2 0x00ec
+
+/* Registers shifts and masks */
+
+/* EMIF_MOD_ID_REV */
+#define OMAP44XX_REG_SCHEME_SHIFT 30
+#define OMAP44XX_REG_SCHEME_MASK (0x3 << 30)
+#define OMAP44XX_REG_MODULE_ID_SHIFT 16
+#define OMAP44XX_REG_MODULE_ID_MASK (0xfff << 16)
+#define OMAP44XX_REG_RTL_VERSION_SHIFT 11
+#define OMAP44XX_REG_RTL_VERSION_MASK (0x1f << 11)
+#define OMAP44XX_REG_MAJOR_REVISION_SHIFT 8
+#define OMAP44XX_REG_MAJOR_REVISION_MASK (0x7 << 8)
+#define OMAP44XX_REG_MINOR_REVISION_SHIFT 0
+#define OMAP44XX_REG_MINOR_REVISION_MASK (0x3f << 0)
+
+/* STATUS */
+#define OMAP44XX_REG_BE_SHIFT 31
+#define OMAP44XX_REG_BE_MASK (1 << 31)
+#define OMAP44XX_REG_DUAL_CLK_MODE_SHIFT 30
+#define OMAP44XX_REG_DUAL_CLK_MODE_MASK (1 << 30)
+#define OMAP44XX_REG_FAST_INIT_SHIFT 29
+#define OMAP44XX_REG_FAST_INIT_MASK (1 << 29)
+#define OMAP44XX_REG_PHY_DLL_READY_SHIFT 2
+#define OMAP44XX_REG_PHY_DLL_READY_MASK (1 << 2)
+
+/* SDRAM_CONFIG */
+#define OMAP44XX_REG_SDRAM_TYPE_SHIFT 29
+#define OMAP44XX_REG_SDRAM_TYPE_MASK (0x7 << 29)
+#define OMAP44XX_REG_IBANK_POS_SHIFT 27
+#define OMAP44XX_REG_IBANK_POS_MASK (0x3 << 27)
+#define OMAP44XX_REG_DDR_TERM_SHIFT 24
+#define OMAP44XX_REG_DDR_TERM_MASK (0x7 << 24)
+#define OMAP44XX_REG_DDR2_DDQS_SHIFT 23
+#define OMAP44XX_REG_DDR2_DDQS_MASK (1 << 23)
+#define OMAP44XX_REG_DYN_ODT_SHIFT 21
+#define OMAP44XX_REG_DYN_ODT_MASK (0x3 << 21)
+#define OMAP44XX_REG_DDR_DISABLE_DLL_SHIFT 20
+#define OMAP44XX_REG_DDR_DISABLE_DLL_MASK (1 << 20)
+#define OMAP44XX_REG_SDRAM_DRIVE_SHIFT 18
+#define OMAP44XX_REG_SDRAM_DRIVE_MASK (0x3 << 18)
+#define OMAP44XX_REG_CWL_SHIFT 16
+#define OMAP44XX_REG_CWL_MASK (0x3 << 16)
+#define OMAP44XX_REG_NARROW_MODE_SHIFT 14
+#define OMAP44XX_REG_NARROW_MODE_MASK (0x3 << 14)
+#define OMAP44XX_REG_CL_SHIFT 10
+#define OMAP44XX_REG_CL_MASK (0xf << 10)
+#define OMAP44XX_REG_ROWSIZE_SHIFT 7
+#define OMAP44XX_REG_ROWSIZE_MASK (0x7 << 7)
+#define OMAP44XX_REG_IBANK_SHIFT 4
+#define OMAP44XX_REG_IBANK_MASK (0x7 << 4)
+#define OMAP44XX_REG_EBANK_SHIFT 3
+#define OMAP44XX_REG_EBANK_MASK (1 << 3)
+#define OMAP44XX_REG_PAGESIZE_SHIFT 0
+#define OMAP44XX_REG_PAGESIZE_MASK (0x7 << 0)
+
+/* SDRAM_CONFIG_2 */
+#define OMAP44XX_REG_CS1NVMEN_SHIFT 30
+#define OMAP44XX_REG_CS1NVMEN_MASK (1 << 30)
+#define OMAP44XX_REG_EBANK_POS_SHIFT 27
+#define OMAP44XX_REG_EBANK_POS_MASK (1 << 27)
+#define OMAP44XX_REG_RDBNUM_SHIFT 4
+#define OMAP44XX_REG_RDBNUM_MASK (0x3 << 4)
+#define OMAP44XX_REG_RDBSIZE_SHIFT 0
+#define OMAP44XX_REG_RDBSIZE_MASK (0x7 << 0)
+
+/* SDRAM_REF_CTRL */
+#define OMAP44XX_REG_INITREF_DIS_SHIFT 31
+#define OMAP44XX_REG_INITREF_DIS_MASK (1 << 31)
+#define OMAP44XX_REG_SRT_SHIFT 29
+#define OMAP44XX_REG_SRT_MASK (1 << 29)
+#define OMAP44XX_REG_ASR_SHIFT 28
+#define OMAP44XX_REG_ASR_MASK (1 << 28)
+#define OMAP44XX_REG_PASR_SHIFT 24
+#define OMAP44XX_REG_PASR_MASK (0x7 << 24)
+#define OMAP44XX_REG_REFRESH_RATE_SHIFT 0
+#define OMAP44XX_REG_REFRESH_RATE_MASK (0xffff << 0)
+
+/* SDRAM_REF_CTRL_SHDW */
+#define OMAP44XX_REG_REFRESH_RATE_SHDW_SHIFT 0
+#define OMAP44XX_REG_REFRESH_RATE_SHDW_MASK (0xffff << 0)
+
+/* SDRAM_TIM_1 */
+#define OMAP44XX_REG_T_RP_SHIFT 25
+#define OMAP44XX_REG_T_RP_MASK (0xf << 25)
+#define OMAP44XX_REG_T_RCD_SHIFT 21
+#define OMAP44XX_REG_T_RCD_MASK (0xf << 21)
+#define OMAP44XX_REG_T_WR_SHIFT 17
+#define OMAP44XX_REG_T_WR_MASK (0xf << 17)
+#define OMAP44XX_REG_T_RAS_SHIFT 12
+#define OMAP44XX_REG_T_RAS_MASK (0x1f << 12)
+#define OMAP44XX_REG_T_RC_SHIFT 6
+#define OMAP44XX_REG_T_RC_MASK (0x3f << 6)
+#define OMAP44XX_REG_T_RRD_SHIFT 3
+#define OMAP44XX_REG_T_RRD_MASK (0x7 << 3)
+#define OMAP44XX_REG_T_WTR_SHIFT 0
+#define OMAP44XX_REG_T_WTR_MASK (0x7 << 0)
+
+/* SDRAM_TIM_1_SHDW */
+#define OMAP44XX_REG_T_RP_SHDW_SHIFT 25
+#define OMAP44XX_REG_T_RP_SHDW_MASK (0xf << 25)
+#define OMAP44XX_REG_T_RCD_SHDW_SHIFT 21
+#define OMAP44XX_REG_T_RCD_SHDW_MASK (0xf << 21)
+#define OMAP44XX_REG_T_WR_SHDW_SHIFT 17
+#define OMAP44XX_REG_T_WR_SHDW_MASK (0xf << 17)
+#define OMAP44XX_REG_T_RAS_SHDW_SHIFT 12
+#define OMAP44XX_REG_T_RAS_SHDW_MASK (0x1f << 12)
+#define OMAP44XX_REG_T_RC_SHDW_SHIFT 6
+#define OMAP44XX_REG_T_RC_SHDW_MASK (0x3f << 6)
+#define OMAP44XX_REG_T_RRD_SHDW_SHIFT 3
+#define OMAP44XX_REG_T_RRD_SHDW_MASK (0x7 << 3)
+#define OMAP44XX_REG_T_WTR_SHDW_SHIFT 0
+#define OMAP44XX_REG_T_WTR_SHDW_MASK (0x7 << 0)
+
+/* SDRAM_TIM_2 */
+#define OMAP44XX_REG_T_XP_SHIFT 28
+#define OMAP44XX_REG_T_XP_MASK (0x7 << 28)
+#define OMAP44XX_REG_T_ODT_SHIFT 25
+#define OMAP44XX_REG_T_ODT_MASK (0x7 << 25)
+#define OMAP44XX_REG_T_XSNR_SHIFT 16
+#define OMAP44XX_REG_T_XSNR_MASK (0x1ff << 16)
+#define OMAP44XX_REG_T_XSRD_SHIFT 6
+#define OMAP44XX_REG_T_XSRD_MASK (0x3ff << 6)
+#define OMAP44XX_REG_T_RTP_SHIFT 3
+#define OMAP44XX_REG_T_RTP_MASK (0x7 << 3)
+#define OMAP44XX_REG_T_CKE_SHIFT 0
+#define OMAP44XX_REG_T_CKE_MASK (0x7 << 0)
+
+/* SDRAM_TIM_2_SHDW */
+#define OMAP44XX_REG_T_XP_SHDW_SHIFT 28
+#define OMAP44XX_REG_T_XP_SHDW_MASK (0x7 << 28)
+#define OMAP44XX_REG_T_ODT_SHDW_SHIFT 25
+#define OMAP44XX_REG_T_ODT_SHDW_MASK (0x7 << 25)
+#define OMAP44XX_REG_T_XSNR_SHDW_SHIFT 16
+#define OMAP44XX_REG_T_XSNR_SHDW_MASK (0x1ff << 16)
+#define OMAP44XX_REG_T_XSRD_SHDW_SHIFT 6
+#define OMAP44XX_REG_T_XSRD_SHDW_MASK (0x3ff << 6)
+#define OMAP44XX_REG_T_RTP_SHDW_SHIFT 3
+#define OMAP44XX_REG_T_RTP_SHDW_MASK (0x7 << 3)
+#define OMAP44XX_REG_T_CKE_SHDW_SHIFT 0
+#define OMAP44XX_REG_T_CKE_SHDW_MASK (0x7 << 0)
+
+/* SDRAM_TIM_3 */
+#define OMAP44XX_REG_T_CKESR_SHIFT 21
+#define OMAP44XX_REG_T_CKESR_MASK (0x7 << 21)
+#define OMAP44XX_REG_ZQ_ZQCS_SHIFT 15
+#define OMAP44XX_REG_ZQ_ZQCS_MASK (0x3f << 15)
+#define OMAP44XX_REG_T_TDQSCKMAX_SHIFT 13
+#define OMAP44XX_REG_T_TDQSCKMAX_MASK (0x3 << 13)
+#define OMAP44XX_REG_T_RFC_SHIFT 4
+#define OMAP44XX_REG_T_RFC_MASK (0x1ff << 4)
+#define OMAP44XX_REG_T_RAS_MAX_SHIFT 0
+#define OMAP44XX_REG_T_RAS_MAX_MASK (0xf << 0)
+
+/* SDRAM_TIM_3_SHDW */
+#define OMAP44XX_REG_T_CKESR_SHDW_SHIFT 21
+#define OMAP44XX_REG_T_CKESR_SHDW_MASK (0x7 << 21)
+#define OMAP44XX_REG_ZQ_ZQCS_SHDW_SHIFT 15
+#define OMAP44XX_REG_ZQ_ZQCS_SHDW_MASK (0x3f << 15)
+#define OMAP44XX_REG_T_TDQSCKMAX_SHDW_SHIFT 13
+#define OMAP44XX_REG_T_TDQSCKMAX_SHDW_MASK (0x3 << 13)
+#define OMAP44XX_REG_T_RFC_SHDW_SHIFT 4
+#define OMAP44XX_REG_T_RFC_SHDW_MASK (0x1ff << 4)
+#define OMAP44XX_REG_T_RAS_MAX_SHDW_SHIFT 0
+#define OMAP44XX_REG_T_RAS_MAX_SHDW_MASK (0xf << 0)
+
+/* LPDDR2_NVM_TIM */
+#define OMAP44XX_REG_NVM_T_XP_SHIFT 28
+#define OMAP44XX_REG_NVM_T_XP_MASK (0x7 << 28)
+#define OMAP44XX_REG_NVM_T_WTR_SHIFT 24
+#define OMAP44XX_REG_NVM_T_WTR_MASK (0x7 << 24)
+#define OMAP44XX_REG_NVM_T_RP_SHIFT 20
+#define OMAP44XX_REG_NVM_T_RP_MASK (0xf << 20)
+#define OMAP44XX_REG_NVM_T_WRA_SHIFT 16
+#define OMAP44XX_REG_NVM_T_WRA_MASK (0xf << 16)
+#define OMAP44XX_REG_NVM_T_RRD_SHIFT 8
+#define OMAP44XX_REG_NVM_T_RRD_MASK (0xff << 8)
+#define OMAP44XX_REG_NVM_T_RCDMIN_SHIFT 0
+#define OMAP44XX_REG_NVM_T_RCDMIN_MASK (0xff << 0)
+
+/* LPDDR2_NVM_TIM_SHDW */
+#define OMAP44XX_REG_NVM_T_XP_SHDW_SHIFT 28
+#define OMAP44XX_REG_NVM_T_XP_SHDW_MASK (0x7 << 28)
+#define OMAP44XX_REG_NVM_T_WTR_SHDW_SHIFT 24
+#define OMAP44XX_REG_NVM_T_WTR_SHDW_MASK (0x7 << 24)
+#define OMAP44XX_REG_NVM_T_RP_SHDW_SHIFT 20
+#define OMAP44XX_REG_NVM_T_RP_SHDW_MASK (0xf << 20)
+#define OMAP44XX_REG_NVM_T_WRA_SHDW_SHIFT 16
+#define OMAP44XX_REG_NVM_T_WRA_SHDW_MASK (0xf << 16)
+#define OMAP44XX_REG_NVM_T_RRD_SHDW_SHIFT 8
+#define OMAP44XX_REG_NVM_T_RRD_SHDW_MASK (0xff << 8)
+#define OMAP44XX_REG_NVM_T_RCDMIN_SHDW_SHIFT 0
+#define OMAP44XX_REG_NVM_T_RCDMIN_SHDW_MASK (0xff << 0)
+
+/* PWR_MGMT_CTRL */
+#define OMAP44XX_REG_PD_TIM_SHIFT 12
+#define OMAP44XX_REG_PD_TIM_MASK (0xf << 12)
+#define OMAP44XX_REG_DPD_EN_SHIFT 11
+#define OMAP44XX_REG_DPD_EN_MASK (1 << 11)
+#define OMAP44XX_REG_LP_MODE_SHIFT 8
+#define OMAP44XX_REG_LP_MODE_MASK (0x7 << 8)
+#define OMAP44XX_REG_SR_TIM_SHIFT 4
+#define OMAP44XX_REG_SR_TIM_MASK (0xf << 4)
+#define OMAP44XX_REG_CS_TIM_SHIFT 0
+#define OMAP44XX_REG_CS_TIM_MASK (0xf << 0)
+
+/* PWR_MGMT_CTRL_SHDW */
+#define OMAP44XX_REG_PD_TIM_SHDW_SHIFT 8
+#define OMAP44XX_REG_PD_TIM_SHDW_MASK (0xf << 8)
+#define OMAP44XX_REG_SR_TIM_SHDW_SHIFT 4
+#define OMAP44XX_REG_SR_TIM_SHDW_MASK (0xf << 4)
+#define OMAP44XX_REG_CS_TIM_SHDW_SHIFT 0
+#define OMAP44XX_REG_CS_TIM_SHDW_MASK (0xf << 0)
+
+/* LPDDR2_MODE_REG_DATA */
+#define OMAP44XX_REG_VALUE_0_SHIFT 0
+#define OMAP44XX_REG_VALUE_0_MASK (0x7f << 0)
+
+/* LPDDR2_MODE_REG_CFG */
+#define OMAP44XX_REG_CS_SHIFT 31
+#define OMAP44XX_REG_CS_MASK (1 << 31)
+#define OMAP44XX_REG_REFRESH_EN_SHIFT 30
+#define OMAP44XX_REG_REFRESH_EN_MASK (1 << 30)
+#define OMAP44XX_REG_ADDRESS_SHIFT 0
+#define OMAP44XX_REG_ADDRESS_MASK (0xff << 0)
+
+/* OCP_CONFIG */
+#define OMAP44XX_REG_SYS_THRESH_MAX_SHIFT 24
+#define OMAP44XX_REG_SYS_THRESH_MAX_MASK (0xf << 24)
+#define OMAP44XX_REG_LL_THRESH_MAX_SHIFT 16
+#define OMAP44XX_REG_LL_THRESH_MAX_MASK (0xf << 16)
+#define OMAP44XX_REG_PR_OLD_COUNT_SHIFT 0
+#define OMAP44XX_REG_PR_OLD_COUNT_MASK (0xff << 0)
+
+/* OCP_CFG_VAL_1 */
+#define OMAP44XX_REG_SYS_BUS_WIDTH_SHIFT 30
+#define OMAP44XX_REG_SYS_BUS_WIDTH_MASK (0x3 << 30)
+#define OMAP44XX_REG_LL_BUS_WIDTH_SHIFT 28
+#define OMAP44XX_REG_LL_BUS_WIDTH_MASK (0x3 << 28)
+#define OMAP44XX_REG_WR_FIFO_DEPTH_SHIFT 8
+#define OMAP44XX_REG_WR_FIFO_DEPTH_MASK (0xff << 8)
+#define OMAP44XX_REG_CMD_FIFO_DEPTH_SHIFT 0
+#define OMAP44XX_REG_CMD_FIFO_DEPTH_MASK (0xff << 0)
+
+/* OCP_CFG_VAL_2 */
+#define OMAP44XX_REG_RREG_FIFO_DEPTH_SHIFT 16
+#define OMAP44XX_REG_RREG_FIFO_DEPTH_MASK (0xff << 16)
+#define OMAP44XX_REG_RSD_FIFO_DEPTH_SHIFT 8
+#define OMAP44XX_REG_RSD_FIFO_DEPTH_MASK (0xff << 8)
+#define OMAP44XX_REG_RCMD_FIFO_DEPTH_SHIFT 0
+#define OMAP44XX_REG_RCMD_FIFO_DEPTH_MASK (0xff << 0)
+
+/* IODFT_TLGC */
+#define OMAP44XX_REG_TLEC_SHIFT 16
+#define OMAP44XX_REG_TLEC_MASK (0xffff << 16)
+#define OMAP44XX_REG_MT_SHIFT 14
+#define OMAP44XX_REG_MT_MASK (1 << 14)
+#define OMAP44XX_REG_ACT_CAP_EN_SHIFT 13
+#define OMAP44XX_REG_ACT_CAP_EN_MASK (1 << 13)
+#define OMAP44XX_REG_OPG_LD_SHIFT 12
+#define OMAP44XX_REG_OPG_LD_MASK (1 << 12)
+#define OMAP44XX_REG_RESET_PHY_SHIFT 10
+#define OMAP44XX_REG_RESET_PHY_MASK (1 << 10)
+#define OMAP44XX_REG_MMS_SHIFT 8
+#define OMAP44XX_REG_MMS_MASK (1 << 8)
+#define OMAP44XX_REG_MC_SHIFT 4
+#define OMAP44XX_REG_MC_MASK (0x3 << 4)
+#define OMAP44XX_REG_PC_SHIFT 1
+#define OMAP44XX_REG_PC_MASK (0x7 << 1)
+#define OMAP44XX_REG_TM_SHIFT 0
+#define OMAP44XX_REG_TM_MASK (1 << 0)
+
+/* IODFT_CTRL_MISR_RSLT */
+#define OMAP44XX_REG_DQM_TLMR_SHIFT 16
+#define OMAP44XX_REG_DQM_TLMR_MASK (0x3ff << 16)
+#define OMAP44XX_REG_CTL_TLMR_SHIFT 0
+#define OMAP44XX_REG_CTL_TLMR_MASK (0x7ff << 0)
+
+/* IODFT_ADDR_MISR_RSLT */
+#define OMAP44XX_REG_ADDR_TLMR_SHIFT 0
+#define OMAP44XX_REG_ADDR_TLMR_MASK (0x1fffff << 0)
+
+/* IODFT_DATA_MISR_RSLT_1 */
+#define OMAP44XX_REG_DATA_TLMR_31_0_SHIFT 0
+#define OMAP44XX_REG_DATA_TLMR_31_0_MASK (0xffffffff << 0)
+
+/* IODFT_DATA_MISR_RSLT_2 */
+#define OMAP44XX_REG_DATA_TLMR_63_32_SHIFT 0
+#define OMAP44XX_REG_DATA_TLMR_63_32_MASK (0xffffffff << 0)
+
+/* IODFT_DATA_MISR_RSLT_3 */
+#define OMAP44XX_REG_DATA_TLMR_66_64_SHIFT 0
+#define OMAP44XX_REG_DATA_TLMR_66_64_MASK (0x7 << 0)
+
+/* PERF_CNT_1 */
+#define OMAP44XX_REG_COUNTER1_SHIFT 0
+#define OMAP44XX_REG_COUNTER1_MASK (0xffffffff << 0)
+
+/* PERF_CNT_2 */
+#define OMAP44XX_REG_COUNTER2_SHIFT 0
+#define OMAP44XX_REG_COUNTER2_MASK (0xffffffff << 0)
+
+/* PERF_CNT_CFG */
+#define OMAP44XX_REG_CNTR2_MCONNID_EN_SHIFT 31
+#define OMAP44XX_REG_CNTR2_MCONNID_EN_MASK (1 << 31)
+#define OMAP44XX_REG_CNTR2_REGION_EN_SHIFT 30
+#define OMAP44XX_REG_CNTR2_REGION_EN_MASK (1 << 30)
+#define OMAP44XX_REG_CNTR2_CFG_SHIFT 16
+#define OMAP44XX_REG_CNTR2_CFG_MASK (0xf << 16)
+#define OMAP44XX_REG_CNTR1_MCONNID_EN_SHIFT 15
+#define OMAP44XX_REG_CNTR1_MCONNID_EN_MASK (1 << 15)
+#define OMAP44XX_REG_CNTR1_REGION_EN_SHIFT 14
+#define OMAP44XX_REG_CNTR1_REGION_EN_MASK (1 << 14)
+#define OMAP44XX_REG_CNTR1_CFG_SHIFT 0
+#define OMAP44XX_REG_CNTR1_CFG_MASK (0xf << 0)
+
+/* PERF_CNT_SEL */
+#define OMAP44XX_REG_MCONNID2_SHIFT 24
+#define OMAP44XX_REG_MCONNID2_MASK (0xff << 24)
+#define OMAP44XX_REG_REGION_SEL2_SHIFT 16
+#define OMAP44XX_REG_REGION_SEL2_MASK (0x3 << 16)
+#define OMAP44XX_REG_MCONNID1_SHIFT 8
+#define OMAP44XX_REG_MCONNID1_MASK (0xff << 8)
+#define OMAP44XX_REG_REGION_SEL1_SHIFT 0
+#define OMAP44XX_REG_REGION_SEL1_MASK (0x3 << 0)
+
+/* PERF_CNT_TIM */
+#define OMAP44XX_REG_TOTAL_TIME_SHIFT 0
+#define OMAP44XX_REG_TOTAL_TIME_MASK (0xffffffff << 0)
+
+/* READ_IDLE_CTRL */
+#define OMAP44XX_REG_READ_IDLE_LEN_SHIFT 16
+#define OMAP44XX_REG_READ_IDLE_LEN_MASK (0xf << 16)
+#define OMAP44XX_REG_READ_IDLE_INTERVAL_SHIFT 0
+#define OMAP44XX_REG_READ_IDLE_INTERVAL_MASK (0x1ff << 0)
+
+/* READ_IDLE_CTRL_SHDW */
+#define OMAP44XX_REG_READ_IDLE_LEN_SHDW_SHIFT 16
+#define OMAP44XX_REG_READ_IDLE_LEN_SHDW_MASK (0xf << 16)
+#define OMAP44XX_REG_READ_IDLE_INTERVAL_SHDW_SHIFT 0
+#define OMAP44XX_REG_READ_IDLE_INTERVAL_SHDW_MASK (0x1ff << 0)
+
+/* IRQ_EOI */
+#define OMAP44XX_REG_EOI_SHIFT 0
+#define OMAP44XX_REG_EOI_MASK (1 << 0)
+
+/* IRQSTATUS_RAW_SYS */
+#define OMAP44XX_REG_DNV_SYS_SHIFT 2
+#define OMAP44XX_REG_DNV_SYS_MASK (1 << 2)
+#define OMAP44XX_REG_TA_SYS_SHIFT 1
+#define OMAP44XX_REG_TA_SYS_MASK (1 << 1)
+#define OMAP44XX_REG_ERR_SYS_SHIFT 0
+#define OMAP44XX_REG_ERR_SYS_MASK (1 << 0)
+
+/* IRQSTATUS_RAW_LL */
+#define OMAP44XX_REG_DNV_LL_SHIFT 2
+#define OMAP44XX_REG_DNV_LL_MASK (1 << 2)
+#define OMAP44XX_REG_TA_LL_SHIFT 1
+#define OMAP44XX_REG_TA_LL_MASK (1 << 1)
+#define OMAP44XX_REG_ERR_LL_SHIFT 0
+#define OMAP44XX_REG_ERR_LL_MASK (1 << 0)
+
+/* IRQSTATUS_SYS */
+
+/* IRQSTATUS_LL */
+
+/* IRQENABLE_SET_SYS */
+#define OMAP44XX_REG_EN_DNV_SYS_SHIFT 2
+#define OMAP44XX_REG_EN_DNV_SYS_MASK (1 << 2)
+#define OMAP44XX_REG_EN_TA_SYS_SHIFT 1
+#define OMAP44XX_REG_EN_TA_SYS_MASK (1 << 1)
+#define OMAP44XX_REG_EN_ERR_SYS_SHIFT 0
+#define OMAP44XX_REG_EN_ERR_SYS_MASK (1 << 0)
+
+/* IRQENABLE_SET_LL */
+#define OMAP44XX_REG_EN_DNV_LL_SHIFT 2
+#define OMAP44XX_REG_EN_DNV_LL_MASK (1 << 2)
+#define OMAP44XX_REG_EN_TA_LL_SHIFT 1
+#define OMAP44XX_REG_EN_TA_LL_MASK (1 << 1)
+#define OMAP44XX_REG_EN_ERR_LL_SHIFT 0
+#define OMAP44XX_REG_EN_ERR_LL_MASK (1 << 0)
+
+/* IRQENABLE_CLR_SYS */
+
+/* IRQENABLE_CLR_LL */
+
+/* ZQ_CONFIG */
+#define OMAP44XX_REG_ZQ_CS1EN_SHIFT 31
+#define OMAP44XX_REG_ZQ_CS1EN_MASK (1 << 31)
+#define OMAP44XX_REG_ZQ_CS0EN_SHIFT 30
+#define OMAP44XX_REG_ZQ_CS0EN_MASK (1 << 30)
+#define OMAP44XX_REG_ZQ_DUALCALEN_SHIFT 29
+#define OMAP44XX_REG_ZQ_DUALCALEN_MASK (1 << 29)
+#define OMAP44XX_REG_ZQ_SFEXITEN_SHIFT 28
+#define OMAP44XX_REG_ZQ_SFEXITEN_MASK (1 << 28)
+#define OMAP44XX_REG_ZQ_ZQINIT_MULT_SHIFT 18
+#define OMAP44XX_REG_ZQ_ZQINIT_MULT_MASK (0x3 << 18)
+#define OMAP44XX_REG_ZQ_ZQCL_MULT_SHIFT 16
+#define OMAP44XX_REG_ZQ_ZQCL_MULT_MASK (0x3 << 16)
+#define OMAP44XX_REG_ZQ_REFINTERVAL_SHIFT 0
+#define OMAP44XX_REG_ZQ_REFINTERVAL_MASK (0xffff << 0)
+
+/* TEMP_ALERT_CONFIG */
+#define OMAP44XX_REG_TA_CS1EN_SHIFT 31
+#define OMAP44XX_REG_TA_CS1EN_MASK (1 << 31)
+#define OMAP44XX_REG_TA_CS0EN_SHIFT 30
+#define OMAP44XX_REG_TA_CS0EN_MASK (1 << 30)
+#define OMAP44XX_REG_TA_SFEXITEN_SHIFT 28
+#define OMAP44XX_REG_TA_SFEXITEN_MASK (1 << 28)
+#define OMAP44XX_REG_TA_DEVWDT_SHIFT 26
+#define OMAP44XX_REG_TA_DEVWDT_MASK (0x3 << 26)
+#define OMAP44XX_REG_TA_DEVCNT_SHIFT 24
+#define OMAP44XX_REG_TA_DEVCNT_MASK (0x3 << 24)
+#define OMAP44XX_REG_TA_REFINTERVAL_SHIFT 0
+#define OMAP44XX_REG_TA_REFINTERVAL_MASK (0x3fffff << 0)
+
+/* OCP_ERR_LOG */
+#define OMAP44XX_REG_MADDRSPACE_SHIFT 14
+#define OMAP44XX_REG_MADDRSPACE_MASK (0x3 << 14)
+#define OMAP44XX_REG_MBURSTSEQ_SHIFT 11
+#define OMAP44XX_REG_MBURSTSEQ_MASK (0x7 << 11)
+#define OMAP44XX_REG_MCMD_SHIFT 8
+#define OMAP44XX_REG_MCMD_MASK (0x7 << 8)
+#define OMAP44XX_REG_MCONNID_SHIFT 0
+#define OMAP44XX_REG_MCONNID_MASK (0xff << 0)
+
+/* DDR_PHY_CTRL_1 */
+#define OMAP44XX_REG_DDR_PHY_CTRL_1_SHIFT 4
+#define OMAP44XX_REG_DDR_PHY_CTRL_1_MASK (0xfffffff << 4)
+#define OMAP44XX_REG_READ_LATENCY_SHIFT 0
+#define OMAP44XX_REG_READ_LATENCY_MASK (0xf << 0)
+#define OMAP44XX_REG_DLL_SLAVE_DLY_CTRL_SHIFT 4
+#define OMAP44XX_REG_DLL_SLAVE_DLY_CTRL_MASK (0xFF << 4)
+#define OMAP44XX_EMIF_DDR_PHY_CTRL_1_BASE_VAL_SHIFT 12
+#define OMAP44XX_EMIF_DDR_PHY_CTRL_1_BASE_VAL_MASK (0xFFFFF << 12)
+
+/* DDR_PHY_CTRL_1_SHDW */
+#define OMAP44XX_REG_DDR_PHY_CTRL_1_SHDW_SHIFT 4
+#define OMAP44XX_REG_DDR_PHY_CTRL_1_SHDW_MASK (0xfffffff << 4)
+#define OMAP44XX_REG_READ_LATENCY_SHDW_SHIFT 0
+#define OMAP44XX_REG_READ_LATENCY_SHDW_MASK (0xf << 0)
+#define OMAP44XX_REG_DLL_SLAVE_DLY_CTRL_SHDW_SHIFT 4
+#define OMAP44XX_REG_DLL_SLAVE_DLY_CTRL_SHDW_MASK (0xFF << 4)
+#define OMAP44XX_EMIF_DDR_PHY_CTRL_1_BASE_VAL_SHDW_SHIFT 12
+#define OMAP44XX_EMIF_DDR_PHY_CTRL_1_BASE_VAL_SHDW_MASK (0xFFFFF << 12)
+
+/* DDR_PHY_CTRL_2 */
+#define OMAP44XX_REG_DDR_PHY_CTRL_2_SHIFT 0
+#define OMAP44XX_REG_DDR_PHY_CTRL_2_MASK (0xffffffff << 0)
+#endif
diff --git a/arch/arm/mach-omap2/include/mach/emif.h b/arch/arm/mach-omap2/include/mach/emif.h
new file mode 100644
index 0000000..dd8159a
--- /dev/null
+++ b/arch/arm/mach-omap2/include/mach/emif.h
@@ -0,0 +1,292 @@
+/*
+ * OMAP44xx EMIF header
+ *
+ * Copyright (C) 2009-2010 Texas Instruments, Inc.
+ *
+ * Aneesh V <aneesh@ti.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.
+ */
+
+#ifndef _EMIF_H
+#define _EMIF_H
+
+#include <mach/emif-44xx.h>
+#include <mach/lpddr2-jedec.h>
+
+#define EMIF_NUM_INSTANCES 2
+#define EMIF1 0
+#define EMIF2 1
+
+/* The maximum frequency at which the LPDDR2 interface can operate in Hz*/
+#define MAX_LPDDR2_FREQ 400000000 /* 400 MHz */
+
+/* 19.2 MHz to be used for finding initialization values */
+#define EMIF_FREQ_19_2_MHZ 19200000 /* 19.2 MHz */
+/*
+ * The period of DDR clk is represented as numerator and denominator for
+ * better accuracy in integer based calculations. However, if the numerator
+ * and denominator are very huge there may be chances of overflow in
+ * calculations. So, as a trade-off keep denominator(and consequently
+ * numerator) within a limit sacrificing some accuracy - but not much
+ * If denominator and numerator are already small (such as at 400 MHz)
+ * no adjustment is needed
+ */
+#define EMIF_PERIOD_DEN_LIMIT 1000
+/*
+ * Maximum number of different frequencies supported by EMIF driver
+ * Determines the number of entries in the pointer array for register
+ * cache
+ */
+#define EMIF_MAX_NUM_FREQUENCIES 6
+/*
+ * Indices into the Addressing Table array.
+ * One entry each for all the different types of devices with different
+ * addressing schemes
+ */
+#define ADDR_TABLE_INDEX64M 0
+#define ADDR_TABLE_INDEX128M 1
+#define ADDR_TABLE_INDEX256M 2
+#define ADDR_TABLE_INDEX512M 3
+#define ADDR_TABLE_INDEX1GS4 4
+#define ADDR_TABLE_INDEX2GS4 5
+#define ADDR_TABLE_INDEX4G 6
+#define ADDR_TABLE_INDEX8G 7
+#define ADDR_TABLE_INDEX1GS2 8
+#define ADDR_TABLE_INDEX2GS2 9
+#define ADDR_TABLE_INDEXMAX 10
+
+/* Number of Row bits */
+#define ROW_9 0
+#define ROW_10 1
+#define ROW_11 2
+#define ROW_12 3
+#define ROW_13 4
+#define ROW_14 5
+#define ROW_15 6
+#define ROW_16 7
+
+/* Number of Column bits */
+#define COL_8 0
+#define COL_9 1
+#define COL_10 2
+#define COL_11 3
+#define COL_7 4 /*Not supported by OMAP included for completeness */
+
+/* Number of Banks*/
+#define BANKS1 0
+#define BANKS2 1
+#define BANKS4 2
+#define BANKS8 3
+
+/* Refresh rate in micro seconds x 10 */
+#define T_REFI_15_6 156
+#define T_REFI_7_8 78
+#define T_REFI_3_9 39
+
+#define EBANK_CS1_DIS 0
+#define EBANK_CS1_EN 1
+
+/* Read Latency at the base frequency - 19.2 MHz on bootup */
+#define RL_19_2_MHZ 3
+/* Interleaving policies at EMIF level- between banks and Chip Selects */
+#define EMIF_INTERLEAVING_POLICY_MAX_INTERLEAVING 0
+#define EMIF_INTERLEAVING_POLICY_NO_BANK_INTERLEAVING 3
+
+/*
+ * Interleaving policy to be used
+ * Currently set to MAX interleaving for better performance
+ */
+#define EMIF_INTERLEAVING_POLICY EMIF_INTERLEAVING_POLICY_MAX_INTERLEAVING
+
+/* State of the core voltage:
+ * This is important for some parameters such as read idle control and
+ * ZQ calibration timings. Timings are much stricter when voltage ramp
+ * is happening compared to when the voltage is stable.
+ * We need to calculate two sets of values for these parameters and use
+ * them accordingly
+ */
+#define LPDDR2_VOLTAGE_STABLE 0
+#define LPDDR2_VOLTAGE_RAMPING 1
+
+/* Length of the forced read idle period in terms of cycles */
+#define EMIF_REG_READ_IDLE_LEN_VAL 5
+
+/* Interval between forced 'read idles' */
+/* To be used when voltage is changed for DPS/DVFS - 1us */
+#define READ_IDLE_INTERVAL_DVFS (1*1000)
+/*
+ * To be used when voltage is not scaled except by Smart Reflex
+ * 50us - or maximum value will do
+ */
+#define READ_IDLE_INTERVAL_NORMAL (50*1000)
+
+
+/*
+ * Unless voltage is changing due to DVFS one ZQCS command every 50ms should
+ * be enough. This shoule be enough also in the case when voltage is changing
+ * due to smart-reflex.
+ */
+#define EMIF_ZQCS_INTERVAL_NORMAL_IN_US (50*1000)
+/*
+ * If voltage is changing due to DVFS ZQCS should be performed more
+ * often(every 50us)
+ */
+#define EMIF_ZQCS_INTERVAL_DVFS_IN_US 50
+
+/* The interval between ZQCL commands as a multiple of ZQCS interval */
+#define REG_ZQ_ZQCL_MULT 4
+/* The interval between ZQINIT commands as a multiple of ZQCL interval */
+#define REG_ZQ_ZQINIT_MULT 3
+/* Enable ZQ Calibration on exiting Self-refresh */
+#define REG_ZQ_SFEXITEN_ENABLE 1
+/*
+ * ZQ Calibration simultaneously on both chip-selects:
+ * Needs one calibration resistor per CS
+ * None of the boards that we know of have this capability
+ * So disabled by default
+ */
+#define REG_ZQ_DUALCALEN_DISABLE 0
+/*
+ * Enable ZQ Calibration by default on CS0. If we are asked to program
+ * the EMIF there will be something connected to CS0 for sure
+ */
+#define REG_ZQ_CS0EN_ENABLE 1
+
+/* EMIF_PWR_MGMT_CTRL register */
+/* Low power modes */
+#define LP_MODE_DISABLE 0
+#define LP_MODE_CLOCK_STOP 1
+#define LP_MODE_SELF_REFRESH 2
+#define LP_MODE_PWR_DN 3
+
+/* REG_DPD_EN */
+#define DPD_DISABLE 0
+#define DPD_ENABLE 1
+
+/* Maximum delay before Low Power Modes */
+#define REG_CS_TIM 0xF
+#define REG_SR_TIM 0xF
+#define REG_PD_TIM 0xF
+
+/* EMIF_PWR_MGMT_CTRL register */
+#define EMIF_PWR_MGMT_CTRL (\
+ ((REG_CS_TIM << OMAP44XX_REG_CS_TIM_SHIFT) & OMAP44XX_REG_CS_TIM_MASK)|\
+ ((REG_SR_TIM << OMAP44XX_REG_SR_TIM_SHIFT) & OMAP44XX_REG_SR_TIM_MASK)|\
+ ((REG_PD_TIM << OMAP44XX_REG_PD_TIM_SHIFT) & OMAP44XX_REG_PD_TIM_MASK)|\
+ ((REG_PD_TIM << OMAP44XX_REG_PD_TIM_SHIFT) & OMAP44XX_REG_PD_TIM_MASK)|\
+ ((LP_MODE_SELF_REFRESH << OMAP44XX_REG_LP_MODE_SHIFT)\
+ & OMAP44XX_REG_LP_MODE_MASK) |\
+ ((DPD_DISABLE << OMAP44XX_REG_DPD_EN_SHIFT)\
+ & OMAP44XX_REG_DPD_EN_MASK))\
+
+#define EMIF_PWR_MGMT_CTRL_SHDW (\
+ ((REG_CS_TIM << OMAP44XX_REG_CS_TIM_SHDW_SHIFT)\
+ & OMAP44XX_REG_CS_TIM_SHDW_MASK) |\
+ ((REG_SR_TIM << OMAP44XX_REG_SR_TIM_SHDW_SHIFT)\
+ & OMAP44XX_REG_SR_TIM_SHDW_MASK) |\
+ ((REG_PD_TIM << OMAP44XX_REG_PD_TIM_SHDW_SHIFT)\
+ & OMAP44XX_REG_PD_TIM_SHDW_MASK) |\
+ ((REG_PD_TIM << OMAP44XX_REG_PD_TIM_SHDW_SHIFT)\
+ & OMAP44XX_REG_PD_TIM_SHDW_MASK))
+
+/*
+ * Value of bits 12:31 of DDR_PHY_CTRL_1 register:
+ * All these fields have magic values dependent on frequency and
+ * determined by PHY and DLL integration with EMIF. Setting the magic
+ * values suggested by hw team.
+ */
+#define EMIF_DDR_PHY_CTRL_1_BASE_VAL 0x049FF
+#define EMIF_DLL_SLAVE_DLY_CTRL_400_MHZ 0x41
+#define EMIF_DLL_SLAVE_DLY_CTRL_200_MHZ 0x80
+#define EMIF_DLL_SLAVE_DLY_CTRL_100_MHZ_AND_LESS 0xFF
+
+/*
+* MR1 value:
+* Burst length : 8
+* Burst type : sequential
+* Wrap : enabled
+* nWR : 3(default). EMIF does not do pre-charge.
+* : So nWR is don't care
+*/
+#define MR1_VAL 0x23
+
+/* MR10: ZQ calibration codes */
+#define MR10_ZQ_ZQCS 0x56
+#define MR10_ZQ_ZQCL 0xAB
+#define MR10_ZQ_ZQINIT 0xFF
+#define MR10_ZQ_ZQRESET 0xC3
+
+/* TEMP_ALERT_CONFIG */
+#define TEMP_ALERT_POLL_INTERVAL_MS 360 /* for temp gradient - 5 C/s */
+#define TEMP_ALERT_CONFIG_DEVCT_1 0
+#define TEMP_ALERT_CONFIG_DEVWDT_32 2
+
+/* MR16 value: refresh full array(no partial array self refresh) */
+#define MR16_VAL 0
+
+#if defined(DEBUG)
+#define emif_assert(c) BUG_ON(!(c))
+#else
+#define emif_assert(c) ({ if (0) BUG_ON(!(c)); 0; })
+#endif
+
+/* Details of the devices connected to each chip-select of an EMIF instance */
+struct emif_device_details {
+ const struct lpddr2_device_info *cs0_device;
+ const struct lpddr2_device_info *cs1_device;
+};
+
+/*
+ * LPDDR2 interface clock frequency:
+ * Period (represented as numerator and denominator for better accuracy in
+ * calculations) should be <= the real value. Period is used for calculating
+ * all timings except refresh rate.
+ * freq_mhz_floor - freq in mhz truncated to the lower integer is used for
+ * calculating refresh rate
+ * freq_mhz_ceil - frequency in mhz rounded up is used for identifying the
+ * right speed bin and the corresponding timings table for the LPDDR2 device
+ */
+struct freq_info {
+ u16 period_num;
+ u16 period_den;
+ u16 freq_mhz_floor;
+ u16 freq_mhz_ceil;
+};
+
+/*
+ * Structure containing shadow of important registers in EMIF
+ * The calculation function fills in this structure to be later used for
+ * initialization and DVFS
+ */
+struct emif_regs {
+ u32 freq;
+ u8 RL_final;
+ u32 sdram_config_init;
+ u32 sdram_config_final;
+ u32 ref_ctrl;
+ u32 ref_ctrl_derated;
+ u32 sdram_tim1;
+ u32 sdram_tim1_derated;
+ u32 sdram_tim2;
+ u32 sdram_tim3;
+ u32 read_idle_ctrl_normal;
+ u32 read_idle_ctrl_volt_ramp;
+ u32 zq_config_normal;
+ u32 zq_config_volt_ramp;
+ u32 temp_alert_config;
+ u32 temp_alert_config_derated;
+ u32 emif_ddr_phy_ctlr_1_init;
+ u32 emif_ddr_phy_ctlr_1_final;
+};
+
+int omap_emif_notify_voltage(u32 volt_state);
+
+int omap_emif_setup_registers(u32 freq,
+ u32 volt_state);
+int omap_emif_setup_device_details(
+ const struct emif_device_details *emif1_devices,
+ const struct emif_device_details *emif2_devices);
+#endif
diff --git a/arch/arm/mach-omap2/include/mach/lpddr2-jedec.h b/arch/arm/mach-omap2/include/mach/lpddr2-jedec.h
new file mode 100644
index 0000000..8376466
--- /dev/null
+++ b/arch/arm/mach-omap2/include/mach/lpddr2-jedec.h
@@ -0,0 +1,147 @@
+/*
+ * LPDDR2 header based on JESD209-2
+ *
+ * Copyright (C) 2010 Texas Instruments, Inc.
+ *
+ * Aneesh V <aneesh@ti.com>
+ * Santosh Shilimkar <santosh.shilimkar@ti.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.
+ */
+
+#ifndef _LPDDR2_JDEC_H
+#define _LPDDR2_JDEC_H
+
+#include <linux/types.h>
+
+/*
+ * Maximum number of entries we keep in our array of timing tables
+ * We need not keep all the speed bins supported by the device
+ * We need to keep timing tables for only the speed bins that we
+ * are interested in
+ */
+#define MAX_NUM_SPEEDBINS 4
+
+/* LPDDR2 Densities */
+#define LPDDR2_DENSITY_64Mb 0
+#define LPDDR2_DENSITY_128Mb 1
+#define LPDDR2_DENSITY_256Mb 2
+#define LPDDR2_DENSITY_512Mb 3
+#define LPDDR2_DENSITY_1Gb 4
+#define LPDDR2_DENSITY_2Gb 5
+#define LPDDR2_DENSITY_4Gb 6
+#define LPDDR2_DENSITY_8Gb 7
+#define LPDDR2_DENSITY_16Gb 8
+#define LPDDR2_DENSITY_32Gb 9
+
+/* LPDDR2 type */
+#define LPDDR2_TYPE_S4 0
+#define LPDDR2_TYPE_S2 1
+#define LPDDR2_TYPE_NVM 2
+
+/* LPDDR2 IO width */
+#define LPDDR2_IO_WIDTH_32 0
+#define LPDDR2_IO_WIDTH_16 1
+#define LPDDR2_IO_WIDTH_8 2
+
+/* Mode register numbers */
+#define LPDDR2_MR0 0
+#define LPDDR2_MR1 1
+#define LPDDR2_MR2 2
+#define LPDDR2_MR3 3
+#define LPDDR2_MR4 4
+#define LPDDR2_MR5 5
+#define LPDDR2_MR6 6
+#define LPDDR2_MR7 7
+#define LPDDR2_MR8 8
+#define LPDDR2_MR9 9
+#define LPDDR2_MR10 10
+#define LPDDR2_MR11 11
+#define LPDDR2_MR16 16
+#define LPDDR2_MR17 17
+#define LPDDR2_MR18 18
+
+/* MR4 register fields */
+#define MR4_SDRAM_REF_RATE_SHIFT 0
+#define MR4_SDRAM_REF_RATE_MASK 7
+#define MR4_TUF_SHIFT 7
+#define MR4_TUF_MASK (1 << 7)
+
+/* MR4 SDRAM Refresh Rate field values */
+#define SDRAM_TEMP_NOMINAL 0x3
+#define SDRAM_TEMP_RESERVED_4 0x4
+#define SDRAM_TEMP_HIGH_DERATE_REFRESH 0x5
+#define SDRAM_TEMP_HIGH_DERATE_REFRESH_AND_TIMINGS 0x6
+#define SDRAM_TEMP_VERY_HIGH_SHUTDOWN 0x7
+
+struct lpddr2_addressing {
+ u8 num_banks;
+ u8 t_REFI_us_x10;
+ u8 row_sz[2]; /* One entry each for x32 and x16 */
+ u8 col_sz[2]; /* One entry each for x32 and x16 */
+};
+
+/* Structure for timings from the DDR datasheet */
+struct lpddr2_timings {
+ u32 max_freq;
+ u8 RL;
+ u8 tRPab;
+ u8 tRCD;
+ u8 tWR;
+ u8 tRASmin;
+ u8 tRRD;
+ u8 tWTRx2;
+ u8 tXSR;
+ u8 tXPx2;
+ u8 tRFCab;
+ u8 tRTPx2;
+ u8 tCKE;
+ u8 tCKESR;
+ u8 tZQCS;
+ u32 tZQCL;
+ u32 tZQINIT;
+ u8 tDQSCKMAXx2;
+ u8 tRASmax;
+ u8 tFAW;
+
+};
+
+/*
+ * Min tCK values for some of the parameters:
+ * If the calculated clock cycles for the respective parameter is
+ * less than the corresponding min tCK value, we need to set the min
+ * tCK value. This may happen at lower frequencies.
+ */
+struct lpddr2_min_tck {
+ u32 tRL;
+ u32 tRP_AB;
+ u32 tRCD;
+ u32 tWR;
+ u32 tRAS_MIN;
+ u32 tRRD;
+ u32 tWTR;
+ u32 tXP;
+ u32 tRTP;
+ u8 tCKE;
+ u32 tCKESR;
+ u32 tFAW;
+};
+
+struct lpddr2_device_info {
+ const struct lpddr2_timings *device_timings[MAX_NUM_SPEEDBINS];
+ const struct lpddr2_min_tck *min_tck;
+ u8 type;
+ u8 density;
+ u8 io_width;
+};
+
+/* The following are exported for devices which use JDEC specifications */
+extern const struct lpddr2_addressing lpddr2_jedec_addressing_table[];
+extern const struct lpddr2_timings lpddr2_jedec_timings_400_mhz;
+extern const struct lpddr2_timings lpddr2_jedec_timings_333_mhz;
+extern const struct lpddr2_timings lpddr2_jedec_timings_200_mhz;
+extern const struct lpddr2_min_tck lpddr2_jedec_min_tck;
+
+#endif
diff --git a/arch/arm/mach-omap2/lpddr2_jedec_data.c b/arch/arm/mach-omap2/lpddr2_jedec_data.c
new file mode 100644
index 0000000..e8b447c
--- /dev/null
+++ b/arch/arm/mach-omap2/lpddr2_jedec_data.c
@@ -0,0 +1,132 @@
+/*
+ * LPDDR2 data as per JESD209-2
+ *
+ * Copyright (C) 2010 Texas Instruments, Inc.
+ *
+ * Aneesh V <aneesh@ti.com>
+ * Santosh Shilimkar <santosh.shilimkar@ti.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 <mach/lpddr2-jedec.h>
+#include <mach/emif.h>
+
+/*
+ * Organization and refresh requirements for LPDDR2 devices of different
+ * types and densities. Derived from JESD209-2 section 2.4
+ */
+const struct lpddr2_addressing lpddr2_jedec_addressing_table[] = {
+ /* Banks tREFIx10 rowx32,rowx16 colx32,colx16 density */
+ {BANKS4, T_REFI_15_6, {ROW_12, ROW_12}, {COL_7, COL_8} }, /*64M*/
+ {BANKS4, T_REFI_15_6, {ROW_12, ROW_12}, {COL_8, COL_9} }, /*128M*/
+ {BANKS4, T_REFI_7_8, {ROW_13, ROW_13}, {COL_8, COL_9} }, /*256M*/
+ {BANKS4, T_REFI_7_8, {ROW_13, ROW_13}, {COL_9, COL_10} }, /*512M*/
+ {BANKS8, T_REFI_7_8, {ROW_13, ROW_13}, {COL_9, COL_10} }, /*1GS4*/
+ {BANKS8, T_REFI_3_9, {ROW_14, ROW_14}, {COL_9, COL_10} }, /*2GS4*/
+ {BANKS8, T_REFI_3_9, {ROW_14, ROW_14}, {COL_10, COL_11} }, /*4G*/
+ {BANKS8, T_REFI_3_9, {ROW_15, ROW_15}, {COL_10, COL_11} }, /*8G*/
+ {BANKS4, T_REFI_7_8, {ROW_14, ROW_14}, {COL_9, COL_10} }, /*1GS2*/
+ {BANKS4, T_REFI_3_9, {ROW_15, ROW_15}, {COL_9, COL_10} }, /*2GS2*/
+};
+
+/*
+ * Base AC Timing values specified by JESD209-2 for 400MHz operation
+ * All devices will honour these timings at this frequency.
+ * Some devices may have better timings. Using these timings is safe when the
+ * timings are not available from the device data sheet.
+ */
+const struct lpddr2_timings lpddr2_jedec_timings_400_mhz = {
+ .max_freq = 400000000,
+ .RL = 6,
+ .tRPab = 21,
+ .tRCD = 18,
+ .tWR = 15,
+ .tRASmin = 42,
+ .tRRD = 10,
+ .tWTRx2 = 15,
+ .tXSR = 140,
+ .tXPx2 = 15,
+ .tRFCab = 130,
+ .tRTPx2 = 15,
+ .tCKE = 3,
+ .tCKESR = 15,
+ .tZQCS = 90,
+ .tZQCL = 360,
+ .tZQINIT = 1000,
+ .tDQSCKMAXx2 = 11,
+ .tRASmax = 70,
+ .tFAW = 50
+};
+
+/* Base AC Timing values specified by JESD209-2 for 333 MHz operation */
+const struct lpddr2_timings lpddr2_jedec_timings_333_mhz = {
+ .max_freq = 333000000,
+ .RL = 5,
+ .tRPab = 21,
+ .tRCD = 18,
+ .tWR = 15,
+ .tRASmin = 42,
+ .tRRD = 10,
+ .tWTRx2 = 15,
+ .tXSR = 140,
+ .tXPx2 = 15,
+ .tRFCab = 130,
+ .tRTPx2 = 15,
+ .tCKE = 3,
+ .tCKESR = 15,
+ .tZQCS = 90,
+ .tZQCL = 360,
+ .tZQINIT = 1000,
+ .tDQSCKMAXx2 = 11,
+ .tRASmax = 70,
+ .tFAW = 50
+};
+
+/* Base AC Timing values specified by JESD209-2 for 200 MHz operation */
+const struct lpddr2_timings lpddr2_jedec_timings_200_mhz = {
+ .max_freq = 200000000,
+ .RL = 3,
+ .tRPab = 21,
+ .tRCD = 18,
+ .tWR = 15,
+ .tRASmin = 42,
+ .tRRD = 10,
+ .tWTRx2 = 20,
+ .tXSR = 140,
+ .tXPx2 = 15,
+ .tRFCab = 130,
+ .tRTPx2 = 15,
+ .tCKE = 3,
+ .tCKESR = 15,
+ .tZQCS = 90,
+ .tZQCL = 360,
+ .tZQINIT = 1000,
+ .tDQSCKMAXx2 = 11,
+ .tRASmax = 70,
+ .tFAW = 50
+};
+
+/*
+ * Min tCK values specified by JESD209-2
+ * Min tCK specifies the minimum duration of some AC timing parameters in terms
+ * of the number of cycles. If the calculated number of cycles based on the
+ * absolute time value is less than the min tCK value, min tCK value should
+ * be used instead. This typically happens at low frequencies.
+ */
+const struct lpddr2_min_tck lpddr2_jedec_min_tck = {
+ .tRL = 3,
+ .tRP_AB = 3,
+ .tRCD = 3,
+ .tWR = 3,
+ .tRAS_MIN = 3,
+ .tRRD = 2,
+ .tWTR = 2,
+ .tXP = 2,
+ .tRTP = 2,
+ .tCKE = 3,
+ .tCKESR = 3,
+ .tFAW = 8
+};
diff --git a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
index 22a45f8..d0b9856 100644
--- a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
@@ -2093,6 +2093,108 @@ static struct omap_hwmod omap44xx_dss_venc_hwmod = {
};
/*
+ * 'emif' class
+ * external memory interface no1
+ */
+
+static struct omap_hwmod_class omap44xx_emif_hwmod_class = {
+ .name = "emif",
+};
+
+/* emif1 */
+static struct omap_hwmod omap44xx_emif1_hwmod;
+static struct omap_hwmod_irq_info omap44xx_emif1_irqs[] = {
+ { .irq = 110 + OMAP44XX_IRQ_GIC_START },
+};
+
+static struct omap_hwmod_addr_space omap44xx_emif1_addrs[] = {
+ {
+ .pa_start = 0x4c000000,
+ .pa_end = 0x4c0000ff,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* emif_fw -> emif1 */
+static struct omap_hwmod_ocp_if omap44xx_emif_fw__emif1 = {
+ .master = &omap44xx_emif_fw_hwmod,
+ .slave = &omap44xx_emif1_hwmod,
+ .clk = "l3_div_ck",
+ .addr = omap44xx_emif1_addrs,
+ .addr_cnt = ARRAY_SIZE(omap44xx_emif1_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* emif1 slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_emif1_slaves[] = {
+ &omap44xx_emif_fw__emif1,
+};
+
+static struct omap_hwmod omap44xx_emif1_hwmod = {
+ .name = "emif1",
+ .class = &omap44xx_emif_hwmod_class,
+ .flags = HWMOD_INIT_NO_IDLE | HWMOD_INIT_NO_RESET,
+ .mpu_irqs = omap44xx_emif1_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap44xx_emif1_irqs),
+ .main_clk = "emif1_fck",
+ .prcm = {
+ .omap4 = {
+ .clkctrl_reg = OMAP4430_CM_MEMIF_EMIF_1_CLKCTRL,
+ },
+ },
+ .slaves = omap44xx_emif1_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap44xx_emif1_slaves),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX),
+};
+
+/* emif2 */
+static struct omap_hwmod omap44xx_emif2_hwmod;
+static struct omap_hwmod_irq_info omap44xx_emif2_irqs[] = {
+ { .irq = 111 + OMAP44XX_IRQ_GIC_START },
+};
+
+static struct omap_hwmod_addr_space omap44xx_emif2_addrs[] = {
+ {
+ .pa_start = 0x4d000000,
+ .pa_end = 0x4d0000ff,
+ .flags = ADDR_TYPE_RT
+ },
+};
+
+/* emif_fw -> emif2 */
+static struct omap_hwmod_ocp_if omap44xx_emif_fw__emif2 = {
+ .master = &omap44xx_emif_fw_hwmod,
+ .slave = &omap44xx_emif2_hwmod,
+ .clk = "l3_div_ck",
+ .addr = omap44xx_emif2_addrs,
+ .addr_cnt = ARRAY_SIZE(omap44xx_emif2_addrs),
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* emif2 slave ports */
+static struct omap_hwmod_ocp_if *omap44xx_emif2_slaves[] = {
+ &omap44xx_emif_fw__emif2,
+};
+
+static struct omap_hwmod omap44xx_emif2_hwmod = {
+ .name = "emif2",
+ .class = &omap44xx_emif_hwmod_class,
+ .flags = HWMOD_INIT_NO_IDLE | HWMOD_INIT_NO_RESET,
+ .mpu_irqs = omap44xx_emif2_irqs,
+ .mpu_irqs_cnt = ARRAY_SIZE(omap44xx_emif2_irqs),
+ .main_clk = "emif2_fck",
+ .prcm = {
+ .omap4 = {
+ .clkctrl_reg = OMAP4430_CM_MEMIF_EMIF_2_CLKCTRL,
+ },
+ },
+ .slaves = omap44xx_emif2_slaves,
+ .slaves_cnt = ARRAY_SIZE(omap44xx_emif2_slaves),
+ .omap_chip = OMAP_CHIP_INIT(CHIP_IS_OMAP44XX),
+};
+
+
+/*
* 'fdif' class
* face detection hw accelerator module
*/
@@ -5509,6 +5611,10 @@ static __initdata struct omap_hwmod *omap44xx_hwmods[] = {
&omap44xx_dss_rfbi_hwmod,
&omap44xx_dss_venc_hwmod,
+ /* emif class */
+ &omap44xx_emif1_hwmod,
+ &omap44xx_emif2_hwmod,
+
/* gpio class */
&omap443x_gpio1_hwmod,
&omap446x_gpio1_hwmod,