aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAneesh V <aneesh@ti.com>2012-04-27 08:24:06 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-05-02 13:52:09 -0400
commita93de288aad3b046935d626065d4bcbb7d93b093 (patch)
tree69fb0c026b801c22f166fabf2844440985dbbd79
parent7ec944538dde3d7f490bd4d2619051789db5c3c3 (diff)
memory: emif: handle frequency and voltage change events
Change SDRAM timings and other settings as necessary on voltage and frequency changes. We calculate these register settings based on data from the device data sheet and inputs such a frequency, voltage state(stable or ramping), temperature level etc. TODO: frequency and voltage change handling needs to be integrated with clock framework and regulator framework respectively. This is not done today due to missing pieces in the kernel. Signed-off-by: Aneesh V <aneesh@ti.com> Reviewed-by: Santosh Shilimkar <santosh.shilimkar@ti.com> Reviewed-by: Benoit Cousson <b-cousson@ti.com> [santosh.shilimkar@ti.com: Moved to drivers/memory from drivers/misc] Signed-off-by: Santosh Shilimkar <santosh.shilimkar@ti.com> Tested-by: Lokesh Vutla <lokeshvutla@ti.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/memory/emif.c894
-rw-r--r--drivers/memory/emif.h130
2 files changed, 1020 insertions, 4 deletions
diff --git a/drivers/memory/emif.c b/drivers/memory/emif.c
index 7486d7ef0826..bd116eb8c738 100644
--- a/drivers/memory/emif.c
+++ b/drivers/memory/emif.c
@@ -21,6 +21,7 @@
21#include <linux/seq_file.h> 21#include <linux/seq_file.h>
22#include <linux/module.h> 22#include <linux/module.h>
23#include <linux/list.h> 23#include <linux/list.h>
24#include <linux/spinlock.h>
24#include <memory/jedec_ddr.h> 25#include <memory/jedec_ddr.h>
25#include "emif.h" 26#include "emif.h"
26 27
@@ -37,20 +38,595 @@
37 * @node: node in the device list 38 * @node: node in the device list
38 * @base: base address of memory-mapped IO registers. 39 * @base: base address of memory-mapped IO registers.
39 * @dev: device pointer. 40 * @dev: device pointer.
41 * @addressing table with addressing information from the spec
42 * @regs_cache: An array of 'struct emif_regs' that stores
43 * calculated register values for different
44 * frequencies, to avoid re-calculating them on
45 * each DVFS transition.
46 * @curr_regs: The set of register values used in the last
47 * frequency change (i.e. corresponding to the
48 * frequency in effect at the moment)
40 * @plat_data: Pointer to saved platform data. 49 * @plat_data: Pointer to saved platform data.
41 */ 50 */
42struct emif_data { 51struct emif_data {
43 u8 duplicate; 52 u8 duplicate;
44 u8 temperature_level; 53 u8 temperature_level;
54 u8 lpmode;
45 struct list_head node; 55 struct list_head node;
56 unsigned long irq_state;
46 void __iomem *base; 57 void __iomem *base;
47 struct device *dev; 58 struct device *dev;
59 const struct lpddr2_addressing *addressing;
60 struct emif_regs *regs_cache[EMIF_MAX_NUM_FREQUENCIES];
61 struct emif_regs *curr_regs;
48 struct emif_platform_data *plat_data; 62 struct emif_platform_data *plat_data;
49}; 63};
50 64
51static struct emif_data *emif1; 65static struct emif_data *emif1;
66static spinlock_t emif_lock;
67static unsigned long irq_state;
68static u32 t_ck; /* DDR clock period in ps */
52static LIST_HEAD(device_list); 69static LIST_HEAD(device_list);
53 70
71/*
72 * Calculate the period of DDR clock from frequency value
73 */
74static void set_ddr_clk_period(u32 freq)
75{
76 /* Divide 10^12 by frequency to get period in ps */
77 t_ck = (u32)DIV_ROUND_UP_ULL(1000000000000ull, freq);
78}
79
80/*
81 * Get the CL from SDRAM_CONFIG register
82 */
83static u32 get_cl(struct emif_data *emif)
84{
85 u32 cl;
86 void __iomem *base = emif->base;
87
88 cl = (readl(base + EMIF_SDRAM_CONFIG) & CL_MASK) >> CL_SHIFT;
89
90 return cl;
91}
92
93static void set_lpmode(struct emif_data *emif, u8 lpmode)
94{
95 u32 temp;
96 void __iomem *base = emif->base;
97
98 temp = readl(base + EMIF_POWER_MANAGEMENT_CONTROL);
99 temp &= ~LP_MODE_MASK;
100 temp |= (lpmode << LP_MODE_SHIFT);
101 writel(temp, base + EMIF_POWER_MANAGEMENT_CONTROL);
102}
103
104static void do_freq_update(void)
105{
106 struct emif_data *emif;
107
108 /*
109 * Workaround for errata i728: Disable LPMODE during FREQ_UPDATE
110 *
111 * i728 DESCRIPTION:
112 * The EMIF automatically puts the SDRAM into self-refresh mode
113 * after the EMIF has not performed accesses during
114 * EMIF_PWR_MGMT_CTRL[7:4] REG_SR_TIM number of DDR clock cycles
115 * and the EMIF_PWR_MGMT_CTRL[10:8] REG_LP_MODE bit field is set
116 * to 0x2. If during a small window the following three events
117 * occur:
118 * - The SR_TIMING counter expires
119 * - And frequency change is requested
120 * - And OCP access is requested
121 * Then it causes instable clock on the DDR interface.
122 *
123 * WORKAROUND
124 * To avoid the occurrence of the three events, the workaround
125 * is to disable the self-refresh when requesting a frequency
126 * change. Before requesting a frequency change the software must
127 * program EMIF_PWR_MGMT_CTRL[10:8] REG_LP_MODE to 0x0. When the
128 * frequency change has been done, the software can reprogram
129 * EMIF_PWR_MGMT_CTRL[10:8] REG_LP_MODE to 0x2
130 */
131 list_for_each_entry(emif, &device_list, node) {
132 if (emif->lpmode == EMIF_LP_MODE_SELF_REFRESH)
133 set_lpmode(emif, EMIF_LP_MODE_DISABLE);
134 }
135
136 /*
137 * TODO: Do FREQ_UPDATE here when an API
138 * is available for this as part of the new
139 * clock framework
140 */
141
142 list_for_each_entry(emif, &device_list, node) {
143 if (emif->lpmode == EMIF_LP_MODE_SELF_REFRESH)
144 set_lpmode(emif, EMIF_LP_MODE_SELF_REFRESH);
145 }
146}
147
148/* Find addressing table entry based on the device's type and density */
149static const struct lpddr2_addressing *get_addressing_table(
150 const struct ddr_device_info *device_info)
151{
152 u32 index, type, density;
153
154 type = device_info->type;
155 density = device_info->density;
156
157 switch (type) {
158 case DDR_TYPE_LPDDR2_S4:
159 index = density - 1;
160 break;
161 case DDR_TYPE_LPDDR2_S2:
162 switch (density) {
163 case DDR_DENSITY_1Gb:
164 case DDR_DENSITY_2Gb:
165 index = density + 3;
166 break;
167 default:
168 index = density - 1;
169 }
170 break;
171 default:
172 return NULL;
173 }
174
175 return &lpddr2_jedec_addressing_table[index];
176}
177
178/*
179 * Find the the right timing table from the array of timing
180 * tables of the device using DDR clock frequency
181 */
182static const struct lpddr2_timings *get_timings_table(struct emif_data *emif,
183 u32 freq)
184{
185 u32 i, min, max, freq_nearest;
186 const struct lpddr2_timings *timings = NULL;
187 const struct lpddr2_timings *timings_arr = emif->plat_data->timings;
188 struct device *dev = emif->dev;
189
190 /* Start with a very high frequency - 1GHz */
191 freq_nearest = 1000000000;
192
193 /*
194 * Find the timings table such that:
195 * 1. the frequency range covers the required frequency(safe) AND
196 * 2. the max_freq is closest to the required frequency(optimal)
197 */
198 for (i = 0; i < emif->plat_data->timings_arr_size; i++) {
199 max = timings_arr[i].max_freq;
200 min = timings_arr[i].min_freq;
201 if ((freq >= min) && (freq <= max) && (max < freq_nearest)) {
202 freq_nearest = max;
203 timings = &timings_arr[i];
204 }
205 }
206
207 if (!timings)
208 dev_err(dev, "%s: couldn't find timings for - %dHz\n",
209 __func__, freq);
210
211 dev_dbg(dev, "%s: timings table: freq %d, speed bin freq %d\n",
212 __func__, freq, freq_nearest);