blob: d6a51839ef301b8a32a7c8642640d4bc2020fb40 [file] [log] [blame]
Channagoud Kadabiafb8e172013-05-23 13:55:47 -07001/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
2 *
3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions are
5 * met:
6 * * Redistributions of source code must retain the above copyright
7 * notice, this list of conditions and the following disclaimer.
8 * * Redistributions in binary form must reproduce the above
9 * copyright notice, this list of conditions and the following
10 * disclaimer in the documentation and/or other materials provided
11 * with the distribution.
12 * * Neither the name of The Linux Foundation nor the names of its
13 * contributors may be used to endorse or promote products derived
14 * from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
26 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include <platform/iomap.h>
30#include <platform/irqs.h>
31#include <platform/interrupts.h>
32#include <platform/timer.h>
Channagoud Kadabicfeee4d2013-07-26 12:02:49 -070033#include <sys/types.h>
Channagoud Kadabiafb8e172013-05-23 13:55:47 -070034#include <target.h>
35#include <string.h>
36#include <stdlib.h>
37#include <bits.h>
38#include <debug.h>
Channagoud Kadabicfeee4d2013-07-26 12:02:49 -070039#include <mmc.h>
Channagoud Kadabiafb8e172013-05-23 13:55:47 -070040#include <sdhci.h>
41#include <sdhci_msm.h>
42
Channagoud Kadabicfeee4d2013-07-26 12:02:49 -070043/* Known data stored in the card & read during tuning
44 * process. 64 bytes for 4bit bus width & 128 bytes
45 * of data for 8 bit bus width.
46 * These values are derived from HPG
47 */
48static const uint32_t tuning_block_64[] = {
49 0x00FF0FFF, 0xCCC3CCFF, 0xFFCC3CC3, 0xEFFEFFFE,
50 0xDDFFDFFF, 0xFBFFFBFF, 0xFF7FFFBF, 0xEFBDF777,
51 0xF0FFF0FF, 0x3CCCFC0F, 0xCFCC33CC, 0xEEFFEFFF,
52 0xFDFFFDFF, 0xFFBFFFDF, 0xFFF7FFBB, 0xDE7B7FF7
53};
54
55static const uint32_t tuning_block_128[] = {
56 0xFF00FFFF, 0x0000FFFF, 0xCCCCFFFF, 0xCCCC33CC,
57 0xCC3333CC, 0xFFFFCCCC, 0xFFFFEEFF, 0xFFEEEEFF,
58 0xFFDDFFFF, 0xDDDDFFFF, 0xBBFFFFFF, 0xBBFFFFFF,
59 0xFFFFFFBB, 0xFFFFFF77, 0x77FF7777, 0xFFEEDDBB,
60 0x00FFFFFF, 0x00FFFFFF, 0xCCFFFF00, 0xCC33CCCC,
61 0x3333CCCC, 0xFFCCCCCC, 0xFFEEFFFF, 0xEEEEFFFF,
62 0xDDFFFFFF, 0xDDFFFFFF, 0xFFFFFFDD, 0xFFFFFFBB,
63 0xFFFFBBBB, 0xFFFF77FF, 0xFF7777FF, 0xEEDDBB77
64};
Channagoud Kadabiafb8e172013-05-23 13:55:47 -070065
66/*
67 * Function: sdhci int handler
68 * Arg : MSM specific data for sdhci
69 * Return : 0
70 * Flow: : 1. Read the power control mask register
71 * 2. Check if bus is ON
72 * 3. Write success to ack regiser
73 * Details : This is power control interrupt handler.
74 * Once we receive the interrupt, we will ack the power control
75 * register that we have successfully completed pmic transactions
76 */
77static enum handler_return sdhci_int_handler(struct sdhci_msm_data *data)
78{
79 uint32_t ack;
80 uint32_t status;
81
82 /*
83 * Read the mask register to check if BUS & IO level
84 * interrupts are enabled
85 */
86 status = readl(data->pwrctl_base + SDCC_HC_PWRCTL_MASK_REG);
87
88 if (status & (SDCC_HC_BUS_ON | SDCC_HC_BUS_OFF))
89 ack = SDCC_HC_BUS_ON_OFF_SUCC;
90 if (status & (SDCC_HC_IO_SIG_LOW | SDCC_HC_IO_SIG_HIGH))
91 ack |= SDCC_HC_IO_SIG_SUCC;
92
93 /* Write success to power control register */
94 writel(ack, (data->pwrctl_base + SDCC_HC_PWRCTL_CTL_REG));
95
96 event_signal(data->sdhc_event, false);
97
98 return 0;
99}
100
101/*
102 * Function: sdhci clear pending interrupts
103 * Arg : MSM specific data for sdhci
104 * Return : None
105 * Flow: : Clear pending interrupts
106 */
107static void sdhci_clear_power_ctrl_irq(struct sdhci_msm_data *data)
108{
109 uint32_t irq_ctl;
110 uint32_t irq_stat;
111
112 /*
113 * Read the power control status register to know
114 * the status of BUS & IO_HIGH_V
115 */
116 irq_stat = readl(data->pwrctl_base + SDCC_HC_PWRCTL_STATUS_REG);
117
118 /* Clear the power control status */
119 writel(irq_stat, (data->pwrctl_base + SDCC_HC_PWRCTL_CLEAR_REG));
120
121 /*
122 * Handle the pending irq by ack'ing the bus & IO switch
123 */
124 irq_ctl = readl(data->pwrctl_base + SDCC_HC_PWRCTL_CTL_REG);
125
126 if (irq_stat & (SDCC_HC_BUS_ON | SDCC_HC_BUS_OFF))
127 irq_ctl |= SDCC_HC_BUS_ON_OFF_SUCC;
128 if (irq_stat & (SDCC_HC_IO_SIG_LOW | SDCC_HC_IO_SIG_HIGH))
129 irq_ctl |= SDCC_HC_IO_SIG_SUCC;
130
131 writel(irq_ctl, (data->pwrctl_base + SDCC_HC_PWRCTL_CTL_REG));
132}
133
134/*
135 * Function: sdhci msm init
136 * Arg : MSM specific config data for sdhci
137 * Return : None
138 * Flow: : Enable sdhci mode & do msm specific init
139 */
Channagoud Kadabicfeee4d2013-07-26 12:02:49 -0700140void sdhci_msm_init(struct sdhci_host *host, struct sdhci_msm_data *config)
Channagoud Kadabiafb8e172013-05-23 13:55:47 -0700141{
Channagoud Kadabi4ac38dd2013-12-30 11:51:53 -0800142 /* Disable HC mode */
143 RMWREG32((config->pwrctl_base + SDCC_MCI_HC_MODE), SDHCI_HC_START_BIT, SDHCI_HC_WIDTH, 0);
144
145 /* Core power reset */
146 RMWREG32((config->pwrctl_base + SDCC_MCI_POWER), CORE_SW_RST_START, CORE_SW_RST_WIDTH, 1);
147
148 /* Wait for the core power reset to complete*/
149 mdelay(1);
150
Channagoud Kadabiafb8e172013-05-23 13:55:47 -0700151 /* Enable sdhc mode */
152 writel(SDHCI_HC_MODE_EN, (config->pwrctl_base + SDCC_MCI_HC_MODE));
153
154 /*
Channagoud Kadabicfeee4d2013-07-26 12:02:49 -0700155 * Reset the controller
156 */
157 sdhci_reset(host, SDHCI_SOFT_RESET);
158
159 /*
Channagoud Kadabiafb8e172013-05-23 13:55:47 -0700160 * CORE_SW_RST may trigger power irq if previous status of PWRCTL
161 * was either BUS_ON or IO_HIGH. So before we enable the power irq
162 * interrupt in GIC (by registering the interrupt handler), we need to
163 * ensure that any pending power irq interrupt status is acknowledged
164 * otherwise power irq interrupt handler would be fired prematurely.
165 */
166 sdhci_clear_power_ctrl_irq(config);
167
168 /*
169 * Register the interrupt handler for pwr irq
170 */
171 register_int_handler(config->pwr_irq, sdhci_int_handler, (void *)config);
172
173 unmask_interrupt(config->pwr_irq);
174
175 /* Enable pwr control interrupt */
176 writel(SDCC_HC_PWR_CTRL_INT, (config->pwrctl_base + SDCC_HC_PWRCTL_MASK_REG));
Channagoud Kadabicfeee4d2013-07-26 12:02:49 -0700177
178 config->tuning_done = false;
179 config->calibration_done = false;
180 host->tuning_in_progress = false;
181}
182
183/*
184 * Function: sdhci msm set mci clk
185 * Arg : Host structure
186 * Return : None
187 * Flow: : Set HC_SELECT & HC_SELECT_EN for hs400
188 */
189void sdhci_msm_set_mci_clk(struct sdhci_host *host)
190{
191 struct sdhci_msm_data *msm_host;
192
193 msm_host = host->msm_host;
194
195 if (host->timing == MMC_HS400_TIMING)
196 {
197 /*
198 * If the current tuning mode is HS400 then we should set the MCLK to run
199 * the clock @ MCLK/2. Also set HS400 mode in SELECT_IN of vendor specific
200 * register
201 */
202 REG_RMW32(host, SDCC_VENDOR_SPECIFIC_FUNC, SDCC_HC_MCLK_HS400_START, SDCC_HC_MCLK_HS400_WIDTH, SDCC_HC_MCLK_SEL_HS400);
203
204 /* Enable HS400 mode from HC_SELECT_IN bit of VENDOR_SPEC register
205 * As the SDCC spec does not have matching mode for HS400
206 */
207 if (msm_host->tuning_done && !msm_host->calibration_done)
208 {
209 REG_RMW32(host, SDCC_VENDOR_SPECIFIC_FUNC, SDCC_HC_MCLK_SEL_IN_START, SDCC_HC_MCLK_SEL_IN_WIDTH, SDCC_HC_MCLK_SEL_IN_HS400);
210 REG_RMW32(host, SDCC_VENDOR_SPECIFIC_FUNC, SDCC_HC_MCLK_SEL_IN_EN_START, SDCC_HC_MCLK_SEL_IN_EN_WIDTH, SDCC_HC_MCLK_SEL_IN_EN);
211 }
212 }
213 else
214 {
215 /*
216 * Set 0x0 mode in SELECT_IN of vendor specific register so that the
217 * host control2 register settings from sdhc spec are used for
218 * speed mode
219 */
220 REG_RMW32(host, SDCC_VENDOR_SPECIFIC_FUNC, SDCC_HC_MCLK_SEL_IN_START, SDCC_HC_MCLK_SEL_IN_WIDTH, 0x0);
221 REG_RMW32(host, SDCC_VENDOR_SPECIFIC_FUNC, SDCC_HC_MCLK_SEL_IN_EN_START, SDCC_HC_MCLK_SEL_IN_EN_WIDTH, 0x0);
222 }
223}
224
225/*
226 * Set the value based on sdcc clock frequency
227 */
228static void msm_set_dll_freq(struct sdhci_host *host)
229{
230 uint32_t reg_val = 0;
231
232 /* Set clock freq value based on clock range */
233 if (host->cur_clk_rate <= 112000000)
234 reg_val = 0x0;
235 else if (host->cur_clk_rate <= 125000000)
236 reg_val = 0x1;
237 else if (host->cur_clk_rate <= 137000000)
238 reg_val = 0x2;
239 else if (host->cur_clk_rate <= 150000000)
240 reg_val = 0x3;
241 else if (host->cur_clk_rate <= 162000000)
242 reg_val = 0x4;
243 else if (host->cur_clk_rate <= 175000000)
244 reg_val = 0x5;
245 else if (host->cur_clk_rate <= 187000000)
246 reg_val = 0x6;
247 else if (host->cur_clk_rate <= 200000000)
248 reg_val = 0x7;
249
250 REG_RMW32(host, SDCC_DLL_CONFIG_REG, SDCC_DLL_CONFIG_MCLK_START, SDCC_DLL_CONFIG_MCLK_WIDTH, reg_val);
251}
252
253/* Initialize DLL (Programmable Delay Line) */
254static void sdhci_msm_init_dll(struct sdhci_host *host)
255{
256 uint32_t pwr_save = 0;
257
258 pwr_save = REG_READ32(host, SDCC_VENDOR_SPECIFIC_FUNC) & SDCC_DLL_PWR_SAVE_EN;
259
260 /* PWR SAVE to 0 */
261 if (pwr_save)
262 REG_WRITE32(host, (REG_READ32(host, SDCC_VENDOR_SPECIFIC_FUNC) & ~SDCC_DLL_PWR_SAVE_EN), SDCC_VENDOR_SPECIFIC_FUNC);
263 /* Set DLL_RST to 1 */
264 REG_WRITE32(host, (REG_READ32(host, SDCC_DLL_CONFIG_REG) | SDCC_DLL_RESET_EN), SDCC_DLL_CONFIG_REG);
265 /* Set DLL_PDN to 1 */
266 REG_WRITE32(host, (REG_READ32(host, SDCC_DLL_CONFIG_REG) | SDCC_DLL_PDN_EN), SDCC_DLL_CONFIG_REG);
267
268 /* Set frequency field in DLL_CONFIG */
269 msm_set_dll_freq(host);
270
271 /* Write 0 to DLL_RST */
272 REG_WRITE32(host, (REG_READ32(host, SDCC_DLL_CONFIG_REG) & ~SDCC_DLL_RESET_EN), SDCC_DLL_CONFIG_REG);
273 /* Write 0 to DLL_PDN */
274 REG_WRITE32(host, (REG_READ32(host, SDCC_DLL_CONFIG_REG) & ~SDCC_DLL_PDN_EN), SDCC_DLL_CONFIG_REG);
275 /* Write 1 to DLL_EN */
276 REG_WRITE32(host, (REG_READ32(host, SDCC_DLL_CONFIG_REG) | SDCC_DLL_EN), SDCC_DLL_CONFIG_REG);
277 /* Write 1 to CLK_OUT_EN */
278 REG_WRITE32(host, (REG_READ32(host, SDCC_DLL_CONFIG_REG) | SDCC_DLL_CLK_OUT_EN), SDCC_DLL_CONFIG_REG);
279 /* Wait for DLL_LOCK in DLL_STATUS register */
280 while(!((REG_READ32(host, SDCC_REG_DLL_STATUS)) & SDCC_DLL_LOCK_STAT));
281 /* Set the powersave back on */
282 if (pwr_save)
283 REG_WRITE32(host, (REG_READ32(host, SDCC_DLL_CONFIG_REG) | SDCC_DLL_PWR_SAVE_EN), SDCC_VENDOR_SPECIFIC_FUNC);
284}
285
286/* Configure DLL with delay value based on 'phase' */
287static void sdhci_msm_config_dll(struct sdhci_host *host, uint32_t phase)
288{
289 uint32_t core_cfg = 0;
290 /* Gray code values from SWI */
291 uint32_t gray_code [] = { 0x0, 0x1, 0x3, 0x2, 0x6, 0x7, 0x5, 0x4, 0xC, 0xD, 0xF, 0xE, 0xA, 0xB, 0x9, 0x8 };
292
293 /* set CDR_EN & CLK_OUT_EN to 0 and
294 * CDR_EXT_EN & DLL_EN to 1*/
295 core_cfg = REG_READ32(host, SDCC_DLL_CONFIG_REG);
296 core_cfg &= ~(SDCC_DLL_CDR_EN | SDCC_DLL_CLK_OUT_EN);
297 core_cfg |= (SDCC_DLL_CDR_EXT_EN | SDCC_DLL_EN);
298 REG_WRITE32(host, core_cfg, SDCC_DLL_CONFIG_REG);
299
300 /* Wait until CLK_OUT_EN is 0 */
301 while(REG_READ32(host, SDCC_DLL_CONFIG_REG) & SDCC_DLL_CLK_OUT_EN);
302
303 REG_RMW32(host, SDCC_DLL_CONFIG_REG, SDCC_DLL_GRAY_CODE_START, SDCC_DLL_GRAY_CODE_WIDTH, gray_code[phase]);
304
305 REG_WRITE32(host, (REG_READ32(host, SDCC_DLL_CONFIG_REG) | SDCC_DLL_CLK_OUT_EN), SDCC_DLL_CONFIG_REG);
306
307 /* Wait until CLK_OUT_EN is 1 */
308 while(!(REG_READ32(host, SDCC_DLL_CONFIG_REG) & SDCC_DLL_CLK_OUT_EN));
309
310 core_cfg = REG_READ32(host, SDCC_DLL_CONFIG_REG);
311
312 core_cfg |= SDCC_DLL_CDR_EN;
313 core_cfg &= ~SDCC_DLL_CDR_EXT_EN;
314
315 REG_WRITE32(host, core_cfg, SDCC_DLL_CONFIG_REG);
316
317 return;
318}
319
320/*
321 * Find the right tuning delay, this function finds the largest
322 * consecutive sequence of phases & then selects the 3/4 th of
323 * the range which has max entries
324 * For eg: If we get the following sequence in phase_table[]
325 * (A) phase_table[] = 0x1, 0x2, 0x3, 0x4 , 0x5
326 * (B) phase_table[] = 0xA, 0xB, 0xC
327 * In the above case the (A) has maximum consecutive entries with '5' entries
328 * So delay would be phase_table[(0x5 * 3) / 4] = 0x3
329 */
330static int sdhci_msm_find_appropriate_phase(struct sdhci_host *host,
331 uint32_t *phase_table,
332 uint32_t total_phases)
333{
334 int sub_phases[MAX_PHASES][MAX_PHASES]={{0}};
335 int phases_per_row[MAX_PHASES] = {0};
336 uint32_t i,j;
337 int selected_phase = 0;
338 uint32_t row_index = 0;
339 uint32_t col_index = 0;
340 uint32_t phase_15_row_idx = 0;
341 uint32_t phases_0_row_idx = 0;
342 uint32_t max_phases_3_4_idx = 0;
343 uint32_t max_phases = 0;
344 uint32_t max_phases_row = 0;
345 bool found_loop = false;
346
347 if (!phase_table[0] && phase_table[total_phases - 1] == (MAX_PHASES - 1))
348 found_loop = true;
349
350 for (i = 0; i < total_phases; i++)
351 {
352 /* Break the phase table entries into different sub arrays based
353 * on the consecutive entries. Each row will have one sub array
354 * of consecutive entries.
355 * for eg: phase_table [] = { 0x0, 0x1, 0x2, 0xA, 0xB}
356 * sub_phases [0][] = { 0x0, 0x1, 0x2}
357 * sub_phases [1][] = { 0xA, 0xB}
358 */
359 sub_phases[row_index][col_index] = phase_table[i];
360 phases_per_row[row_index]++;
361 col_index++;
362
363 /* If we are at the last phase no need to check further */
364 if ((i + 1) == total_phases)
365 break;
366
367 /* If phase_table does not have consecutive entries, move to next entry */
368 if (phase_table[i]+1 != phase_table[i+1])
369 {
370 row_index++;
371 col_index = 0;
372 }
373 }
374
375 if (found_loop && total_phases < MAX_PHASES)
376 {
377 /* For consecutive entries we need to consider loops.
378 * If the phase_table contains 0x0 & 0xF then we have
379 * a loop, the number after 0xF in the sequence would be
380 * 0x0.
381 * for eg:
382 * phase_table = { 0x0, 0x1, 0x2, 0xD, 0xE, 0xF }
383 * then
384 * sub_phase [0][] = { 0x0, 0x1, 0x2 }
385 * sub_phase [1][] = { 0xD, 0xE, 0xF }
386 * Since we have a loop here, we need to merge the sub arrays as:
387 * sub_phase [1][] = { 0xD, 0xE, 0xF, 0x0, 0x1, 0x2 }
388 */
389
390 /* The entry 0xF will always be in the last row
391 * and entry 0x0 will always be in the first row
392 */
393 phase_15_row_idx = row_index;
394 j = 0;
395 for (i = phases_per_row[phase_15_row_idx] ; i < MAX_PHASES ; i++)
396 {
397 sub_phases[phase_15_row_idx][i] = sub_phases[phases_0_row_idx][j];
398 if (++j >= phases_per_row[phases_0_row_idx])
399 break;
400 }
401
402 /* Update the number of entries for the sub_phase after the merger */
403 phases_per_row[phase_15_row_idx] = phases_per_row[phase_15_row_idx] + phases_per_row[phases_0_row_idx];
404 phases_per_row[phases_0_row_idx] = 0;
405 }
406
407 for (i = 0 ; i <= row_index; i++)
408 {
409 if (phases_per_row[i] > max_phases)
410 {
411 max_phases = phases_per_row[i];
412 max_phases_row = i;
413 }
414 }
415
416 max_phases_3_4_idx = (max_phases * 3) / 4;
417 if (max_phases_3_4_idx)
418 max_phases_3_4_idx--;
419
420 selected_phase = sub_phases[max_phases_row][max_phases_3_4_idx];
421
422 return selected_phase;
423}
424
425static uint32_t sdhci_msm_cdclp533_calibration(struct sdhci_host *host)
426{
427 uint32_t timeout;
428 uint32_t cdc_err;
429
430 /* Reset & Initialize the DLL block */
431 sdhci_msm_init_dll(host);
432
433 /* Write the save phase */
434 sdhci_msm_config_dll(host, host->msm_host->saved_phase);
435
436 /* Configure the clocks needed for CDC */
437 clock_config_cdc(host->msm_host->slot);
438
439 /* Set the FF_CLK_SW_RST_DIS to 1 */
440 REG_WRITE32(host, (REG_READ32(host, SDCC_MCI_HC_MODE) | FW_CLK_SW_RST_DIS), SDCC_MCI_HC_MODE);
441
442 /* Write 1 to CMD_DAT_TRACK_SEL field in DLL_CONFIG */
443 REG_WRITE32(host, (REG_READ32(host, SDCC_DLL_CONFIG_REG) | CMD_DAT_TRACK_SEL), SDCC_DLL_CONFIG_REG);
444
445 /* Write 0 to CDC_T4_DLY_SEL field in VENDOR_SPEC_DDR200_CFG */
446 REG_WRITE32(host, (REG_READ32(host, SDCC_CDC_DDR200_CFG) & ~CDC_T4_DLY_SEL), SDCC_CDC_DDR200_CFG);
447
448 /* Write 0 to START_CDC_TRAFFIC field in CORE_DDR200_CFG */
449 REG_WRITE32(host, (REG_READ32(host, SDCC_CDC_DDR200_CFG) & ~START_CDC_TRAFFIC), SDCC_CDC_DDR200_CFG);
450
451 /* Write 0 to CDC_SWITCH_BYPASS_OFF field in CSR_CDC_GEN_CFG */
452 REG_WRITE32(host, (REG_READ32(host, SDCC_VENDOR_SPEC_CSR_CDC_CFG) & ~CDC_SWITCH_BYPASS_OFF), SDCC_VENDOR_SPEC_CSR_CDC_CFG);
453
454 /* Write 1 to CDC_SWITCH_RC_EN field in CSR_CDC_GEN_CFG */
455 REG_WRITE32(host, (REG_READ32(host, SDCC_VENDOR_SPEC_CSR_CDC_CFG) | CDC_SWITCH_RC_EN), SDCC_VENDOR_SPEC_CSR_CDC_CFG);
456
457 /* Write 0 to START_CDC_TRAFFIC field in CORE_DDR200_CFG */
458 REG_WRITE32(host, (REG_READ32(host, SDCC_CDC_DDR200_CFG) & ~START_CDC_TRAFFIC), SDCC_CDC_DDR200_CFG);
459
460 /* Perform CDCLP533 initialization sequence
461 * SDCC_CSR_CDC_CTRL_CFG0 --> 0x11800EC
462 * SDCC_CSR_CDC_CTRL_CFG1 --> 0x3011111
463 * SDCC_CSR_CDC_CAL_TIMER_CFG0 --> 0x1201000
464 * SDCC_CSR_CDC_CAL_TIMER_CFG1 --> 0x4
465 * SDCC_CSR_CDC_REFCOUNT_CFG --> 0xCB732020
466 * SDCC_CSR_CDC_COARSE_CAL_CFG --> 0xB19
467 * SDCC_CSR_CDC_DELAY_CFG --> 0x3AC
468 * SDCC_CDC_OFFSET_CFG --> 0x0
469 * SDCC_CDC_SLAVE_DDA_CFG --> 0x16334
470 */
471
472 REG_WRITE32(host, 0x11800EC, SDCC_CSR_CDC_CTRL_CFG0);
473 REG_WRITE32(host, 0x3011111, SDCC_CSR_CDC_CTRL_CFG1);
474 REG_WRITE32(host, 0x1201000, SDCC_CSR_CDC_CAL_TIMER_CFG0);
475 REG_WRITE32(host, 0x4, SDCC_CSR_CDC_CAL_TIMER_CFG1);
476 REG_WRITE32(host, 0xCB732020, SDCC_CSR_CDC_REFCOUNT_CFG);
477 REG_WRITE32(host, 0xB19, SDCC_CSR_CDC_COARSE_CAL_CFG);
478 REG_WRITE32(host, 0x3AC, SDCC_CSR_CDC_DELAY_CFG);
479 REG_WRITE32(host, 0x0, SDCC_CDC_OFFSET_CFG);
480 REG_WRITE32(host, 0x16334, SDCC_CDC_SLAVE_DDA_CFG);
481
482 /* Write 1 to SW_TRIGGER_FULL_CALIB */
483 REG_WRITE32(host, (REG_READ32(host, SDCC_CSR_CDC_CTRL_CFG0) | CDC_SW_TRIGGER_FULL_CALIB), SDCC_CSR_CDC_CTRL_CFG0);
484
485 /* Write 0 to SW_TRIGGER_FULL_CALIB */
486 REG_WRITE32(host, (REG_READ32(host, SDCC_CSR_CDC_CTRL_CFG0) & ~CDC_SW_TRIGGER_FULL_CALIB), SDCC_CSR_CDC_CTRL_CFG0);
487
488 /* Write 1 to HW_AUTO_CAL_EN */
489 REG_WRITE32(host, (REG_READ32(host, SDCC_CSR_CDC_CTRL_CFG0) | CDC_HW_AUTO_CAL_EN), SDCC_CSR_CDC_CTRL_CFG0);
490
491 /* Write 1 to TIMER_ENA */
492 REG_WRITE32(host, (REG_READ32(host, SDCC_CSR_CDC_CAL_TIMER_CFG0) | CDC_TIMER_EN), SDCC_CSR_CDC_CAL_TIMER_CFG0);
493
494 /* Wait for CALIBRATION_DONE in CDC_STATUS */
495 timeout = 50;
496 while (!(REG_READ32(host, SDCC_CSR_CDC_STATUS0) & BIT(0)))
497 {
498 timeout--;
499 mdelay(1);
500 if (!timeout)
501 {
502 dprintf(CRITICAL, "Error: Calibration done in CDC status not set\n");
503 return 1;
504 }
505 }
506
507 cdc_err = REG_READ32(host, SDCC_CSR_CDC_STATUS0) & CSR_CDC_ERROR_MASK;
508 if (cdc_err)
509 {
510 dprintf(CRITICAL, "CDC error set during calibration: %x\n", cdc_err);
511 return 1;
512 }
513 /* Write 1 to START_CDC_TRAFFIC field in CORE_DDR200_CFG */
514 REG_WRITE32(host, (REG_READ32(host, SDCC_CDC_DDR200_CFG) | START_CDC_TRAFFIC), SDCC_CDC_DDR200_CFG);
515
516 return 0;
517}
518
519/*
520 * Function: sdhci msm execute tuning
521 * Arg : Host structure & bus width
522 * Return : 0 on Success, 1 on Failure
523 * Flow: : Execute Tuning sequence for HS200
524 */
525uint32_t sdhci_msm_execute_tuning(struct sdhci_host *host, uint32_t bus_width)
526{
527 uint32_t *tuning_block;
528 uint32_t *tuning_data;
529 uint32_t tuned_phases[MAX_PHASES] = {{0}};
530 uint32_t size;
531 uint32_t phase = 0;
532 uint32_t tuned_phase_cnt = 0;
533 int ret = 0;
534 struct sdhci_msm_data *msm_host;
535
536 msm_host = host->msm_host;
537
538 /* In Tuning mode */
539 host->tuning_in_progress = true;
540
541 /* Calibration for CDCLP533 needed for HS400 mode */
542 if (msm_host->tuning_done && !msm_host->calibration_done && host->timing == MMC_HS400_TIMING)
543 {
544 ret = sdhci_msm_cdclp533_calibration(host);
545 if (!ret)
546 msm_host->calibration_done = true;
547 goto out;
548 }
549
550 if (bus_width == DATA_BUS_WIDTH_8BIT)
551 {
552 tuning_block = tuning_block_128;
553 size = sizeof(tuning_block_128);
554 }
555 else
556 {
557 tuning_block = tuning_block_64;
558 size = sizeof(tuning_block_64);
559 }
560
561 tuning_data = (uint32_t *) memalign(CACHE_LINE, ROUNDUP(size, CACHE_LINE));
562
563 ASSERT(tuning_data);
564
565 /* Reset & Initialize the DLL block */
566 sdhci_msm_init_dll(host);
567
568 while (phase < MAX_PHASES)
569 {
570 struct mmc_command cmd = {0};
571
572 /* configure dll to set phase delay */
573 sdhci_msm_config_dll(host, phase);
574
575 cmd.cmd_index = CMD21_SEND_TUNING_BLOCK;
576 cmd.argument = 0x0;
577 cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL;
578 cmd.resp_type = SDHCI_CMD_RESP_R1;
579 cmd.trans_mode = SDHCI_MMC_READ;
580 cmd.data_present = 0x1;
581 cmd.data.data_ptr = tuning_data;
582 cmd.data.blk_sz = size;
583 cmd.data.num_blocks = 0x1;
584
585 /* send command */
586 if (!sdhci_send_command(host, &cmd) && !memcmp(tuning_data, tuning_block, size))
587 tuned_phases[tuned_phase_cnt++] = phase;
588
589 phase++;
590 }
591
592 /* Find the appropriate tuned phase */
593 if (tuned_phase_cnt)
594 {
595 ret = sdhci_msm_find_appropriate_phase(host, tuned_phases, tuned_phase_cnt);
596
597 if (ret < 0)
598 {
599 dprintf(CRITICAL, "Failed in selecting the tuning phase\n");
600 ret = 1;
601 goto free;
602 }
603
604 phase = (uint32_t) ret;
605 ret = 0;
606
607 sdhci_msm_config_dll(host, phase);
608
609 /* Save the tuned phase */
610 host->msm_host->saved_phase = phase;
611 }
612 else
613 {
614 dprintf(CRITICAL, "Failed to get tuned phase\n");
615 ret = 1;
616 }
617
618free:
619 free(tuning_data);
620out:
621 /* Tuning done */
622 host->tuning_in_progress = false;
623 host->msm_host->tuning_done = true;
624 return ret;
Channagoud Kadabiafb8e172013-05-23 13:55:47 -0700625}