blob: 3f6d4603d43d26f24202def554aa08dcf3ae0ae2 [file] [log] [blame]
Mayank Grover0d3b2c72017-01-23 17:44:00 +05301/* Copyright (c) 2013-2017, 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 Kadabi9b8f8fc2013-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 Kadabi9b8f8fc2013-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 Kadabie106d1f2014-04-25 18:26:26 -070043
44#define MX_DRV_SUPPORTED_HS200 3
Channagoud Kadabi0b028662015-03-17 11:54:57 -070045static bool attempt_cdr_unlock;
Channagoud Kadabie106d1f2014-04-25 18:26:26 -070046
Channagoud Kadabi9b8f8fc2013-07-26 12:02:49 -070047/* Known data stored in the card & read during tuning
48 * process. 64 bytes for 4bit bus width & 128 bytes
49 * of data for 8 bit bus width.
50 * These values are derived from HPG
51 */
52static const uint32_t tuning_block_64[] = {
53 0x00FF0FFF, 0xCCC3CCFF, 0xFFCC3CC3, 0xEFFEFFFE,
54 0xDDFFDFFF, 0xFBFFFBFF, 0xFF7FFFBF, 0xEFBDF777,
55 0xF0FFF0FF, 0x3CCCFC0F, 0xCFCC33CC, 0xEEFFEFFF,
56 0xFDFFFDFF, 0xFFBFFFDF, 0xFFF7FFBB, 0xDE7B7FF7
57};
58
59static const uint32_t tuning_block_128[] = {
60 0xFF00FFFF, 0x0000FFFF, 0xCCCCFFFF, 0xCCCC33CC,
61 0xCC3333CC, 0xFFFFCCCC, 0xFFFFEEFF, 0xFFEEEEFF,
62 0xFFDDFFFF, 0xDDDDFFFF, 0xBBFFFFFF, 0xBBFFFFFF,
63 0xFFFFFFBB, 0xFFFFFF77, 0x77FF7777, 0xFFEEDDBB,
64 0x00FFFFFF, 0x00FFFFFF, 0xCCFFFF00, 0xCC33CCCC,
65 0x3333CCCC, 0xFFCCCCCC, 0xFFEEFFFF, 0xEEEEFFFF,
66 0xDDFFFFFF, 0xDDFFFFFF, 0xFFFFFFDD, 0xFFFFFFBB,
67 0xFFFFBBBB, 0xFFFF77FF, 0xFF7777FF, 0xEEDDBB77
68};
Channagoud Kadabiafb8e172013-05-23 13:55:47 -070069
70/*
71 * Function: sdhci int handler
72 * Arg : MSM specific data for sdhci
73 * Return : 0
74 * Flow: : 1. Read the power control mask register
75 * 2. Check if bus is ON
76 * 3. Write success to ack regiser
77 * Details : This is power control interrupt handler.
78 * Once we receive the interrupt, we will ack the power control
79 * register that we have successfully completed pmic transactions
80 */
81static enum handler_return sdhci_int_handler(struct sdhci_msm_data *data)
82{
83 uint32_t ack;
84 uint32_t status;
85
86 /*
87 * Read the mask register to check if BUS & IO level
88 * interrupts are enabled
89 */
90 status = readl(data->pwrctl_base + SDCC_HC_PWRCTL_MASK_REG);
91
92 if (status & (SDCC_HC_BUS_ON | SDCC_HC_BUS_OFF))
93 ack = SDCC_HC_BUS_ON_OFF_SUCC;
94 if (status & (SDCC_HC_IO_SIG_LOW | SDCC_HC_IO_SIG_HIGH))
95 ack |= SDCC_HC_IO_SIG_SUCC;
96
97 /* Write success to power control register */
98 writel(ack, (data->pwrctl_base + SDCC_HC_PWRCTL_CTL_REG));
99
100 event_signal(data->sdhc_event, false);
101
102 return 0;
103}
104
105/*
106 * Function: sdhci clear pending interrupts
107 * Arg : MSM specific data for sdhci
108 * Return : None
109 * Flow: : Clear pending interrupts
110 */
111static void sdhci_clear_power_ctrl_irq(struct sdhci_msm_data *data)
112{
113 uint32_t irq_ctl;
114 uint32_t irq_stat;
115
116 /*
117 * Read the power control status register to know
118 * the status of BUS & IO_HIGH_V
119 */
120 irq_stat = readl(data->pwrctl_base + SDCC_HC_PWRCTL_STATUS_REG);
121
122 /* Clear the power control status */
123 writel(irq_stat, (data->pwrctl_base + SDCC_HC_PWRCTL_CLEAR_REG));
124
125 /*
126 * Handle the pending irq by ack'ing the bus & IO switch
127 */
128 irq_ctl = readl(data->pwrctl_base + SDCC_HC_PWRCTL_CTL_REG);
129
130 if (irq_stat & (SDCC_HC_BUS_ON | SDCC_HC_BUS_OFF))
131 irq_ctl |= SDCC_HC_BUS_ON_OFF_SUCC;
132 if (irq_stat & (SDCC_HC_IO_SIG_LOW | SDCC_HC_IO_SIG_HIGH))
133 irq_ctl |= SDCC_HC_IO_SIG_SUCC;
134
135 writel(irq_ctl, (data->pwrctl_base + SDCC_HC_PWRCTL_CTL_REG));
136}
137
138/*
139 * Function: sdhci msm init
140 * Arg : MSM specific config data for sdhci
141 * Return : None
142 * Flow: : Enable sdhci mode & do msm specific init
143 */
Channagoud Kadabi9b8f8fc2013-07-26 12:02:49 -0700144void sdhci_msm_init(struct sdhci_host *host, struct sdhci_msm_data *config)
Channagoud Kadabiafb8e172013-05-23 13:55:47 -0700145{
Channagoud Kadabi17e69972014-10-13 11:42:24 -0700146 uint32_t io_switch;
Channagoud Kadabi0e657d02014-11-06 18:08:57 -0800147 uint32_t caps = 0;
148 uint32_t version;
Channagoud Kadabi17e69972014-10-13 11:42:24 -0700149
Channagoud Kadabi050d99d2015-06-26 15:07:06 -0700150 REG_WRITE32(host, 0xA1C, SDCC_VENDOR_SPECIFIC_FUNC);
Channagoud Kadabid10f6182013-12-30 11:51:53 -0800151
Channagoud Kadabiafb8e172013-05-23 13:55:47 -0700152 /* Enable sdhc mode */
Channagoud Kadabi946848d2013-10-02 12:09:37 -0700153 RMWREG32((config->pwrctl_base + SDCC_MCI_HC_MODE), SDHCI_HC_START_BIT, SDHCI_HC_WIDTH, SDHCI_HC_MODE_EN);
Channagoud Kadabiafb8e172013-05-23 13:55:47 -0700154
Channagoud Kadabie632e252014-03-31 15:26:00 -0700155 /* Set the FF_CLK_SW_RST_DIS to 1 */
156 RMWREG32((config->pwrctl_base + SDCC_MCI_HC_MODE), FF_CLK_SW_RST_DIS_START, FF_CLK_SW_RST_DIS_WIDTH, 1);
157
Channagoud Kadabiafb8e172013-05-23 13:55:47 -0700158 /*
Channagoud Kadabi9b8f8fc2013-07-26 12:02:49 -0700159 * Reset the controller
160 */
161 sdhci_reset(host, SDHCI_SOFT_RESET);
162
163 /*
Channagoud Kadabi17e69972014-10-13 11:42:24 -0700164 * Some platforms have same SDC instance shared between emmc & sd card.
165 * For such platforms the emmc IO voltage has to be switched from 3.3 to
166 * 1.8 for the contoller to work with emmc.
167 */
168
169 if(config->use_io_switch)
170 {
171 io_switch = REG_READ32(host, SDCC_VENDOR_SPECIFIC_FUNC);
172 io_switch |= HC_IO_PAD_PWR_SWITCH | HC_IO_PAD_PWR_SWITCH_EN;
173 REG_WRITE32(host, io_switch, SDCC_VENDOR_SPECIFIC_FUNC);
174 }
175
176 /*
Channagoud Kadabiafb8e172013-05-23 13:55:47 -0700177 * CORE_SW_RST may trigger power irq if previous status of PWRCTL
178 * was either BUS_ON or IO_HIGH. So before we enable the power irq
179 * interrupt in GIC (by registering the interrupt handler), we need to
180 * ensure that any pending power irq interrupt status is acknowledged
181 * otherwise power irq interrupt handler would be fired prematurely.
182 */
183 sdhci_clear_power_ctrl_irq(config);
184
185 /*
186 * Register the interrupt handler for pwr irq
187 */
vijay kumar4f4405f2014-08-08 11:49:53 +0530188 register_int_handler(config->pwr_irq, (int_handler)sdhci_int_handler, (void *)config);
Channagoud Kadabiafb8e172013-05-23 13:55:47 -0700189
190 unmask_interrupt(config->pwr_irq);
191
192 /* Enable pwr control interrupt */
193 writel(SDCC_HC_PWR_CTRL_INT, (config->pwrctl_base + SDCC_HC_PWRCTL_MASK_REG));
Channagoud Kadabi9b8f8fc2013-07-26 12:02:49 -0700194
Channagoud Kadabi0e657d02014-11-06 18:08:57 -0800195 version = readl(host->msm_host->pwrctl_base + MCI_VERSION);
196
197 host->major = (version & CORE_VERSION_MAJOR_MASK) >> CORE_VERSION_MAJOR_SHIFT;
198 host->minor = (version & CORE_VERSION_MINOR_MASK);
199
200 /*
201 * For SDCC5 the capabilities registers does not have voltage advertised
202 * Override the values using SDCC_HC_VENDOR_SPECIFIC_CAPABILITIES0
203 */
204 if (host->major >= 1 && host->minor != 0x11 && host->minor != 0x12)
205 {
206 caps = REG_READ32(host, SDHCI_CAPS_REG1);
207
208 if (config->slot == 0x1)
209 REG_WRITE32(host, (caps | SDHCI_1_8_VOL_MASK), SDCC_HC_VENDOR_SPECIFIC_CAPABILITIES0);
210 else
211 REG_WRITE32(host, (caps | SDHCI_3_0_VOL_MASK), SDCC_HC_VENDOR_SPECIFIC_CAPABILITIES0);
212 }
213
Channagoud Kadabi9b8f8fc2013-07-26 12:02:49 -0700214 config->tuning_done = false;
215 config->calibration_done = false;
216 host->tuning_in_progress = false;
217}
218
219/*
220 * Function: sdhci msm set mci clk
221 * Arg : Host structure
222 * Return : None
223 * Flow: : Set HC_SELECT & HC_SELECT_EN for hs400
224 */
225void sdhci_msm_set_mci_clk(struct sdhci_host *host)
226{
227 struct sdhci_msm_data *msm_host;
228
229 msm_host = host->msm_host;
230
231 if (host->timing == MMC_HS400_TIMING)
232 {
233 /*
234 * If the current tuning mode is HS400 then we should set the MCLK to run
235 * the clock @ MCLK/2. Also set HS400 mode in SELECT_IN of vendor specific
236 * register
237 */
238 REG_RMW32(host, SDCC_VENDOR_SPECIFIC_FUNC, SDCC_HC_MCLK_HS400_START, SDCC_HC_MCLK_HS400_WIDTH, SDCC_HC_MCLK_SEL_HS400);
239
240 /* Enable HS400 mode from HC_SELECT_IN bit of VENDOR_SPEC register
241 * As the SDCC spec does not have matching mode for HS400
242 */
243 if (msm_host->tuning_done && !msm_host->calibration_done)
244 {
245 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);
246 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);
247 }
248 }
249 else
250 {
251 /*
252 * Set 0x0 mode in SELECT_IN of vendor specific register so that the
253 * host control2 register settings from sdhc spec are used for
254 * speed mode
255 */
256 REG_RMW32(host, SDCC_VENDOR_SPECIFIC_FUNC, SDCC_HC_MCLK_SEL_IN_START, SDCC_HC_MCLK_SEL_IN_WIDTH, 0x0);
257 REG_RMW32(host, SDCC_VENDOR_SPECIFIC_FUNC, SDCC_HC_MCLK_SEL_IN_EN_START, SDCC_HC_MCLK_SEL_IN_EN_WIDTH, 0x0);
258 }
259}
260
261/*
262 * Set the value based on sdcc clock frequency
263 */
264static void msm_set_dll_freq(struct sdhci_host *host)
265{
266 uint32_t reg_val = 0;
267
268 /* Set clock freq value based on clock range */
269 if (host->cur_clk_rate <= 112000000)
270 reg_val = 0x0;
271 else if (host->cur_clk_rate <= 125000000)
272 reg_val = 0x1;
273 else if (host->cur_clk_rate <= 137000000)
274 reg_val = 0x2;
275 else if (host->cur_clk_rate <= 150000000)
276 reg_val = 0x3;
277 else if (host->cur_clk_rate <= 162000000)
278 reg_val = 0x4;
279 else if (host->cur_clk_rate <= 175000000)
280 reg_val = 0x5;
281 else if (host->cur_clk_rate <= 187000000)
282 reg_val = 0x6;
283 else if (host->cur_clk_rate <= 200000000)
284 reg_val = 0x7;
285
Channagoud Kadabie632e252014-03-31 15:26:00 -0700286 DBG("\n %s: DLL freq: 0x%08x\n", __func__, reg_val);
287
Channagoud Kadabi9b8f8fc2013-07-26 12:02:49 -0700288 REG_RMW32(host, SDCC_DLL_CONFIG_REG, SDCC_DLL_CONFIG_MCLK_START, SDCC_DLL_CONFIG_MCLK_WIDTH, reg_val);
289}
290
Channagoud Kadabid3178012015-02-03 13:22:59 -0800291static void sdhci_dll_clk_enable(struct sdhci_host *host, int enable)
292{
293 if (enable)
294 {
295 REG_WRITE32(host, (REG_READ32(host, SDCC_HC_REG_DLL_CONFIG_2) & ~SDCC_DLL_CLOCK_DISABLE), SDCC_HC_REG_DLL_CONFIG_2);
296 }
297 else
298 {
299 REG_WRITE32(host, (REG_READ32(host, SDCC_DLL_CONFIG_REG) & ~SDCC_DLL_CLK_OUT_EN), SDCC_DLL_CONFIG_REG);
300 REG_WRITE32(host, (REG_READ32(host, SDCC_HC_REG_DLL_CONFIG_2) | SDCC_DLL_CLOCK_DISABLE), SDCC_HC_REG_DLL_CONFIG_2);
301 }
302}
303
Channagoud Kadabi9b8f8fc2013-07-26 12:02:49 -0700304/* Initialize DLL (Programmable Delay Line) */
Channagoud Kadabie632e252014-03-31 15:26:00 -0700305static uint32_t sdhci_msm_init_dll(struct sdhci_host *host)
Channagoud Kadabi9b8f8fc2013-07-26 12:02:49 -0700306{
307 uint32_t pwr_save = 0;
Channagoud Kadabie632e252014-03-31 15:26:00 -0700308 uint32_t timeout = SDHCI_DLL_TIMEOUT;
Channagoud Kadabid3178012015-02-03 13:22:59 -0800309 uint32_t dll_cfg2;
310 uint32_t mclk_clk_freq = 0;
Channagoud Kadabi9b8f8fc2013-07-26 12:02:49 -0700311
312 pwr_save = REG_READ32(host, SDCC_VENDOR_SPECIFIC_FUNC) & SDCC_DLL_PWR_SAVE_EN;
313
Channagoud Kadabid3178012015-02-03 13:22:59 -0800314 /* Dll sequence needs additional steps for sdcc core version 42 */
315 if (host->major == 1 && host->minor >= 0x42)
316 {
317 /* Disable DLL clock before configuring */
318 sdhci_dll_clk_enable(host, 0);
319 }
320
Channagoud Kadabi9b8f8fc2013-07-26 12:02:49 -0700321 /* PWR SAVE to 0 */
322 if (pwr_save)
323 REG_WRITE32(host, (REG_READ32(host, SDCC_VENDOR_SPECIFIC_FUNC) & ~SDCC_DLL_PWR_SAVE_EN), SDCC_VENDOR_SPECIFIC_FUNC);
324 /* Set DLL_RST to 1 */
325 REG_WRITE32(host, (REG_READ32(host, SDCC_DLL_CONFIG_REG) | SDCC_DLL_RESET_EN), SDCC_DLL_CONFIG_REG);
326 /* Set DLL_PDN to 1 */
327 REG_WRITE32(host, (REG_READ32(host, SDCC_DLL_CONFIG_REG) | SDCC_DLL_PDN_EN), SDCC_DLL_CONFIG_REG);
328
329 /* Set frequency field in DLL_CONFIG */
330 msm_set_dll_freq(host);
331
Channagoud Kadabid3178012015-02-03 13:22:59 -0800332 /* Configure the mclk freq based on the current clock rate
Channagoud Kadabib7fc8dc2015-03-26 13:37:00 -0700333 * and fll cycle count
Channagoud Kadabid3178012015-02-03 13:22:59 -0800334 */
335 if (host->major == 1 && host->minor >= 0x42)
336 {
337 dll_cfg2 = REG_READ32(host, SDCC_HC_REG_DLL_CONFIG_2);
338 if (dll_cfg2 & SDCC_FLL_CYCLE_CNT)
339 mclk_clk_freq = (host->cur_clk_rate / TCXO_FREQ) * 8;
340 else
341 mclk_clk_freq = (host->cur_clk_rate / TCXO_FREQ) * 4;
342
343 REG_WRITE32(host, ((REG_READ32(host, SDCC_HC_REG_DLL_CONFIG_2) & ~(0xFF << 10)) | (mclk_clk_freq << 10)), SDCC_HC_REG_DLL_CONFIG_2);
344
345 udelay(5);
346 }
347
Channagoud Kadabi9b8f8fc2013-07-26 12:02:49 -0700348 /* Write 0 to DLL_RST */
349 REG_WRITE32(host, (REG_READ32(host, SDCC_DLL_CONFIG_REG) & ~SDCC_DLL_RESET_EN), SDCC_DLL_CONFIG_REG);
350 /* Write 0 to DLL_PDN */
351 REG_WRITE32(host, (REG_READ32(host, SDCC_DLL_CONFIG_REG) & ~SDCC_DLL_PDN_EN), SDCC_DLL_CONFIG_REG);
Channagoud Kadabid3178012015-02-03 13:22:59 -0800352
353 /* Set the mclk clock and enable the dll clock */
354 if (host->major == 1 && host->minor >= 0x42)
355 {
356 msm_set_dll_freq(host);
357 sdhci_dll_clk_enable(host, 1);
358 }
Channagoud Kadabi9b8f8fc2013-07-26 12:02:49 -0700359 /* Write 1 to DLL_EN */
360 REG_WRITE32(host, (REG_READ32(host, SDCC_DLL_CONFIG_REG) | SDCC_DLL_EN), SDCC_DLL_CONFIG_REG);
361 /* Write 1 to CLK_OUT_EN */
362 REG_WRITE32(host, (REG_READ32(host, SDCC_DLL_CONFIG_REG) | SDCC_DLL_CLK_OUT_EN), SDCC_DLL_CONFIG_REG);
Channagoud Kadabie632e252014-03-31 15:26:00 -0700363 /* Wait for DLL_LOCK in DLL_STATUS register, wait time 50us */
Channagoud Kadabi96622212014-07-30 12:13:28 -0700364 while(!((REG_READ32(host, SDCC_REG_DLL_STATUS)) & SDCC_DLL_LOCK_STAT))
Channagoud Kadabie632e252014-03-31 15:26:00 -0700365 {
366 udelay(1);
367 timeout--;
368 if (!timeout)
369 {
370 dprintf(CRITICAL, "%s: Failed to get DLL lock: 0x%08x\n", __func__, REG_READ32(host, SDCC_REG_DLL_STATUS));
371 return 1;
372 }
373 }
374
Channagoud Kadabi9b8f8fc2013-07-26 12:02:49 -0700375 /* Set the powersave back on */
376 if (pwr_save)
Channagoud Kadabi7bcf6252014-05-14 18:28:13 -0700377 REG_WRITE32(host, (REG_READ32(host, SDCC_VENDOR_SPECIFIC_FUNC) | SDCC_DLL_PWR_SAVE_EN), SDCC_VENDOR_SPECIFIC_FUNC);
Channagoud Kadabie632e252014-03-31 15:26:00 -0700378
379 return 0;
Channagoud Kadabi9b8f8fc2013-07-26 12:02:49 -0700380}
381
Channagoud Kadabidd8a7342014-07-09 10:35:01 -0700382void sdhci_msm_toggle_cdr(struct sdhci_host *host, bool enable)
383{
384 uint32_t core_cfg;
385
386 core_cfg = REG_READ32(host, SDCC_DLL_CONFIG_REG);
387
388 if (enable)
389 {
390 core_cfg |= SDCC_DLL_CDR_EN;
Parth Dixitb27f0f52016-02-19 17:01:15 +0530391 core_cfg &= ~SDCC_DLL_CDR_EXT_EN;
Channagoud Kadabidd8a7342014-07-09 10:35:01 -0700392 }
393 else
394 {
395 core_cfg &= ~SDCC_DLL_CDR_EN;
Parth Dixitb27f0f52016-02-19 17:01:15 +0530396 core_cfg |= SDCC_DLL_CDR_EXT_EN;
Channagoud Kadabidd8a7342014-07-09 10:35:01 -0700397 }
398
399 REG_WRITE32(host, core_cfg, SDCC_DLL_CONFIG_REG);
400}
401
Channagoud Kadabi9b8f8fc2013-07-26 12:02:49 -0700402/* Configure DLL with delay value based on 'phase' */
Channagoud Kadabie632e252014-03-31 15:26:00 -0700403static uint32_t sdhci_msm_config_dll(struct sdhci_host *host, uint32_t phase)
Channagoud Kadabi9b8f8fc2013-07-26 12:02:49 -0700404{
405 uint32_t core_cfg = 0;
Channagoud Kadabie632e252014-03-31 15:26:00 -0700406 uint32_t timeout = SDHCI_DLL_TIMEOUT;
407
Channagoud Kadabi9b8f8fc2013-07-26 12:02:49 -0700408 /* Gray code values from SWI */
409 uint32_t gray_code [] = { 0x0, 0x1, 0x3, 0x2, 0x6, 0x7, 0x5, 0x4, 0xC, 0xD, 0xF, 0xE, 0xA, 0xB, 0x9, 0x8 };
410
411 /* set CDR_EN & CLK_OUT_EN to 0 and
412 * CDR_EXT_EN & DLL_EN to 1*/
413 core_cfg = REG_READ32(host, SDCC_DLL_CONFIG_REG);
414 core_cfg &= ~(SDCC_DLL_CDR_EN | SDCC_DLL_CLK_OUT_EN);
415 core_cfg |= (SDCC_DLL_CDR_EXT_EN | SDCC_DLL_EN);
416 REG_WRITE32(host, core_cfg, SDCC_DLL_CONFIG_REG);
417
418 /* Wait until CLK_OUT_EN is 0 */
419 while(REG_READ32(host, SDCC_DLL_CONFIG_REG) & SDCC_DLL_CLK_OUT_EN);
420
421 REG_RMW32(host, SDCC_DLL_CONFIG_REG, SDCC_DLL_GRAY_CODE_START, SDCC_DLL_GRAY_CODE_WIDTH, gray_code[phase]);
422
423 REG_WRITE32(host, (REG_READ32(host, SDCC_DLL_CONFIG_REG) | SDCC_DLL_CLK_OUT_EN), SDCC_DLL_CONFIG_REG);
424
Channagoud Kadabie632e252014-03-31 15:26:00 -0700425 /* Wait until CLK_OUT_EN is 1, wait time 50us */
426 while(!(REG_READ32(host, SDCC_DLL_CONFIG_REG) & SDCC_DLL_CLK_OUT_EN))
427 {
428 timeout--;
429 udelay(1);
430 if (!timeout)
431 {
432 dprintf(CRITICAL, "%s: clk_out_en timed out: %08x\n", __func__, REG_READ32(host, SDCC_DLL_CONFIG_REG));
433 return 1;
434 }
435 }
Channagoud Kadabi9b8f8fc2013-07-26 12:02:49 -0700436
437 core_cfg = REG_READ32(host, SDCC_DLL_CONFIG_REG);
438
439 core_cfg |= SDCC_DLL_CDR_EN;
440 core_cfg &= ~SDCC_DLL_CDR_EXT_EN;
441
442 REG_WRITE32(host, core_cfg, SDCC_DLL_CONFIG_REG);
443
Channagoud Kadabie632e252014-03-31 15:26:00 -0700444 return 0;
Channagoud Kadabi9b8f8fc2013-07-26 12:02:49 -0700445}
446
447/*
448 * Find the right tuning delay, this function finds the largest
449 * consecutive sequence of phases & then selects the 3/4 th of
450 * the range which has max entries
451 * For eg: If we get the following sequence in phase_table[]
452 * (A) phase_table[] = 0x1, 0x2, 0x3, 0x4 , 0x5
453 * (B) phase_table[] = 0xA, 0xB, 0xC
454 * In the above case the (A) has maximum consecutive entries with '5' entries
455 * So delay would be phase_table[(0x5 * 3) / 4] = 0x3
456 */
457static int sdhci_msm_find_appropriate_phase(struct sdhci_host *host,
458 uint32_t *phase_table,
459 uint32_t total_phases)
460{
461 int sub_phases[MAX_PHASES][MAX_PHASES]={{0}};
vijay kumar4f4405f2014-08-08 11:49:53 +0530462 uint32_t phases_per_row[MAX_PHASES] = {0};
Channagoud Kadabi9b8f8fc2013-07-26 12:02:49 -0700463 uint32_t i,j;
464 int selected_phase = 0;
465 uint32_t row_index = 0;
466 uint32_t col_index = 0;
467 uint32_t phase_15_row_idx = 0;
468 uint32_t phases_0_row_idx = 0;
469 uint32_t max_phases_3_4_idx = 0;
470 uint32_t max_phases = 0;
471 uint32_t max_phases_row = 0;
472 bool found_loop = false;
473
474 if (!phase_table[0] && phase_table[total_phases - 1] == (MAX_PHASES - 1))
475 found_loop = true;
476
477 for (i = 0; i < total_phases; i++)
478 {
479 /* Break the phase table entries into different sub arrays based
480 * on the consecutive entries. Each row will have one sub array
481 * of consecutive entries.
482 * for eg: phase_table [] = { 0x0, 0x1, 0x2, 0xA, 0xB}
483 * sub_phases [0][] = { 0x0, 0x1, 0x2}
484 * sub_phases [1][] = { 0xA, 0xB}
485 */
486 sub_phases[row_index][col_index] = phase_table[i];
487 phases_per_row[row_index]++;
488 col_index++;
489
490 /* If we are at the last phase no need to check further */
491 if ((i + 1) == total_phases)
492 break;
493
494 /* If phase_table does not have consecutive entries, move to next entry */
495 if (phase_table[i]+1 != phase_table[i+1])
496 {
497 row_index++;
498 col_index = 0;
499 }
500 }
501
502 if (found_loop && total_phases < MAX_PHASES)
503 {
504 /* For consecutive entries we need to consider loops.
505 * If the phase_table contains 0x0 & 0xF then we have
506 * a loop, the number after 0xF in the sequence would be
507 * 0x0.
508 * for eg:
509 * phase_table = { 0x0, 0x1, 0x2, 0xD, 0xE, 0xF }
510 * then
511 * sub_phase [0][] = { 0x0, 0x1, 0x2 }
512 * sub_phase [1][] = { 0xD, 0xE, 0xF }
513 * Since we have a loop here, we need to merge the sub arrays as:
514 * sub_phase [1][] = { 0xD, 0xE, 0xF, 0x0, 0x1, 0x2 }
515 */
516
517 /* The entry 0xF will always be in the last row
518 * and entry 0x0 will always be in the first row
519 */
520 phase_15_row_idx = row_index;
521 j = 0;
522 for (i = phases_per_row[phase_15_row_idx] ; i < MAX_PHASES ; i++)
523 {
524 sub_phases[phase_15_row_idx][i] = sub_phases[phases_0_row_idx][j];
525 if (++j >= phases_per_row[phases_0_row_idx])
526 break;
527 }
528
529 /* Update the number of entries for the sub_phase after the merger */
530 phases_per_row[phase_15_row_idx] = phases_per_row[phase_15_row_idx] + phases_per_row[phases_0_row_idx];
531 phases_per_row[phases_0_row_idx] = 0;
532 }
533
534 for (i = 0 ; i <= row_index; i++)
535 {
536 if (phases_per_row[i] > max_phases)
537 {
538 max_phases = phases_per_row[i];
539 max_phases_row = i;
540 }
541 }
542
543 max_phases_3_4_idx = (max_phases * 3) / 4;
544 if (max_phases_3_4_idx)
545 max_phases_3_4_idx--;
546
547 selected_phase = sub_phases[max_phases_row][max_phases_3_4_idx];
548
549 return selected_phase;
550}
551
Channagoud Kadabi756e1e32014-06-05 13:00:55 -0700552static uint32_t sdhci_msm_cm_dll_sdc4_calibration(struct sdhci_host *host)
553{
554 uint32_t timeout = 0;
555
556 DBG("\n CM_DLL_SDC4 Calibration Start\n");
557
Channagoud Kadabi355f1fa2014-10-08 19:57:00 -0700558 /*1.Write the DDR config value to SDCC_HC_REG_DDR_CONFIG register*/
Parth Dixitff1928a2016-11-16 19:57:21 +0530559 REG_WRITE32(host, target_ddr_cfg_val(), target_ddr_cfg_reg());
Channagoud Kadabi756e1e32014-06-05 13:00:55 -0700560
561 /*2. Write DDR_CAL_EN to '1' */
562 REG_WRITE32(host, (REG_READ32(host, SDCC_HC_REG_DLL_CONFIG_2) | DDR_CAL_EN), SDCC_HC_REG_DLL_CONFIG_2);
563
564 /*3. Wait for DLL_LOCK for hs400 to be set */
565 timeout = DDR_CAL_TIMEOUT_MAX;
566 while (!(REG_READ32(host, SDCC_REG_DLL_STATUS) & DDR_DLL_LOCK_JDR))
567 {
568 timeout--;
569 mdelay(1);
570 if (!timeout)
571 {
572 dprintf(CRITICAL, "Error: DLL lock for hs400 operation is not set\n");
573 return 1;
574 }
575 }
576
577 /*4. Set powersave dll */
578 REG_WRITE32(host, (REG_READ32(host, SDCC_HC_VENDOR_SPECIFIC_FUNC3) | PWRSAVE_DLL), SDCC_HC_VENDOR_SPECIFIC_FUNC3);
579
580 DBG("\n CM_DLL_SDC4 Calibration Done\n");
581
582 return 0;
583}
584
Channagoud Kadabi9b8f8fc2013-07-26 12:02:49 -0700585static uint32_t sdhci_msm_cdclp533_calibration(struct sdhci_host *host)
586{
587 uint32_t timeout;
588 uint32_t cdc_err;
589
Channagoud Kadabie632e252014-03-31 15:26:00 -0700590 DBG("\n CDCLP533 Calibration Start\n");
591
Channagoud Kadabi9b8f8fc2013-07-26 12:02:49 -0700592 /* Write 0 to CDC_T4_DLY_SEL field in VENDOR_SPEC_DDR200_CFG */
593 REG_WRITE32(host, (REG_READ32(host, SDCC_CDC_DDR200_CFG) & ~CDC_T4_DLY_SEL), SDCC_CDC_DDR200_CFG);
594
595 /* Write 0 to START_CDC_TRAFFIC field in CORE_DDR200_CFG */
596 REG_WRITE32(host, (REG_READ32(host, SDCC_CDC_DDR200_CFG) & ~START_CDC_TRAFFIC), SDCC_CDC_DDR200_CFG);
597
598 /* Write 0 to CDC_SWITCH_BYPASS_OFF field in CSR_CDC_GEN_CFG */
599 REG_WRITE32(host, (REG_READ32(host, SDCC_VENDOR_SPEC_CSR_CDC_CFG) & ~CDC_SWITCH_BYPASS_OFF), SDCC_VENDOR_SPEC_CSR_CDC_CFG);
600
601 /* Write 1 to CDC_SWITCH_RC_EN field in CSR_CDC_GEN_CFG */
602 REG_WRITE32(host, (REG_READ32(host, SDCC_VENDOR_SPEC_CSR_CDC_CFG) | CDC_SWITCH_RC_EN), SDCC_VENDOR_SPEC_CSR_CDC_CFG);
603
604 /* Write 0 to START_CDC_TRAFFIC field in CORE_DDR200_CFG */
605 REG_WRITE32(host, (REG_READ32(host, SDCC_CDC_DDR200_CFG) & ~START_CDC_TRAFFIC), SDCC_CDC_DDR200_CFG);
606
607 /* Perform CDCLP533 initialization sequence
608 * SDCC_CSR_CDC_CTRL_CFG0 --> 0x11800EC
609 * SDCC_CSR_CDC_CTRL_CFG1 --> 0x3011111
610 * SDCC_CSR_CDC_CAL_TIMER_CFG0 --> 0x1201000
611 * SDCC_CSR_CDC_CAL_TIMER_CFG1 --> 0x4
612 * SDCC_CSR_CDC_REFCOUNT_CFG --> 0xCB732020
613 * SDCC_CSR_CDC_COARSE_CAL_CFG --> 0xB19
Channagoud Kadabi86afb382014-06-23 11:15:46 -0700614 * SDCC_CSR_CDC_DELAY_CFG --> 0x4E2
Channagoud Kadabi9b8f8fc2013-07-26 12:02:49 -0700615 * SDCC_CDC_OFFSET_CFG --> 0x0
616 * SDCC_CDC_SLAVE_DDA_CFG --> 0x16334
617 */
618
619 REG_WRITE32(host, 0x11800EC, SDCC_CSR_CDC_CTRL_CFG0);
620 REG_WRITE32(host, 0x3011111, SDCC_CSR_CDC_CTRL_CFG1);
621 REG_WRITE32(host, 0x1201000, SDCC_CSR_CDC_CAL_TIMER_CFG0);
622 REG_WRITE32(host, 0x4, SDCC_CSR_CDC_CAL_TIMER_CFG1);
623 REG_WRITE32(host, 0xCB732020, SDCC_CSR_CDC_REFCOUNT_CFG);
624 REG_WRITE32(host, 0xB19, SDCC_CSR_CDC_COARSE_CAL_CFG);
Channagoud Kadabi86afb382014-06-23 11:15:46 -0700625 REG_WRITE32(host, 0x4E2, SDCC_CSR_CDC_DELAY_CFG);
Channagoud Kadabi9b8f8fc2013-07-26 12:02:49 -0700626 REG_WRITE32(host, 0x0, SDCC_CDC_OFFSET_CFG);
627 REG_WRITE32(host, 0x16334, SDCC_CDC_SLAVE_DDA_CFG);
628
629 /* Write 1 to SW_TRIGGER_FULL_CALIB */
630 REG_WRITE32(host, (REG_READ32(host, SDCC_CSR_CDC_CTRL_CFG0) | CDC_SW_TRIGGER_FULL_CALIB), SDCC_CSR_CDC_CTRL_CFG0);
631
632 /* Write 0 to SW_TRIGGER_FULL_CALIB */
633 REG_WRITE32(host, (REG_READ32(host, SDCC_CSR_CDC_CTRL_CFG0) & ~CDC_SW_TRIGGER_FULL_CALIB), SDCC_CSR_CDC_CTRL_CFG0);
634
635 /* Write 1 to HW_AUTO_CAL_EN */
636 REG_WRITE32(host, (REG_READ32(host, SDCC_CSR_CDC_CTRL_CFG0) | CDC_HW_AUTO_CAL_EN), SDCC_CSR_CDC_CTRL_CFG0);
637
638 /* Write 1 to TIMER_ENA */
639 REG_WRITE32(host, (REG_READ32(host, SDCC_CSR_CDC_CAL_TIMER_CFG0) | CDC_TIMER_EN), SDCC_CSR_CDC_CAL_TIMER_CFG0);
640
641 /* Wait for CALIBRATION_DONE in CDC_STATUS */
Channagoud Kadabie632e252014-03-31 15:26:00 -0700642 timeout = CDC_STATUS_TIMEOUT;
Channagoud Kadabi9b8f8fc2013-07-26 12:02:49 -0700643 while (!(REG_READ32(host, SDCC_CSR_CDC_STATUS0) & BIT(0)))
644 {
645 timeout--;
646 mdelay(1);
647 if (!timeout)
648 {
649 dprintf(CRITICAL, "Error: Calibration done in CDC status not set\n");
650 return 1;
651 }
652 }
653
654 cdc_err = REG_READ32(host, SDCC_CSR_CDC_STATUS0) & CSR_CDC_ERROR_MASK;
655 if (cdc_err)
656 {
657 dprintf(CRITICAL, "CDC error set during calibration: %x\n", cdc_err);
658 return 1;
659 }
660 /* Write 1 to START_CDC_TRAFFIC field in CORE_DDR200_CFG */
661 REG_WRITE32(host, (REG_READ32(host, SDCC_CDC_DDR200_CFG) | START_CDC_TRAFFIC), SDCC_CDC_DDR200_CFG);
662
Channagoud Kadabie632e252014-03-31 15:26:00 -0700663 DBG("\n CDCLP533 Calibration Done\n");
664
Channagoud Kadabi9b8f8fc2013-07-26 12:02:49 -0700665 return 0;
666}
667
Channagoud Kadabi756e1e32014-06-05 13:00:55 -0700668
669static uint32_t sdhci_msm_hs400_calibration(struct sdhci_host *host)
670{
671 DBG("\n HS400 Calibration Start\n");
672
673 /* Reset & Initialize the DLL block */
674 if (sdhci_msm_init_dll(host))
675 return 1;
676
677 /* Write the save phase */
678 if (sdhci_msm_config_dll(host, host->msm_host->saved_phase))
679 return 1;
680
681 /* Write 1 to CMD_DAT_TRACK_SEL field in DLL_CONFIG */
682 REG_WRITE32(host, (REG_READ32(host, SDCC_DLL_CONFIG_REG) | CMD_DAT_TRACK_SEL), SDCC_DLL_CONFIG_REG);
683
684 if (host->use_cdclp533)
685 return sdhci_msm_cdclp533_calibration(host);
686 else
687 return sdhci_msm_cm_dll_sdc4_calibration(host);
688
689 DBG("\n HS400 Calibration Done\n");
690
691 return 0;
692}
693
Channagoud Kadabi9b8f8fc2013-07-26 12:02:49 -0700694/*
695 * Function: sdhci msm execute tuning
696 * Arg : Host structure & bus width
697 * Return : 0 on Success, 1 on Failure
Channagoud Kadabi756e1e32014-06-05 13:00:55 -0700698 * Flow: : Execute Tuning sequence for HS200 and calibration for hs400
Channagoud Kadabi9b8f8fc2013-07-26 12:02:49 -0700699 */
Channagoud Kadabie106d1f2014-04-25 18:26:26 -0700700uint32_t sdhci_msm_execute_tuning(struct sdhci_host *host, struct mmc_card *card, uint32_t bus_width)
Channagoud Kadabi9b8f8fc2013-07-26 12:02:49 -0700701{
702 uint32_t *tuning_block;
703 uint32_t *tuning_data;
vijay kumar4f4405f2014-08-08 11:49:53 +0530704 uint32_t tuned_phases[MAX_PHASES] = {0};
Channagoud Kadabi9b8f8fc2013-07-26 12:02:49 -0700705 uint32_t size;
706 uint32_t phase = 0;
707 uint32_t tuned_phase_cnt = 0;
Channagoud Kadabie106d1f2014-04-25 18:26:26 -0700708 uint8_t drv_type = 0;
709 bool drv_type_changed = false;
Channagoud Kadabi9b8f8fc2013-07-26 12:02:49 -0700710 int ret = 0;
vijay kumar4f4405f2014-08-08 11:49:53 +0530711 uint32_t i;
Parth Dixit6dda8d42015-06-10 22:39:34 +0530712 uint32_t err = 0;
Channagoud Kadabi9b8f8fc2013-07-26 12:02:49 -0700713 struct sdhci_msm_data *msm_host;
714
715 msm_host = host->msm_host;
716
717 /* In Tuning mode */
718 host->tuning_in_progress = true;
719
Channagoud Kadabi9b8f8fc2013-07-26 12:02:49 -0700720 if (bus_width == DATA_BUS_WIDTH_8BIT)
721 {
vijay kumar4f4405f2014-08-08 11:49:53 +0530722 tuning_block = (uint32_t *)tuning_block_128;
Channagoud Kadabi9b8f8fc2013-07-26 12:02:49 -0700723 size = sizeof(tuning_block_128);
724 }
725 else
726 {
vijay kumar4f4405f2014-08-08 11:49:53 +0530727 tuning_block = (uint32_t *)tuning_block_64;
Channagoud Kadabi9b8f8fc2013-07-26 12:02:49 -0700728 size = sizeof(tuning_block_64);
729 }
730
731 tuning_data = (uint32_t *) memalign(CACHE_LINE, ROUNDUP(size, CACHE_LINE));
732
733 ASSERT(tuning_data);
734
Channagoud Kadabi0b028662015-03-17 11:54:57 -0700735 /* Calibration for CDCLP533 needed for HS400 mode */
736 if (msm_host->tuning_done && !msm_host->calibration_done && host->timing == MMC_HS400_TIMING)
737 {
738 ret = sdhci_msm_hs400_calibration(host);
739 if (!ret)
740 msm_host->calibration_done = true;
741 goto out;
742 }
743
Channagoud Kadabi9b8f8fc2013-07-26 12:02:49 -0700744 /* Reset & Initialize the DLL block */
Channagoud Kadabie632e252014-03-31 15:26:00 -0700745 if (sdhci_msm_init_dll(host))
746 {
747 ret = 1;
Channagoud Kadabi0b028662015-03-17 11:54:57 -0700748 goto out;
Channagoud Kadabie632e252014-03-31 15:26:00 -0700749 }
Channagoud Kadabi9b8f8fc2013-07-26 12:02:49 -0700750
Channagoud Kadabie106d1f2014-04-25 18:26:26 -0700751retry_tuning:
752 tuned_phase_cnt = 0;
753 phase = 0;
Channagoud Kadabi0b028662015-03-17 11:54:57 -0700754 struct mmc_command cmd = {0};
Parth Dixit6dda8d42015-06-10 22:39:34 +0530755 struct mmc_command sts_cmd = {0};
756 uint32_t sts_retry;
757 uint32_t sts_err;
Channagoud Kadabie106d1f2014-04-25 18:26:26 -0700758
Channagoud Kadabi9b8f8fc2013-07-26 12:02:49 -0700759 while (phase < MAX_PHASES)
760 {
Channagoud Kadabi9b8f8fc2013-07-26 12:02:49 -0700761 /* configure dll to set phase delay */
Channagoud Kadabie632e252014-03-31 15:26:00 -0700762 if (sdhci_msm_config_dll(host, phase))
763 {
764 ret = 1;
Channagoud Kadabi0b028662015-03-17 11:54:57 -0700765 goto out;
Channagoud Kadabie632e252014-03-31 15:26:00 -0700766 }
Channagoud Kadabi9b8f8fc2013-07-26 12:02:49 -0700767
768 cmd.cmd_index = CMD21_SEND_TUNING_BLOCK;
769 cmd.argument = 0x0;
770 cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL;
771 cmd.resp_type = SDHCI_CMD_RESP_R1;
772 cmd.trans_mode = SDHCI_MMC_READ;
773 cmd.data_present = 0x1;
774 cmd.data.data_ptr = tuning_data;
775 cmd.data.blk_sz = size;
776 cmd.data.num_blocks = 0x1;
777
778 /* send command */
Parth Dixit6dda8d42015-06-10 22:39:34 +0530779 err = sdhci_send_command(host, &cmd);
780 if(err)
781 {
782
Gaurav Nebhwani77e21612016-04-27 15:00:07 +0530783 sts_retry = 50;
Parth Dixit6dda8d42015-06-10 22:39:34 +0530784 sts_cmd.cmd_index = CMD13_SEND_STATUS;
785 sts_cmd.argument = card->rca << 16;
786 sts_cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL;
787 sts_cmd.resp_type = SDHCI_CMD_RESP_R1;
788 while(sts_retry)
789 {
790 sts_err = sdhci_send_command(host, &sts_cmd);
791 DBG(" response is %d err is %d phase is %d\n",sts_cmd.resp[0],sts_err, phase);
792 if( sts_err || (MMC_CARD_STATUS(sts_cmd.resp[0]) != MMC_TRAN_STATE) )
793 {
794 udelay(10);
795 sts_retry--;
796 continue;
797 }
798 break;
799 }
800 }
801
802 if (!err && !memcmp(tuning_data, tuning_block, size))
Channagoud Kadabi9b8f8fc2013-07-26 12:02:49 -0700803 tuned_phases[tuned_phase_cnt++] = phase;
804
805 phase++;
806 }
807
Channagoud Kadabie106d1f2014-04-25 18:26:26 -0700808 /*
809 * Check if all the tuning phases passed */
810 if (tuned_phase_cnt == MAX_PHASES)
811 {
812 /* Change the driver type & rerun tuning */
Channagoud Kadabie4cab762014-07-08 17:26:06 -0700813 while(++drv_type <= MX_DRV_SUPPORTED_HS200)
Channagoud Kadabie106d1f2014-04-25 18:26:26 -0700814 {
Mayank Grover0d3b2c72017-01-23 17:44:00 +0530815 /* Marking driver type changed if we try to change it */
816 if(!drv_type_changed)
817 drv_type_changed = true;
818
Mayank Grover3e66b2b2016-12-07 15:16:29 +0530819 if (mmc_set_drv_type(host, card, drv_type))
Channagoud Kadabie106d1f2014-04-25 18:26:26 -0700820 goto retry_tuning;
Channagoud Kadabie106d1f2014-04-25 18:26:26 -0700821 }
822 }
823
824 /* Restore the driver strength to default value */
825 if (drv_type_changed)
826 mmc_set_drv_type(host, card, 0);
827
Channagoud Kadabia7a8cfa2015-03-05 23:20:41 -0800828 if (tuned_phase_cnt == MAX_PHASES)
Channagoud Kadabi0b028662015-03-17 11:54:57 -0700829 {
830 attempt_cdr_unlock = true;
Channagoud Kadabia7a8cfa2015-03-05 23:20:41 -0800831 dprintf(CRITICAL, "WARNING: All phase passed.The selected phase may not be optimal\n");
Channagoud Kadabi0b028662015-03-17 11:54:57 -0700832 }
Channagoud Kadabia7a8cfa2015-03-05 23:20:41 -0800833
Channagoud Kadabi9b8f8fc2013-07-26 12:02:49 -0700834 /* Find the appropriate tuned phase */
835 if (tuned_phase_cnt)
836 {
Channagoud Kadabie632e252014-03-31 15:26:00 -0700837 DBG("\n Tuned phase\n");
838 for (i = 0 ; i < tuned_phase_cnt ; i++)
839 {
840 DBG("%d\t", tuned_phases[i]);
841 }
842
Channagoud Kadabi9b8f8fc2013-07-26 12:02:49 -0700843 ret = sdhci_msm_find_appropriate_phase(host, tuned_phases, tuned_phase_cnt);
844
845 if (ret < 0)
846 {
847 dprintf(CRITICAL, "Failed in selecting the tuning phase\n");
848 ret = 1;
Channagoud Kadabi0b028662015-03-17 11:54:57 -0700849 goto out;
Channagoud Kadabi9b8f8fc2013-07-26 12:02:49 -0700850 }
851
852 phase = (uint32_t) ret;
853 ret = 0;
854
Channagoud Kadabie632e252014-03-31 15:26:00 -0700855 DBG("\n: %s: Tuned Phase: 0x%08x\n", __func__, phase);
856
857 if (sdhci_msm_config_dll(host, phase))
Channagoud Kadabi0b028662015-03-17 11:54:57 -0700858 goto out;
Channagoud Kadabi9b8f8fc2013-07-26 12:02:49 -0700859
860 /* Save the tuned phase */
861 host->msm_host->saved_phase = phase;
862 }
863 else
864 {
865 dprintf(CRITICAL, "Failed to get tuned phase\n");
866 ret = 1;
867 }
868
Channagoud Kadabi9b8f8fc2013-07-26 12:02:49 -0700869out:
Channagoud Kadabi0b028662015-03-17 11:54:57 -0700870 /* If all the tuning phases passed, send CMD21 after enabling
871 * CDR to make sure right tuning phase is selected by CDR
872 */
873 if (attempt_cdr_unlock)
874 {
875 cmd.cmd_index = CMD21_SEND_TUNING_BLOCK;
876 cmd.argument = 0x0;
877 cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL;
878 cmd.resp_type = SDHCI_CMD_RESP_R1;
879 cmd.trans_mode = SDHCI_MMC_READ;
880 cmd.data_present = 0x1;
881 cmd.data.data_ptr = tuning_data;
882 cmd.data.blk_sz = size;
883 cmd.data.num_blocks = 0x1;
884
885 /* send command */
886 if (!sdhci_send_command(host, &cmd))
887 {
888 DBG("\n: %s: Sending CMD21 after CDR enable with default phases fail\n", __func__);
889 }
890 }
891
892 free(tuning_data);
Channagoud Kadabi9b8f8fc2013-07-26 12:02:49 -0700893 /* Tuning done */
894 host->tuning_in_progress = false;
895 host->msm_host->tuning_done = true;
896 return ret;
Channagoud Kadabiafb8e172013-05-23 13:55:47 -0700897}
Channagoud Kadabi24146af2014-01-24 17:22:08 -0800898
899/*
900 * API to disable HC mode
901 */
902void sdhci_mode_disable(struct sdhci_host *host)
903{
904 /* Disable HC mode */
905 RMWREG32((host->msm_host->pwrctl_base + SDCC_MCI_HC_MODE), SDHCI_HC_START_BIT, SDHCI_HC_WIDTH, 0);
906}
907