blob: 7554016f55726b93c3965b6d82bfa36d48d63977 [file] [log] [blame]
Channagoud Kadabid2137a62014-01-24 17:22:08 -08001/* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
Channagoud Kadabiafb8e172013-05-23 13:55:47 -07002 *
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
Channagoud Kadabifd96a0b2014-03-31 15:26:00 -0700154 /* Set the FF_CLK_SW_RST_DIS to 1 */
155 RMWREG32((config->pwrctl_base + SDCC_MCI_HC_MODE), FF_CLK_SW_RST_DIS_START, FF_CLK_SW_RST_DIS_WIDTH, 1);
156
Channagoud Kadabiafb8e172013-05-23 13:55:47 -0700157 /*
Channagoud Kadabicfeee4d2013-07-26 12:02:49 -0700158 * Reset the controller
159 */
160 sdhci_reset(host, SDHCI_SOFT_RESET);
161
162 /*
Channagoud Kadabiafb8e172013-05-23 13:55:47 -0700163 * CORE_SW_RST may trigger power irq if previous status of PWRCTL
164 * was either BUS_ON or IO_HIGH. So before we enable the power irq
165 * interrupt in GIC (by registering the interrupt handler), we need to
166 * ensure that any pending power irq interrupt status is acknowledged
167 * otherwise power irq interrupt handler would be fired prematurely.
168 */
169 sdhci_clear_power_ctrl_irq(config);
170
171 /*
172 * Register the interrupt handler for pwr irq
173 */
174 register_int_handler(config->pwr_irq, sdhci_int_handler, (void *)config);
175
176 unmask_interrupt(config->pwr_irq);
177
178 /* Enable pwr control interrupt */
179 writel(SDCC_HC_PWR_CTRL_INT, (config->pwrctl_base + SDCC_HC_PWRCTL_MASK_REG));
Channagoud Kadabicfeee4d2013-07-26 12:02:49 -0700180
181 config->tuning_done = false;
182 config->calibration_done = false;
183 host->tuning_in_progress = false;
184}
185
186/*
187 * Function: sdhci msm set mci clk
188 * Arg : Host structure
189 * Return : None
190 * Flow: : Set HC_SELECT & HC_SELECT_EN for hs400
191 */
192void sdhci_msm_set_mci_clk(struct sdhci_host *host)
193{
194 struct sdhci_msm_data *msm_host;
195
196 msm_host = host->msm_host;
197
198 if (host->timing == MMC_HS400_TIMING)
199 {
200 /*
201 * If the current tuning mode is HS400 then we should set the MCLK to run
202 * the clock @ MCLK/2. Also set HS400 mode in SELECT_IN of vendor specific
203 * register
204 */
205 REG_RMW32(host, SDCC_VENDOR_SPECIFIC_FUNC, SDCC_HC_MCLK_HS400_START, SDCC_HC_MCLK_HS400_WIDTH, SDCC_HC_MCLK_SEL_HS400);
206
207 /* Enable HS400 mode from HC_SELECT_IN bit of VENDOR_SPEC register
208 * As the SDCC spec does not have matching mode for HS400
209 */
210 if (msm_host->tuning_done && !msm_host->calibration_done)
211 {
212 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);
213 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);
214 }
215 }
216 else
217 {
218 /*
219 * Set 0x0 mode in SELECT_IN of vendor specific register so that the
220 * host control2 register settings from sdhc spec are used for
221 * speed mode
222 */
223 REG_RMW32(host, SDCC_VENDOR_SPECIFIC_FUNC, SDCC_HC_MCLK_SEL_IN_START, SDCC_HC_MCLK_SEL_IN_WIDTH, 0x0);
224 REG_RMW32(host, SDCC_VENDOR_SPECIFIC_FUNC, SDCC_HC_MCLK_SEL_IN_EN_START, SDCC_HC_MCLK_SEL_IN_EN_WIDTH, 0x0);
225 }
226}
227
228/*
229 * Set the value based on sdcc clock frequency
230 */
231static void msm_set_dll_freq(struct sdhci_host *host)
232{
233 uint32_t reg_val = 0;
234
235 /* Set clock freq value based on clock range */
236 if (host->cur_clk_rate <= 112000000)
237 reg_val = 0x0;
238 else if (host->cur_clk_rate <= 125000000)
239 reg_val = 0x1;
240 else if (host->cur_clk_rate <= 137000000)
241 reg_val = 0x2;
242 else if (host->cur_clk_rate <= 150000000)
243 reg_val = 0x3;
244 else if (host->cur_clk_rate <= 162000000)
245 reg_val = 0x4;
246 else if (host->cur_clk_rate <= 175000000)
247 reg_val = 0x5;
248 else if (host->cur_clk_rate <= 187000000)
249 reg_val = 0x6;
250 else if (host->cur_clk_rate <= 200000000)
251 reg_val = 0x7;
252
Channagoud Kadabifd96a0b2014-03-31 15:26:00 -0700253 DBG("\n %s: DLL freq: 0x%08x\n", __func__, reg_val);
254
Channagoud Kadabicfeee4d2013-07-26 12:02:49 -0700255 REG_RMW32(host, SDCC_DLL_CONFIG_REG, SDCC_DLL_CONFIG_MCLK_START, SDCC_DLL_CONFIG_MCLK_WIDTH, reg_val);
256}
257
258/* Initialize DLL (Programmable Delay Line) */
Channagoud Kadabifd96a0b2014-03-31 15:26:00 -0700259static uint32_t sdhci_msm_init_dll(struct sdhci_host *host)
Channagoud Kadabicfeee4d2013-07-26 12:02:49 -0700260{
261 uint32_t pwr_save = 0;
Channagoud Kadabifd96a0b2014-03-31 15:26:00 -0700262 uint32_t timeout = SDHCI_DLL_TIMEOUT;
Channagoud Kadabicfeee4d2013-07-26 12:02:49 -0700263
264 pwr_save = REG_READ32(host, SDCC_VENDOR_SPECIFIC_FUNC) & SDCC_DLL_PWR_SAVE_EN;
265
266 /* PWR SAVE to 0 */
267 if (pwr_save)
268 REG_WRITE32(host, (REG_READ32(host, SDCC_VENDOR_SPECIFIC_FUNC) & ~SDCC_DLL_PWR_SAVE_EN), SDCC_VENDOR_SPECIFIC_FUNC);
269 /* Set DLL_RST to 1 */
270 REG_WRITE32(host, (REG_READ32(host, SDCC_DLL_CONFIG_REG) | SDCC_DLL_RESET_EN), SDCC_DLL_CONFIG_REG);
271 /* Set DLL_PDN to 1 */
272 REG_WRITE32(host, (REG_READ32(host, SDCC_DLL_CONFIG_REG) | SDCC_DLL_PDN_EN), SDCC_DLL_CONFIG_REG);
273
274 /* Set frequency field in DLL_CONFIG */
275 msm_set_dll_freq(host);
276
277 /* Write 0 to DLL_RST */
278 REG_WRITE32(host, (REG_READ32(host, SDCC_DLL_CONFIG_REG) & ~SDCC_DLL_RESET_EN), SDCC_DLL_CONFIG_REG);
279 /* Write 0 to DLL_PDN */
280 REG_WRITE32(host, (REG_READ32(host, SDCC_DLL_CONFIG_REG) & ~SDCC_DLL_PDN_EN), SDCC_DLL_CONFIG_REG);
281 /* Write 1 to DLL_EN */
282 REG_WRITE32(host, (REG_READ32(host, SDCC_DLL_CONFIG_REG) | SDCC_DLL_EN), SDCC_DLL_CONFIG_REG);
283 /* Write 1 to CLK_OUT_EN */
284 REG_WRITE32(host, (REG_READ32(host, SDCC_DLL_CONFIG_REG) | SDCC_DLL_CLK_OUT_EN), SDCC_DLL_CONFIG_REG);
Channagoud Kadabifd96a0b2014-03-31 15:26:00 -0700285 /* Wait for DLL_LOCK in DLL_STATUS register, wait time 50us */
Channagoud Kadabicfeee4d2013-07-26 12:02:49 -0700286 while(!((REG_READ32(host, SDCC_REG_DLL_STATUS)) & SDCC_DLL_LOCK_STAT));
Channagoud Kadabifd96a0b2014-03-31 15:26:00 -0700287 {
288 udelay(1);
289 timeout--;
290 if (!timeout)
291 {
292 dprintf(CRITICAL, "%s: Failed to get DLL lock: 0x%08x\n", __func__, REG_READ32(host, SDCC_REG_DLL_STATUS));
293 return 1;
294 }
295 }
296
Channagoud Kadabicfeee4d2013-07-26 12:02:49 -0700297 /* Set the powersave back on */
298 if (pwr_save)
299 REG_WRITE32(host, (REG_READ32(host, SDCC_DLL_CONFIG_REG) | SDCC_DLL_PWR_SAVE_EN), SDCC_VENDOR_SPECIFIC_FUNC);
Channagoud Kadabifd96a0b2014-03-31 15:26:00 -0700300
301 return 0;
Channagoud Kadabicfeee4d2013-07-26 12:02:49 -0700302}
303
Channagoud Kadabi15e65252014-07-09 10:35:01 -0700304void sdhci_msm_toggle_cdr(struct sdhci_host *host, bool enable)
305{
306 uint32_t core_cfg;
307
308 core_cfg = REG_READ32(host, SDCC_DLL_CONFIG_REG);
309
310 if (enable)
311 {
312 core_cfg |= SDCC_DLL_CDR_EN;
313 }
314 else
315 {
316 core_cfg &= ~SDCC_DLL_CDR_EN;
317 }
318
319 REG_WRITE32(host, core_cfg, SDCC_DLL_CONFIG_REG);
320}
321
Channagoud Kadabicfeee4d2013-07-26 12:02:49 -0700322/* Configure DLL with delay value based on 'phase' */
Channagoud Kadabifd96a0b2014-03-31 15:26:00 -0700323static uint32_t sdhci_msm_config_dll(struct sdhci_host *host, uint32_t phase)
Channagoud Kadabicfeee4d2013-07-26 12:02:49 -0700324{
325 uint32_t core_cfg = 0;
Channagoud Kadabifd96a0b2014-03-31 15:26:00 -0700326 uint32_t timeout = SDHCI_DLL_TIMEOUT;
327
Channagoud Kadabicfeee4d2013-07-26 12:02:49 -0700328 /* Gray code values from SWI */
329 uint32_t gray_code [] = { 0x0, 0x1, 0x3, 0x2, 0x6, 0x7, 0x5, 0x4, 0xC, 0xD, 0xF, 0xE, 0xA, 0xB, 0x9, 0x8 };
330
331 /* set CDR_EN & CLK_OUT_EN to 0 and
332 * CDR_EXT_EN & DLL_EN to 1*/
333 core_cfg = REG_READ32(host, SDCC_DLL_CONFIG_REG);
334 core_cfg &= ~(SDCC_DLL_CDR_EN | SDCC_DLL_CLK_OUT_EN);
335 core_cfg |= (SDCC_DLL_CDR_EXT_EN | SDCC_DLL_EN);
336 REG_WRITE32(host, core_cfg, SDCC_DLL_CONFIG_REG);
337
338 /* Wait until CLK_OUT_EN is 0 */
339 while(REG_READ32(host, SDCC_DLL_CONFIG_REG) & SDCC_DLL_CLK_OUT_EN);
340
341 REG_RMW32(host, SDCC_DLL_CONFIG_REG, SDCC_DLL_GRAY_CODE_START, SDCC_DLL_GRAY_CODE_WIDTH, gray_code[phase]);
342
343 REG_WRITE32(host, (REG_READ32(host, SDCC_DLL_CONFIG_REG) | SDCC_DLL_CLK_OUT_EN), SDCC_DLL_CONFIG_REG);
344
Channagoud Kadabifd96a0b2014-03-31 15:26:00 -0700345 /* Wait until CLK_OUT_EN is 1, wait time 50us */
346 while(!(REG_READ32(host, SDCC_DLL_CONFIG_REG) & SDCC_DLL_CLK_OUT_EN))
347 {
348 timeout--;
349 udelay(1);
350 if (!timeout)
351 {
352 dprintf(CRITICAL, "%s: clk_out_en timed out: %08x\n", __func__, REG_READ32(host, SDCC_DLL_CONFIG_REG));
353 return 1;
354 }
355 }
Channagoud Kadabicfeee4d2013-07-26 12:02:49 -0700356
357 core_cfg = REG_READ32(host, SDCC_DLL_CONFIG_REG);
358
359 core_cfg |= SDCC_DLL_CDR_EN;
360 core_cfg &= ~SDCC_DLL_CDR_EXT_EN;
361
362 REG_WRITE32(host, core_cfg, SDCC_DLL_CONFIG_REG);
363
Channagoud Kadabifd96a0b2014-03-31 15:26:00 -0700364 return 0;
Channagoud Kadabicfeee4d2013-07-26 12:02:49 -0700365}
366
367/*
368 * Find the right tuning delay, this function finds the largest
369 * consecutive sequence of phases & then selects the 3/4 th of
370 * the range which has max entries
371 * For eg: If we get the following sequence in phase_table[]
372 * (A) phase_table[] = 0x1, 0x2, 0x3, 0x4 , 0x5
373 * (B) phase_table[] = 0xA, 0xB, 0xC
374 * In the above case the (A) has maximum consecutive entries with '5' entries
375 * So delay would be phase_table[(0x5 * 3) / 4] = 0x3
376 */
377static int sdhci_msm_find_appropriate_phase(struct sdhci_host *host,
378 uint32_t *phase_table,
379 uint32_t total_phases)
380{
381 int sub_phases[MAX_PHASES][MAX_PHASES]={{0}};
382 int phases_per_row[MAX_PHASES] = {0};
383 uint32_t i,j;
384 int selected_phase = 0;
385 uint32_t row_index = 0;
386 uint32_t col_index = 0;
387 uint32_t phase_15_row_idx = 0;
388 uint32_t phases_0_row_idx = 0;
389 uint32_t max_phases_3_4_idx = 0;
390 uint32_t max_phases = 0;
391 uint32_t max_phases_row = 0;
392 bool found_loop = false;
393
394 if (!phase_table[0] && phase_table[total_phases - 1] == (MAX_PHASES - 1))
395 found_loop = true;
396
397 for (i = 0; i < total_phases; i++)
398 {
399 /* Break the phase table entries into different sub arrays based
400 * on the consecutive entries. Each row will have one sub array
401 * of consecutive entries.
402 * for eg: phase_table [] = { 0x0, 0x1, 0x2, 0xA, 0xB}
403 * sub_phases [0][] = { 0x0, 0x1, 0x2}
404 * sub_phases [1][] = { 0xA, 0xB}
405 */
406 sub_phases[row_index][col_index] = phase_table[i];
407 phases_per_row[row_index]++;
408 col_index++;
409
410 /* If we are at the last phase no need to check further */
411 if ((i + 1) == total_phases)
412 break;
413
414 /* If phase_table does not have consecutive entries, move to next entry */
415 if (phase_table[i]+1 != phase_table[i+1])
416 {
417 row_index++;
418 col_index = 0;
419 }
420 }
421
422 if (found_loop && total_phases < MAX_PHASES)
423 {
424 /* For consecutive entries we need to consider loops.
425 * If the phase_table contains 0x0 & 0xF then we have
426 * a loop, the number after 0xF in the sequence would be
427 * 0x0.
428 * for eg:
429 * phase_table = { 0x0, 0x1, 0x2, 0xD, 0xE, 0xF }
430 * then
431 * sub_phase [0][] = { 0x0, 0x1, 0x2 }
432 * sub_phase [1][] = { 0xD, 0xE, 0xF }
433 * Since we have a loop here, we need to merge the sub arrays as:
434 * sub_phase [1][] = { 0xD, 0xE, 0xF, 0x0, 0x1, 0x2 }
435 */
436
437 /* The entry 0xF will always be in the last row
438 * and entry 0x0 will always be in the first row
439 */
440 phase_15_row_idx = row_index;
441 j = 0;
442 for (i = phases_per_row[phase_15_row_idx] ; i < MAX_PHASES ; i++)
443 {
444 sub_phases[phase_15_row_idx][i] = sub_phases[phases_0_row_idx][j];
445 if (++j >= phases_per_row[phases_0_row_idx])
446 break;
447 }
448
449 /* Update the number of entries for the sub_phase after the merger */
450 phases_per_row[phase_15_row_idx] = phases_per_row[phase_15_row_idx] + phases_per_row[phases_0_row_idx];
451 phases_per_row[phases_0_row_idx] = 0;
452 }
453
454 for (i = 0 ; i <= row_index; i++)
455 {
456 if (phases_per_row[i] > max_phases)
457 {
458 max_phases = phases_per_row[i];
459 max_phases_row = i;
460 }
461 }
462
463 max_phases_3_4_idx = (max_phases * 3) / 4;
464 if (max_phases_3_4_idx)
465 max_phases_3_4_idx--;
466
467 selected_phase = sub_phases[max_phases_row][max_phases_3_4_idx];
468
469 return selected_phase;
470}
471
472static uint32_t sdhci_msm_cdclp533_calibration(struct sdhci_host *host)
473{
474 uint32_t timeout;
475 uint32_t cdc_err;
476
Channagoud Kadabifd96a0b2014-03-31 15:26:00 -0700477 DBG("\n CDCLP533 Calibration Start\n");
478
Channagoud Kadabicfeee4d2013-07-26 12:02:49 -0700479 /* Reset & Initialize the DLL block */
Channagoud Kadabifd96a0b2014-03-31 15:26:00 -0700480 if (sdhci_msm_init_dll(host))
481 return 1;
Channagoud Kadabicfeee4d2013-07-26 12:02:49 -0700482
483 /* Write the save phase */
Channagoud Kadabifd96a0b2014-03-31 15:26:00 -0700484 if (sdhci_msm_config_dll(host, host->msm_host->saved_phase))
485 return 1;
Channagoud Kadabicfeee4d2013-07-26 12:02:49 -0700486
487 /* Write 1 to CMD_DAT_TRACK_SEL field in DLL_CONFIG */
488 REG_WRITE32(host, (REG_READ32(host, SDCC_DLL_CONFIG_REG) | CMD_DAT_TRACK_SEL), SDCC_DLL_CONFIG_REG);
489
490 /* Write 0 to CDC_T4_DLY_SEL field in VENDOR_SPEC_DDR200_CFG */
491 REG_WRITE32(host, (REG_READ32(host, SDCC_CDC_DDR200_CFG) & ~CDC_T4_DLY_SEL), SDCC_CDC_DDR200_CFG);
492
493 /* Write 0 to START_CDC_TRAFFIC field in CORE_DDR200_CFG */
494 REG_WRITE32(host, (REG_READ32(host, SDCC_CDC_DDR200_CFG) & ~START_CDC_TRAFFIC), SDCC_CDC_DDR200_CFG);
495
496 /* Write 0 to CDC_SWITCH_BYPASS_OFF field in CSR_CDC_GEN_CFG */
497 REG_WRITE32(host, (REG_READ32(host, SDCC_VENDOR_SPEC_CSR_CDC_CFG) & ~CDC_SWITCH_BYPASS_OFF), SDCC_VENDOR_SPEC_CSR_CDC_CFG);
498
499 /* Write 1 to CDC_SWITCH_RC_EN field in CSR_CDC_GEN_CFG */
500 REG_WRITE32(host, (REG_READ32(host, SDCC_VENDOR_SPEC_CSR_CDC_CFG) | CDC_SWITCH_RC_EN), SDCC_VENDOR_SPEC_CSR_CDC_CFG);
501
502 /* Write 0 to START_CDC_TRAFFIC field in CORE_DDR200_CFG */
503 REG_WRITE32(host, (REG_READ32(host, SDCC_CDC_DDR200_CFG) & ~START_CDC_TRAFFIC), SDCC_CDC_DDR200_CFG);
504
505 /* Perform CDCLP533 initialization sequence
506 * SDCC_CSR_CDC_CTRL_CFG0 --> 0x11800EC
507 * SDCC_CSR_CDC_CTRL_CFG1 --> 0x3011111
508 * SDCC_CSR_CDC_CAL_TIMER_CFG0 --> 0x1201000
509 * SDCC_CSR_CDC_CAL_TIMER_CFG1 --> 0x4
510 * SDCC_CSR_CDC_REFCOUNT_CFG --> 0xCB732020
511 * SDCC_CSR_CDC_COARSE_CAL_CFG --> 0xB19
512 * SDCC_CSR_CDC_DELAY_CFG --> 0x3AC
513 * SDCC_CDC_OFFSET_CFG --> 0x0
514 * SDCC_CDC_SLAVE_DDA_CFG --> 0x16334
515 */
516
517 REG_WRITE32(host, 0x11800EC, SDCC_CSR_CDC_CTRL_CFG0);
518 REG_WRITE32(host, 0x3011111, SDCC_CSR_CDC_CTRL_CFG1);
519 REG_WRITE32(host, 0x1201000, SDCC_CSR_CDC_CAL_TIMER_CFG0);
520 REG_WRITE32(host, 0x4, SDCC_CSR_CDC_CAL_TIMER_CFG1);
521 REG_WRITE32(host, 0xCB732020, SDCC_CSR_CDC_REFCOUNT_CFG);
522 REG_WRITE32(host, 0xB19, SDCC_CSR_CDC_COARSE_CAL_CFG);
523 REG_WRITE32(host, 0x3AC, SDCC_CSR_CDC_DELAY_CFG);
524 REG_WRITE32(host, 0x0, SDCC_CDC_OFFSET_CFG);
525 REG_WRITE32(host, 0x16334, SDCC_CDC_SLAVE_DDA_CFG);
526
527 /* Write 1 to SW_TRIGGER_FULL_CALIB */
528 REG_WRITE32(host, (REG_READ32(host, SDCC_CSR_CDC_CTRL_CFG0) | CDC_SW_TRIGGER_FULL_CALIB), SDCC_CSR_CDC_CTRL_CFG0);
529
530 /* Write 0 to SW_TRIGGER_FULL_CALIB */
531 REG_WRITE32(host, (REG_READ32(host, SDCC_CSR_CDC_CTRL_CFG0) & ~CDC_SW_TRIGGER_FULL_CALIB), SDCC_CSR_CDC_CTRL_CFG0);
532
533 /* Write 1 to HW_AUTO_CAL_EN */
534 REG_WRITE32(host, (REG_READ32(host, SDCC_CSR_CDC_CTRL_CFG0) | CDC_HW_AUTO_CAL_EN), SDCC_CSR_CDC_CTRL_CFG0);
535
536 /* Write 1 to TIMER_ENA */
537 REG_WRITE32(host, (REG_READ32(host, SDCC_CSR_CDC_CAL_TIMER_CFG0) | CDC_TIMER_EN), SDCC_CSR_CDC_CAL_TIMER_CFG0);
538
539 /* Wait for CALIBRATION_DONE in CDC_STATUS */
Channagoud Kadabifd96a0b2014-03-31 15:26:00 -0700540 timeout = CDC_STATUS_TIMEOUT;
Channagoud Kadabicfeee4d2013-07-26 12:02:49 -0700541 while (!(REG_READ32(host, SDCC_CSR_CDC_STATUS0) & BIT(0)))
542 {
543 timeout--;
544 mdelay(1);
545 if (!timeout)
546 {
547 dprintf(CRITICAL, "Error: Calibration done in CDC status not set\n");
548 return 1;
549 }
550 }
551
552 cdc_err = REG_READ32(host, SDCC_CSR_CDC_STATUS0) & CSR_CDC_ERROR_MASK;
553 if (cdc_err)
554 {
555 dprintf(CRITICAL, "CDC error set during calibration: %x\n", cdc_err);
556 return 1;
557 }
558 /* Write 1 to START_CDC_TRAFFIC field in CORE_DDR200_CFG */
559 REG_WRITE32(host, (REG_READ32(host, SDCC_CDC_DDR200_CFG) | START_CDC_TRAFFIC), SDCC_CDC_DDR200_CFG);
560
Channagoud Kadabifd96a0b2014-03-31 15:26:00 -0700561 DBG("\n CDCLP533 Calibration Done\n");
562
Channagoud Kadabicfeee4d2013-07-26 12:02:49 -0700563 return 0;
564}
565
566/*
567 * Function: sdhci msm execute tuning
568 * Arg : Host structure & bus width
569 * Return : 0 on Success, 1 on Failure
570 * Flow: : Execute Tuning sequence for HS200
571 */
572uint32_t sdhci_msm_execute_tuning(struct sdhci_host *host, uint32_t bus_width)
573{
574 uint32_t *tuning_block;
575 uint32_t *tuning_data;
576 uint32_t tuned_phases[MAX_PHASES] = {{0}};
577 uint32_t size;
578 uint32_t phase = 0;
579 uint32_t tuned_phase_cnt = 0;
580 int ret = 0;
Channagoud Kadabifd96a0b2014-03-31 15:26:00 -0700581 int i;
Channagoud Kadabicfeee4d2013-07-26 12:02:49 -0700582 struct sdhci_msm_data *msm_host;
583
584 msm_host = host->msm_host;
585
586 /* In Tuning mode */
587 host->tuning_in_progress = true;
588
589 /* Calibration for CDCLP533 needed for HS400 mode */
590 if (msm_host->tuning_done && !msm_host->calibration_done && host->timing == MMC_HS400_TIMING)
591 {
592 ret = sdhci_msm_cdclp533_calibration(host);
593 if (!ret)
594 msm_host->calibration_done = true;
595 goto out;
596 }
597
598 if (bus_width == DATA_BUS_WIDTH_8BIT)
599 {
600 tuning_block = tuning_block_128;
601 size = sizeof(tuning_block_128);
602 }
603 else
604 {
605 tuning_block = tuning_block_64;
606 size = sizeof(tuning_block_64);
607 }
608
609 tuning_data = (uint32_t *) memalign(CACHE_LINE, ROUNDUP(size, CACHE_LINE));
610
611 ASSERT(tuning_data);
612
613 /* Reset & Initialize the DLL block */
Channagoud Kadabifd96a0b2014-03-31 15:26:00 -0700614 if (sdhci_msm_init_dll(host))
615 {
616 ret = 1;
617 goto free;
618 }
Channagoud Kadabicfeee4d2013-07-26 12:02:49 -0700619
620 while (phase < MAX_PHASES)
621 {
622 struct mmc_command cmd = {0};
623
624 /* configure dll to set phase delay */
Channagoud Kadabifd96a0b2014-03-31 15:26:00 -0700625 if (sdhci_msm_config_dll(host, phase))
626 {
627 ret = 1;
628 goto free;
629 }
Channagoud Kadabicfeee4d2013-07-26 12:02:49 -0700630
631 cmd.cmd_index = CMD21_SEND_TUNING_BLOCK;
632 cmd.argument = 0x0;
633 cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL;
634 cmd.resp_type = SDHCI_CMD_RESP_R1;
635 cmd.trans_mode = SDHCI_MMC_READ;
636 cmd.data_present = 0x1;
637 cmd.data.data_ptr = tuning_data;
638 cmd.data.blk_sz = size;
639 cmd.data.num_blocks = 0x1;
640
641 /* send command */
642 if (!sdhci_send_command(host, &cmd) && !memcmp(tuning_data, tuning_block, size))
643 tuned_phases[tuned_phase_cnt++] = phase;
644
645 phase++;
646 }
647
648 /* Find the appropriate tuned phase */
649 if (tuned_phase_cnt)
650 {
Channagoud Kadabifd96a0b2014-03-31 15:26:00 -0700651 DBG("\n Tuned phase\n");
652 for (i = 0 ; i < tuned_phase_cnt ; i++)
653 {
654 DBG("%d\t", tuned_phases[i]);
655 }
656
Channagoud Kadabicfeee4d2013-07-26 12:02:49 -0700657 ret = sdhci_msm_find_appropriate_phase(host, tuned_phases, tuned_phase_cnt);
658
659 if (ret < 0)
660 {
661 dprintf(CRITICAL, "Failed in selecting the tuning phase\n");
662 ret = 1;
663 goto free;
664 }
665
666 phase = (uint32_t) ret;
667 ret = 0;
668
Channagoud Kadabifd96a0b2014-03-31 15:26:00 -0700669 DBG("\n: %s: Tuned Phase: 0x%08x\n", __func__, phase);
670
671 if (sdhci_msm_config_dll(host, phase))
672 goto free;
Channagoud Kadabicfeee4d2013-07-26 12:02:49 -0700673
674 /* Save the tuned phase */
675 host->msm_host->saved_phase = phase;
676 }
677 else
678 {
679 dprintf(CRITICAL, "Failed to get tuned phase\n");
680 ret = 1;
681 }
682
683free:
684 free(tuning_data);
685out:
686 /* Tuning done */
687 host->tuning_in_progress = false;
688 host->msm_host->tuning_done = true;
689 return ret;
Channagoud Kadabiafb8e172013-05-23 13:55:47 -0700690}
Channagoud Kadabid2137a62014-01-24 17:22:08 -0800691
692/*
693 * API to disable HC mode
694 */
695void sdhci_mode_disable(struct sdhci_host *host)
696{
697 /* Disable HC mode */
698 RMWREG32((host->msm_host->pwrctl_base + SDCC_MCI_HC_MODE), SDHCI_HC_START_BIT, SDHCI_HC_WIDTH, 0);
699}
700