blob: ba638452dba042f9d433f929588917124e7a1699 [file] [log] [blame]
Channagoud Kadabi24146af2014-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 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
45
Channagoud Kadabi9b8f8fc2013-07-26 12:02:49 -070046/* Known data stored in the card & read during tuning
47 * process. 64 bytes for 4bit bus width & 128 bytes
48 * of data for 8 bit bus width.
49 * These values are derived from HPG
50 */
51static const uint32_t tuning_block_64[] = {
52 0x00FF0FFF, 0xCCC3CCFF, 0xFFCC3CC3, 0xEFFEFFFE,
53 0xDDFFDFFF, 0xFBFFFBFF, 0xFF7FFFBF, 0xEFBDF777,
54 0xF0FFF0FF, 0x3CCCFC0F, 0xCFCC33CC, 0xEEFFEFFF,
55 0xFDFFFDFF, 0xFFBFFFDF, 0xFFF7FFBB, 0xDE7B7FF7
56};
57
58static const uint32_t tuning_block_128[] = {
59 0xFF00FFFF, 0x0000FFFF, 0xCCCCFFFF, 0xCCCC33CC,
60 0xCC3333CC, 0xFFFFCCCC, 0xFFFFEEFF, 0xFFEEEEFF,
61 0xFFDDFFFF, 0xDDDDFFFF, 0xBBFFFFFF, 0xBBFFFFFF,
62 0xFFFFFFBB, 0xFFFFFF77, 0x77FF7777, 0xFFEEDDBB,
63 0x00FFFFFF, 0x00FFFFFF, 0xCCFFFF00, 0xCC33CCCC,
64 0x3333CCCC, 0xFFCCCCCC, 0xFFEEFFFF, 0xEEEEFFFF,
65 0xDDFFFFFF, 0xDDFFFFFF, 0xFFFFFFDD, 0xFFFFFFBB,
66 0xFFFFBBBB, 0xFFFF77FF, 0xFF7777FF, 0xEEDDBB77
67};
Channagoud Kadabiafb8e172013-05-23 13:55:47 -070068
69/*
70 * Function: sdhci int handler
71 * Arg : MSM specific data for sdhci
72 * Return : 0
73 * Flow: : 1. Read the power control mask register
74 * 2. Check if bus is ON
75 * 3. Write success to ack regiser
76 * Details : This is power control interrupt handler.
77 * Once we receive the interrupt, we will ack the power control
78 * register that we have successfully completed pmic transactions
79 */
80static enum handler_return sdhci_int_handler(struct sdhci_msm_data *data)
81{
82 uint32_t ack;
83 uint32_t status;
84
85 /*
86 * Read the mask register to check if BUS & IO level
87 * interrupts are enabled
88 */
89 status = readl(data->pwrctl_base + SDCC_HC_PWRCTL_MASK_REG);
90
91 if (status & (SDCC_HC_BUS_ON | SDCC_HC_BUS_OFF))
92 ack = SDCC_HC_BUS_ON_OFF_SUCC;
93 if (status & (SDCC_HC_IO_SIG_LOW | SDCC_HC_IO_SIG_HIGH))
94 ack |= SDCC_HC_IO_SIG_SUCC;
95
96 /* Write success to power control register */
97 writel(ack, (data->pwrctl_base + SDCC_HC_PWRCTL_CTL_REG));
98
99 event_signal(data->sdhc_event, false);
100
101 return 0;
102}
103
104/*
105 * Function: sdhci clear pending interrupts
106 * Arg : MSM specific data for sdhci
107 * Return : None
108 * Flow: : Clear pending interrupts
109 */
110static void sdhci_clear_power_ctrl_irq(struct sdhci_msm_data *data)
111{
112 uint32_t irq_ctl;
113 uint32_t irq_stat;
114
115 /*
116 * Read the power control status register to know
117 * the status of BUS & IO_HIGH_V
118 */
119 irq_stat = readl(data->pwrctl_base + SDCC_HC_PWRCTL_STATUS_REG);
120
121 /* Clear the power control status */
122 writel(irq_stat, (data->pwrctl_base + SDCC_HC_PWRCTL_CLEAR_REG));
123
124 /*
125 * Handle the pending irq by ack'ing the bus & IO switch
126 */
127 irq_ctl = readl(data->pwrctl_base + SDCC_HC_PWRCTL_CTL_REG);
128
129 if (irq_stat & (SDCC_HC_BUS_ON | SDCC_HC_BUS_OFF))
130 irq_ctl |= SDCC_HC_BUS_ON_OFF_SUCC;
131 if (irq_stat & (SDCC_HC_IO_SIG_LOW | SDCC_HC_IO_SIG_HIGH))
132 irq_ctl |= SDCC_HC_IO_SIG_SUCC;
133
134 writel(irq_ctl, (data->pwrctl_base + SDCC_HC_PWRCTL_CTL_REG));
135}
136
137/*
138 * Function: sdhci msm init
139 * Arg : MSM specific config data for sdhci
140 * Return : None
141 * Flow: : Enable sdhci mode & do msm specific init
142 */
Channagoud Kadabi9b8f8fc2013-07-26 12:02:49 -0700143void sdhci_msm_init(struct sdhci_host *host, struct sdhci_msm_data *config)
Channagoud Kadabiafb8e172013-05-23 13:55:47 -0700144{
Channagoud Kadabi17e69972014-10-13 11:42:24 -0700145 uint32_t io_switch;
Channagoud Kadabi0e657d02014-11-06 18:08:57 -0800146 uint32_t caps = 0;
147 uint32_t version;
Channagoud Kadabi17e69972014-10-13 11:42:24 -0700148
Channagoud Kadabid10f6182013-12-30 11:51:53 -0800149 /* Disable HC mode */
150 RMWREG32((config->pwrctl_base + SDCC_MCI_HC_MODE), SDHCI_HC_START_BIT, SDHCI_HC_WIDTH, 0);
151
152 /* Core power reset */
153 RMWREG32((config->pwrctl_base + SDCC_MCI_POWER), CORE_SW_RST_START, CORE_SW_RST_WIDTH, 1);
154
155 /* Wait for the core power reset to complete*/
156 mdelay(1);
157
Channagoud Kadabiafb8e172013-05-23 13:55:47 -0700158 /* Enable sdhc mode */
Channagoud Kadabi946848d2013-10-02 12:09:37 -0700159 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 -0700160
Channagoud Kadabie632e252014-03-31 15:26:00 -0700161 /* Set the FF_CLK_SW_RST_DIS to 1 */
162 RMWREG32((config->pwrctl_base + SDCC_MCI_HC_MODE), FF_CLK_SW_RST_DIS_START, FF_CLK_SW_RST_DIS_WIDTH, 1);
163
Channagoud Kadabiafb8e172013-05-23 13:55:47 -0700164 /*
Channagoud Kadabi9b8f8fc2013-07-26 12:02:49 -0700165 * Reset the controller
166 */
167 sdhci_reset(host, SDHCI_SOFT_RESET);
168
169 /*
Channagoud Kadabi17e69972014-10-13 11:42:24 -0700170 * Some platforms have same SDC instance shared between emmc & sd card.
171 * For such platforms the emmc IO voltage has to be switched from 3.3 to
172 * 1.8 for the contoller to work with emmc.
173 */
174
175 if(config->use_io_switch)
176 {
177 io_switch = REG_READ32(host, SDCC_VENDOR_SPECIFIC_FUNC);
178 io_switch |= HC_IO_PAD_PWR_SWITCH | HC_IO_PAD_PWR_SWITCH_EN;
179 REG_WRITE32(host, io_switch, SDCC_VENDOR_SPECIFIC_FUNC);
180 }
181
182 /*
Channagoud Kadabiafb8e172013-05-23 13:55:47 -0700183 * CORE_SW_RST may trigger power irq if previous status of PWRCTL
184 * was either BUS_ON or IO_HIGH. So before we enable the power irq
185 * interrupt in GIC (by registering the interrupt handler), we need to
186 * ensure that any pending power irq interrupt status is acknowledged
187 * otherwise power irq interrupt handler would be fired prematurely.
188 */
189 sdhci_clear_power_ctrl_irq(config);
190
191 /*
192 * Register the interrupt handler for pwr irq
193 */
vijay kumar4f4405f2014-08-08 11:49:53 +0530194 register_int_handler(config->pwr_irq, (int_handler)sdhci_int_handler, (void *)config);
Channagoud Kadabiafb8e172013-05-23 13:55:47 -0700195
196 unmask_interrupt(config->pwr_irq);
197
198 /* Enable pwr control interrupt */
199 writel(SDCC_HC_PWR_CTRL_INT, (config->pwrctl_base + SDCC_HC_PWRCTL_MASK_REG));
Channagoud Kadabi9b8f8fc2013-07-26 12:02:49 -0700200
Channagoud Kadabi0e657d02014-11-06 18:08:57 -0800201 version = readl(host->msm_host->pwrctl_base + MCI_VERSION);
202
203 host->major = (version & CORE_VERSION_MAJOR_MASK) >> CORE_VERSION_MAJOR_SHIFT;
204 host->minor = (version & CORE_VERSION_MINOR_MASK);
205
206 /*
207 * For SDCC5 the capabilities registers does not have voltage advertised
208 * Override the values using SDCC_HC_VENDOR_SPECIFIC_CAPABILITIES0
209 */
210 if (host->major >= 1 && host->minor != 0x11 && host->minor != 0x12)
211 {
212 caps = REG_READ32(host, SDHCI_CAPS_REG1);
213
214 if (config->slot == 0x1)
215 REG_WRITE32(host, (caps | SDHCI_1_8_VOL_MASK), SDCC_HC_VENDOR_SPECIFIC_CAPABILITIES0);
216 else
217 REG_WRITE32(host, (caps | SDHCI_3_0_VOL_MASK), SDCC_HC_VENDOR_SPECIFIC_CAPABILITIES0);
218 }
219
Channagoud Kadabi9b8f8fc2013-07-26 12:02:49 -0700220 config->tuning_done = false;
221 config->calibration_done = false;
222 host->tuning_in_progress = false;
223}
224
225/*
226 * Function: sdhci msm set mci clk
227 * Arg : Host structure
228 * Return : None
229 * Flow: : Set HC_SELECT & HC_SELECT_EN for hs400
230 */
231void sdhci_msm_set_mci_clk(struct sdhci_host *host)
232{
233 struct sdhci_msm_data *msm_host;
234
235 msm_host = host->msm_host;
236
237 if (host->timing == MMC_HS400_TIMING)
238 {
239 /*
240 * If the current tuning mode is HS400 then we should set the MCLK to run
241 * the clock @ MCLK/2. Also set HS400 mode in SELECT_IN of vendor specific
242 * register
243 */
244 REG_RMW32(host, SDCC_VENDOR_SPECIFIC_FUNC, SDCC_HC_MCLK_HS400_START, SDCC_HC_MCLK_HS400_WIDTH, SDCC_HC_MCLK_SEL_HS400);
245
246 /* Enable HS400 mode from HC_SELECT_IN bit of VENDOR_SPEC register
247 * As the SDCC spec does not have matching mode for HS400
248 */
249 if (msm_host->tuning_done && !msm_host->calibration_done)
250 {
251 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);
252 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);
253 }
254 }
255 else
256 {
257 /*
258 * Set 0x0 mode in SELECT_IN of vendor specific register so that the
259 * host control2 register settings from sdhc spec are used for
260 * speed mode
261 */
262 REG_RMW32(host, SDCC_VENDOR_SPECIFIC_FUNC, SDCC_HC_MCLK_SEL_IN_START, SDCC_HC_MCLK_SEL_IN_WIDTH, 0x0);
263 REG_RMW32(host, SDCC_VENDOR_SPECIFIC_FUNC, SDCC_HC_MCLK_SEL_IN_EN_START, SDCC_HC_MCLK_SEL_IN_EN_WIDTH, 0x0);
264 }
265}
266
267/*
268 * Set the value based on sdcc clock frequency
269 */
270static void msm_set_dll_freq(struct sdhci_host *host)
271{
272 uint32_t reg_val = 0;
273
274 /* Set clock freq value based on clock range */
275 if (host->cur_clk_rate <= 112000000)
276 reg_val = 0x0;
277 else if (host->cur_clk_rate <= 125000000)
278 reg_val = 0x1;
279 else if (host->cur_clk_rate <= 137000000)
280 reg_val = 0x2;
281 else if (host->cur_clk_rate <= 150000000)
282 reg_val = 0x3;
283 else if (host->cur_clk_rate <= 162000000)
284 reg_val = 0x4;
285 else if (host->cur_clk_rate <= 175000000)
286 reg_val = 0x5;
287 else if (host->cur_clk_rate <= 187000000)
288 reg_val = 0x6;
289 else if (host->cur_clk_rate <= 200000000)
290 reg_val = 0x7;
291
Channagoud Kadabie632e252014-03-31 15:26:00 -0700292 DBG("\n %s: DLL freq: 0x%08x\n", __func__, reg_val);
293
Channagoud Kadabi9b8f8fc2013-07-26 12:02:49 -0700294 REG_RMW32(host, SDCC_DLL_CONFIG_REG, SDCC_DLL_CONFIG_MCLK_START, SDCC_DLL_CONFIG_MCLK_WIDTH, reg_val);
295}
296
297/* Initialize DLL (Programmable Delay Line) */
Channagoud Kadabie632e252014-03-31 15:26:00 -0700298static uint32_t sdhci_msm_init_dll(struct sdhci_host *host)
Channagoud Kadabi9b8f8fc2013-07-26 12:02:49 -0700299{
300 uint32_t pwr_save = 0;
Channagoud Kadabie632e252014-03-31 15:26:00 -0700301 uint32_t timeout = SDHCI_DLL_TIMEOUT;
Channagoud Kadabi9b8f8fc2013-07-26 12:02:49 -0700302
303 pwr_save = REG_READ32(host, SDCC_VENDOR_SPECIFIC_FUNC) & SDCC_DLL_PWR_SAVE_EN;
304
305 /* PWR SAVE to 0 */
306 if (pwr_save)
307 REG_WRITE32(host, (REG_READ32(host, SDCC_VENDOR_SPECIFIC_FUNC) & ~SDCC_DLL_PWR_SAVE_EN), SDCC_VENDOR_SPECIFIC_FUNC);
308 /* Set DLL_RST to 1 */
309 REG_WRITE32(host, (REG_READ32(host, SDCC_DLL_CONFIG_REG) | SDCC_DLL_RESET_EN), SDCC_DLL_CONFIG_REG);
310 /* Set DLL_PDN to 1 */
311 REG_WRITE32(host, (REG_READ32(host, SDCC_DLL_CONFIG_REG) | SDCC_DLL_PDN_EN), SDCC_DLL_CONFIG_REG);
312
313 /* Set frequency field in DLL_CONFIG */
314 msm_set_dll_freq(host);
315
316 /* Write 0 to DLL_RST */
317 REG_WRITE32(host, (REG_READ32(host, SDCC_DLL_CONFIG_REG) & ~SDCC_DLL_RESET_EN), SDCC_DLL_CONFIG_REG);
318 /* Write 0 to DLL_PDN */
319 REG_WRITE32(host, (REG_READ32(host, SDCC_DLL_CONFIG_REG) & ~SDCC_DLL_PDN_EN), SDCC_DLL_CONFIG_REG);
320 /* Write 1 to DLL_EN */
321 REG_WRITE32(host, (REG_READ32(host, SDCC_DLL_CONFIG_REG) | SDCC_DLL_EN), SDCC_DLL_CONFIG_REG);
322 /* Write 1 to CLK_OUT_EN */
323 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 -0700324 /* Wait for DLL_LOCK in DLL_STATUS register, wait time 50us */
Channagoud Kadabi96622212014-07-30 12:13:28 -0700325 while(!((REG_READ32(host, SDCC_REG_DLL_STATUS)) & SDCC_DLL_LOCK_STAT))
Channagoud Kadabie632e252014-03-31 15:26:00 -0700326 {
327 udelay(1);
328 timeout--;
329 if (!timeout)
330 {
331 dprintf(CRITICAL, "%s: Failed to get DLL lock: 0x%08x\n", __func__, REG_READ32(host, SDCC_REG_DLL_STATUS));
332 return 1;
333 }
334 }
335
Channagoud Kadabi9b8f8fc2013-07-26 12:02:49 -0700336 /* Set the powersave back on */
337 if (pwr_save)
Channagoud Kadabi7bcf6252014-05-14 18:28:13 -0700338 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 -0700339
340 return 0;
Channagoud Kadabi9b8f8fc2013-07-26 12:02:49 -0700341}
342
Channagoud Kadabidd8a7342014-07-09 10:35:01 -0700343void sdhci_msm_toggle_cdr(struct sdhci_host *host, bool enable)
344{
345 uint32_t core_cfg;
346
347 core_cfg = REG_READ32(host, SDCC_DLL_CONFIG_REG);
348
349 if (enable)
350 {
351 core_cfg |= SDCC_DLL_CDR_EN;
352 }
353 else
354 {
355 core_cfg &= ~SDCC_DLL_CDR_EN;
356 }
357
358 REG_WRITE32(host, core_cfg, SDCC_DLL_CONFIG_REG);
359}
360
Channagoud Kadabi9b8f8fc2013-07-26 12:02:49 -0700361/* Configure DLL with delay value based on 'phase' */
Channagoud Kadabie632e252014-03-31 15:26:00 -0700362static uint32_t sdhci_msm_config_dll(struct sdhci_host *host, uint32_t phase)
Channagoud Kadabi9b8f8fc2013-07-26 12:02:49 -0700363{
364 uint32_t core_cfg = 0;
Channagoud Kadabie632e252014-03-31 15:26:00 -0700365 uint32_t timeout = SDHCI_DLL_TIMEOUT;
366
Channagoud Kadabi9b8f8fc2013-07-26 12:02:49 -0700367 /* Gray code values from SWI */
368 uint32_t gray_code [] = { 0x0, 0x1, 0x3, 0x2, 0x6, 0x7, 0x5, 0x4, 0xC, 0xD, 0xF, 0xE, 0xA, 0xB, 0x9, 0x8 };
369
370 /* set CDR_EN & CLK_OUT_EN to 0 and
371 * CDR_EXT_EN & DLL_EN to 1*/
372 core_cfg = REG_READ32(host, SDCC_DLL_CONFIG_REG);
373 core_cfg &= ~(SDCC_DLL_CDR_EN | SDCC_DLL_CLK_OUT_EN);
374 core_cfg |= (SDCC_DLL_CDR_EXT_EN | SDCC_DLL_EN);
375 REG_WRITE32(host, core_cfg, SDCC_DLL_CONFIG_REG);
376
377 /* Wait until CLK_OUT_EN is 0 */
378 while(REG_READ32(host, SDCC_DLL_CONFIG_REG) & SDCC_DLL_CLK_OUT_EN);
379
380 REG_RMW32(host, SDCC_DLL_CONFIG_REG, SDCC_DLL_GRAY_CODE_START, SDCC_DLL_GRAY_CODE_WIDTH, gray_code[phase]);
381
382 REG_WRITE32(host, (REG_READ32(host, SDCC_DLL_CONFIG_REG) | SDCC_DLL_CLK_OUT_EN), SDCC_DLL_CONFIG_REG);
383
Channagoud Kadabie632e252014-03-31 15:26:00 -0700384 /* Wait until CLK_OUT_EN is 1, wait time 50us */
385 while(!(REG_READ32(host, SDCC_DLL_CONFIG_REG) & SDCC_DLL_CLK_OUT_EN))
386 {
387 timeout--;
388 udelay(1);
389 if (!timeout)
390 {
391 dprintf(CRITICAL, "%s: clk_out_en timed out: %08x\n", __func__, REG_READ32(host, SDCC_DLL_CONFIG_REG));
392 return 1;
393 }
394 }
Channagoud Kadabi9b8f8fc2013-07-26 12:02:49 -0700395
396 core_cfg = REG_READ32(host, SDCC_DLL_CONFIG_REG);
397
398 core_cfg |= SDCC_DLL_CDR_EN;
399 core_cfg &= ~SDCC_DLL_CDR_EXT_EN;
400
401 REG_WRITE32(host, core_cfg, SDCC_DLL_CONFIG_REG);
402
Channagoud Kadabie632e252014-03-31 15:26:00 -0700403 return 0;
Channagoud Kadabi9b8f8fc2013-07-26 12:02:49 -0700404}
405
406/*
407 * Find the right tuning delay, this function finds the largest
408 * consecutive sequence of phases & then selects the 3/4 th of
409 * the range which has max entries
410 * For eg: If we get the following sequence in phase_table[]
411 * (A) phase_table[] = 0x1, 0x2, 0x3, 0x4 , 0x5
412 * (B) phase_table[] = 0xA, 0xB, 0xC
413 * In the above case the (A) has maximum consecutive entries with '5' entries
414 * So delay would be phase_table[(0x5 * 3) / 4] = 0x3
415 */
416static int sdhci_msm_find_appropriate_phase(struct sdhci_host *host,
417 uint32_t *phase_table,
418 uint32_t total_phases)
419{
420 int sub_phases[MAX_PHASES][MAX_PHASES]={{0}};
vijay kumar4f4405f2014-08-08 11:49:53 +0530421 uint32_t phases_per_row[MAX_PHASES] = {0};
Channagoud Kadabi9b8f8fc2013-07-26 12:02:49 -0700422 uint32_t i,j;
423 int selected_phase = 0;
424 uint32_t row_index = 0;
425 uint32_t col_index = 0;
426 uint32_t phase_15_row_idx = 0;
427 uint32_t phases_0_row_idx = 0;
428 uint32_t max_phases_3_4_idx = 0;
429 uint32_t max_phases = 0;
430 uint32_t max_phases_row = 0;
431 bool found_loop = false;
432
433 if (!phase_table[0] && phase_table[total_phases - 1] == (MAX_PHASES - 1))
434 found_loop = true;
435
436 for (i = 0; i < total_phases; i++)
437 {
438 /* Break the phase table entries into different sub arrays based
439 * on the consecutive entries. Each row will have one sub array
440 * of consecutive entries.
441 * for eg: phase_table [] = { 0x0, 0x1, 0x2, 0xA, 0xB}
442 * sub_phases [0][] = { 0x0, 0x1, 0x2}
443 * sub_phases [1][] = { 0xA, 0xB}
444 */
445 sub_phases[row_index][col_index] = phase_table[i];
446 phases_per_row[row_index]++;
447 col_index++;
448
449 /* If we are at the last phase no need to check further */
450 if ((i + 1) == total_phases)
451 break;
452
453 /* If phase_table does not have consecutive entries, move to next entry */
454 if (phase_table[i]+1 != phase_table[i+1])
455 {
456 row_index++;
457 col_index = 0;
458 }
459 }
460
461 if (found_loop && total_phases < MAX_PHASES)
462 {
463 /* For consecutive entries we need to consider loops.
464 * If the phase_table contains 0x0 & 0xF then we have
465 * a loop, the number after 0xF in the sequence would be
466 * 0x0.
467 * for eg:
468 * phase_table = { 0x0, 0x1, 0x2, 0xD, 0xE, 0xF }
469 * then
470 * sub_phase [0][] = { 0x0, 0x1, 0x2 }
471 * sub_phase [1][] = { 0xD, 0xE, 0xF }
472 * Since we have a loop here, we need to merge the sub arrays as:
473 * sub_phase [1][] = { 0xD, 0xE, 0xF, 0x0, 0x1, 0x2 }
474 */
475
476 /* The entry 0xF will always be in the last row
477 * and entry 0x0 will always be in the first row
478 */
479 phase_15_row_idx = row_index;
480 j = 0;
481 for (i = phases_per_row[phase_15_row_idx] ; i < MAX_PHASES ; i++)
482 {
483 sub_phases[phase_15_row_idx][i] = sub_phases[phases_0_row_idx][j];
484 if (++j >= phases_per_row[phases_0_row_idx])
485 break;
486 }
487
488 /* Update the number of entries for the sub_phase after the merger */
489 phases_per_row[phase_15_row_idx] = phases_per_row[phase_15_row_idx] + phases_per_row[phases_0_row_idx];
490 phases_per_row[phases_0_row_idx] = 0;
491 }
492
493 for (i = 0 ; i <= row_index; i++)
494 {
495 if (phases_per_row[i] > max_phases)
496 {
497 max_phases = phases_per_row[i];
498 max_phases_row = i;
499 }
500 }
501
502 max_phases_3_4_idx = (max_phases * 3) / 4;
503 if (max_phases_3_4_idx)
504 max_phases_3_4_idx--;
505
506 selected_phase = sub_phases[max_phases_row][max_phases_3_4_idx];
507
508 return selected_phase;
509}
510
Channagoud Kadabi756e1e32014-06-05 13:00:55 -0700511static uint32_t sdhci_msm_cm_dll_sdc4_calibration(struct sdhci_host *host)
512{
513 uint32_t timeout = 0;
514
515 DBG("\n CM_DLL_SDC4 Calibration Start\n");
516
Channagoud Kadabi355f1fa2014-10-08 19:57:00 -0700517 /*1.Write the DDR config value to SDCC_HC_REG_DDR_CONFIG register*/
518 REG_WRITE32(host, target_ddr_cfg_val(), SDCC_HC_REG_DDR_CONFIG);
Channagoud Kadabi756e1e32014-06-05 13:00:55 -0700519
520 /*2. Write DDR_CAL_EN to '1' */
521 REG_WRITE32(host, (REG_READ32(host, SDCC_HC_REG_DLL_CONFIG_2) | DDR_CAL_EN), SDCC_HC_REG_DLL_CONFIG_2);
522
523 /*3. Wait for DLL_LOCK for hs400 to be set */
524 timeout = DDR_CAL_TIMEOUT_MAX;
525 while (!(REG_READ32(host, SDCC_REG_DLL_STATUS) & DDR_DLL_LOCK_JDR))
526 {
527 timeout--;
528 mdelay(1);
529 if (!timeout)
530 {
531 dprintf(CRITICAL, "Error: DLL lock for hs400 operation is not set\n");
532 return 1;
533 }
534 }
535
536 /*4. Set powersave dll */
537 REG_WRITE32(host, (REG_READ32(host, SDCC_HC_VENDOR_SPECIFIC_FUNC3) | PWRSAVE_DLL), SDCC_HC_VENDOR_SPECIFIC_FUNC3);
538
539 DBG("\n CM_DLL_SDC4 Calibration Done\n");
540
541 return 0;
542}
543
Channagoud Kadabi9b8f8fc2013-07-26 12:02:49 -0700544static uint32_t sdhci_msm_cdclp533_calibration(struct sdhci_host *host)
545{
546 uint32_t timeout;
547 uint32_t cdc_err;
548
Channagoud Kadabie632e252014-03-31 15:26:00 -0700549 DBG("\n CDCLP533 Calibration Start\n");
550
Channagoud Kadabi9b8f8fc2013-07-26 12:02:49 -0700551 /* Write 0 to CDC_T4_DLY_SEL field in VENDOR_SPEC_DDR200_CFG */
552 REG_WRITE32(host, (REG_READ32(host, SDCC_CDC_DDR200_CFG) & ~CDC_T4_DLY_SEL), SDCC_CDC_DDR200_CFG);
553
554 /* Write 0 to START_CDC_TRAFFIC field in CORE_DDR200_CFG */
555 REG_WRITE32(host, (REG_READ32(host, SDCC_CDC_DDR200_CFG) & ~START_CDC_TRAFFIC), SDCC_CDC_DDR200_CFG);
556
557 /* Write 0 to CDC_SWITCH_BYPASS_OFF field in CSR_CDC_GEN_CFG */
558 REG_WRITE32(host, (REG_READ32(host, SDCC_VENDOR_SPEC_CSR_CDC_CFG) & ~CDC_SWITCH_BYPASS_OFF), SDCC_VENDOR_SPEC_CSR_CDC_CFG);
559
560 /* Write 1 to CDC_SWITCH_RC_EN field in CSR_CDC_GEN_CFG */
561 REG_WRITE32(host, (REG_READ32(host, SDCC_VENDOR_SPEC_CSR_CDC_CFG) | CDC_SWITCH_RC_EN), SDCC_VENDOR_SPEC_CSR_CDC_CFG);
562
563 /* Write 0 to START_CDC_TRAFFIC field in CORE_DDR200_CFG */
564 REG_WRITE32(host, (REG_READ32(host, SDCC_CDC_DDR200_CFG) & ~START_CDC_TRAFFIC), SDCC_CDC_DDR200_CFG);
565
566 /* Perform CDCLP533 initialization sequence
567 * SDCC_CSR_CDC_CTRL_CFG0 --> 0x11800EC
568 * SDCC_CSR_CDC_CTRL_CFG1 --> 0x3011111
569 * SDCC_CSR_CDC_CAL_TIMER_CFG0 --> 0x1201000
570 * SDCC_CSR_CDC_CAL_TIMER_CFG1 --> 0x4
571 * SDCC_CSR_CDC_REFCOUNT_CFG --> 0xCB732020
572 * SDCC_CSR_CDC_COARSE_CAL_CFG --> 0xB19
Channagoud Kadabi86afb382014-06-23 11:15:46 -0700573 * SDCC_CSR_CDC_DELAY_CFG --> 0x4E2
Channagoud Kadabi9b8f8fc2013-07-26 12:02:49 -0700574 * SDCC_CDC_OFFSET_CFG --> 0x0
575 * SDCC_CDC_SLAVE_DDA_CFG --> 0x16334
576 */
577
578 REG_WRITE32(host, 0x11800EC, SDCC_CSR_CDC_CTRL_CFG0);
579 REG_WRITE32(host, 0x3011111, SDCC_CSR_CDC_CTRL_CFG1);
580 REG_WRITE32(host, 0x1201000, SDCC_CSR_CDC_CAL_TIMER_CFG0);
581 REG_WRITE32(host, 0x4, SDCC_CSR_CDC_CAL_TIMER_CFG1);
582 REG_WRITE32(host, 0xCB732020, SDCC_CSR_CDC_REFCOUNT_CFG);
583 REG_WRITE32(host, 0xB19, SDCC_CSR_CDC_COARSE_CAL_CFG);
Channagoud Kadabi86afb382014-06-23 11:15:46 -0700584 REG_WRITE32(host, 0x4E2, SDCC_CSR_CDC_DELAY_CFG);
Channagoud Kadabi9b8f8fc2013-07-26 12:02:49 -0700585 REG_WRITE32(host, 0x0, SDCC_CDC_OFFSET_CFG);
586 REG_WRITE32(host, 0x16334, SDCC_CDC_SLAVE_DDA_CFG);
587
588 /* Write 1 to SW_TRIGGER_FULL_CALIB */
589 REG_WRITE32(host, (REG_READ32(host, SDCC_CSR_CDC_CTRL_CFG0) | CDC_SW_TRIGGER_FULL_CALIB), SDCC_CSR_CDC_CTRL_CFG0);
590
591 /* Write 0 to SW_TRIGGER_FULL_CALIB */
592 REG_WRITE32(host, (REG_READ32(host, SDCC_CSR_CDC_CTRL_CFG0) & ~CDC_SW_TRIGGER_FULL_CALIB), SDCC_CSR_CDC_CTRL_CFG0);
593
594 /* Write 1 to HW_AUTO_CAL_EN */
595 REG_WRITE32(host, (REG_READ32(host, SDCC_CSR_CDC_CTRL_CFG0) | CDC_HW_AUTO_CAL_EN), SDCC_CSR_CDC_CTRL_CFG0);
596
597 /* Write 1 to TIMER_ENA */
598 REG_WRITE32(host, (REG_READ32(host, SDCC_CSR_CDC_CAL_TIMER_CFG0) | CDC_TIMER_EN), SDCC_CSR_CDC_CAL_TIMER_CFG0);
599
600 /* Wait for CALIBRATION_DONE in CDC_STATUS */
Channagoud Kadabie632e252014-03-31 15:26:00 -0700601 timeout = CDC_STATUS_TIMEOUT;
Channagoud Kadabi9b8f8fc2013-07-26 12:02:49 -0700602 while (!(REG_READ32(host, SDCC_CSR_CDC_STATUS0) & BIT(0)))
603 {
604 timeout--;
605 mdelay(1);
606 if (!timeout)
607 {
608 dprintf(CRITICAL, "Error: Calibration done in CDC status not set\n");
609 return 1;
610 }
611 }
612
613 cdc_err = REG_READ32(host, SDCC_CSR_CDC_STATUS0) & CSR_CDC_ERROR_MASK;
614 if (cdc_err)
615 {
616 dprintf(CRITICAL, "CDC error set during calibration: %x\n", cdc_err);
617 return 1;
618 }
619 /* Write 1 to START_CDC_TRAFFIC field in CORE_DDR200_CFG */
620 REG_WRITE32(host, (REG_READ32(host, SDCC_CDC_DDR200_CFG) | START_CDC_TRAFFIC), SDCC_CDC_DDR200_CFG);
621
Channagoud Kadabie632e252014-03-31 15:26:00 -0700622 DBG("\n CDCLP533 Calibration Done\n");
623
Channagoud Kadabi9b8f8fc2013-07-26 12:02:49 -0700624 return 0;
625}
626
Channagoud Kadabi756e1e32014-06-05 13:00:55 -0700627
628static uint32_t sdhci_msm_hs400_calibration(struct sdhci_host *host)
629{
630 DBG("\n HS400 Calibration Start\n");
631
632 /* Reset & Initialize the DLL block */
633 if (sdhci_msm_init_dll(host))
634 return 1;
635
636 /* Write the save phase */
637 if (sdhci_msm_config_dll(host, host->msm_host->saved_phase))
638 return 1;
639
640 /* Write 1 to CMD_DAT_TRACK_SEL field in DLL_CONFIG */
641 REG_WRITE32(host, (REG_READ32(host, SDCC_DLL_CONFIG_REG) | CMD_DAT_TRACK_SEL), SDCC_DLL_CONFIG_REG);
642
643 if (host->use_cdclp533)
644 return sdhci_msm_cdclp533_calibration(host);
645 else
646 return sdhci_msm_cm_dll_sdc4_calibration(host);
647
648 DBG("\n HS400 Calibration Done\n");
649
650 return 0;
651}
652
Channagoud Kadabi9b8f8fc2013-07-26 12:02:49 -0700653/*
654 * Function: sdhci msm execute tuning
655 * Arg : Host structure & bus width
656 * Return : 0 on Success, 1 on Failure
Channagoud Kadabi756e1e32014-06-05 13:00:55 -0700657 * Flow: : Execute Tuning sequence for HS200 and calibration for hs400
Channagoud Kadabi9b8f8fc2013-07-26 12:02:49 -0700658 */
Channagoud Kadabie106d1f2014-04-25 18:26:26 -0700659uint32_t sdhci_msm_execute_tuning(struct sdhci_host *host, struct mmc_card *card, uint32_t bus_width)
Channagoud Kadabi9b8f8fc2013-07-26 12:02:49 -0700660{
661 uint32_t *tuning_block;
662 uint32_t *tuning_data;
vijay kumar4f4405f2014-08-08 11:49:53 +0530663 uint32_t tuned_phases[MAX_PHASES] = {0};
Channagoud Kadabi9b8f8fc2013-07-26 12:02:49 -0700664 uint32_t size;
665 uint32_t phase = 0;
666 uint32_t tuned_phase_cnt = 0;
Channagoud Kadabie106d1f2014-04-25 18:26:26 -0700667 uint8_t drv_type = 0;
668 bool drv_type_changed = false;
Channagoud Kadabi9b8f8fc2013-07-26 12:02:49 -0700669 int ret = 0;
vijay kumar4f4405f2014-08-08 11:49:53 +0530670 uint32_t i;
Channagoud Kadabi9b8f8fc2013-07-26 12:02:49 -0700671 struct sdhci_msm_data *msm_host;
672
673 msm_host = host->msm_host;
674
675 /* In Tuning mode */
676 host->tuning_in_progress = true;
677
678 /* Calibration for CDCLP533 needed for HS400 mode */
679 if (msm_host->tuning_done && !msm_host->calibration_done && host->timing == MMC_HS400_TIMING)
680 {
Channagoud Kadabi756e1e32014-06-05 13:00:55 -0700681 ret = sdhci_msm_hs400_calibration(host);
Channagoud Kadabi9b8f8fc2013-07-26 12:02:49 -0700682 if (!ret)
683 msm_host->calibration_done = true;
684 goto out;
685 }
686
687 if (bus_width == DATA_BUS_WIDTH_8BIT)
688 {
vijay kumar4f4405f2014-08-08 11:49:53 +0530689 tuning_block = (uint32_t *)tuning_block_128;
Channagoud Kadabi9b8f8fc2013-07-26 12:02:49 -0700690 size = sizeof(tuning_block_128);
691 }
692 else
693 {
vijay kumar4f4405f2014-08-08 11:49:53 +0530694 tuning_block = (uint32_t *)tuning_block_64;
Channagoud Kadabi9b8f8fc2013-07-26 12:02:49 -0700695 size = sizeof(tuning_block_64);
696 }
697
698 tuning_data = (uint32_t *) memalign(CACHE_LINE, ROUNDUP(size, CACHE_LINE));
699
700 ASSERT(tuning_data);
701
702 /* Reset & Initialize the DLL block */
Channagoud Kadabie632e252014-03-31 15:26:00 -0700703 if (sdhci_msm_init_dll(host))
704 {
705 ret = 1;
706 goto free;
707 }
Channagoud Kadabi9b8f8fc2013-07-26 12:02:49 -0700708
Channagoud Kadabie106d1f2014-04-25 18:26:26 -0700709retry_tuning:
710 tuned_phase_cnt = 0;
711 phase = 0;
712
Channagoud Kadabi9b8f8fc2013-07-26 12:02:49 -0700713 while (phase < MAX_PHASES)
714 {
715 struct mmc_command cmd = {0};
716
717 /* configure dll to set phase delay */
Channagoud Kadabie632e252014-03-31 15:26:00 -0700718 if (sdhci_msm_config_dll(host, phase))
719 {
720 ret = 1;
721 goto free;
722 }
Channagoud Kadabi9b8f8fc2013-07-26 12:02:49 -0700723
724 cmd.cmd_index = CMD21_SEND_TUNING_BLOCK;
725 cmd.argument = 0x0;
726 cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL;
727 cmd.resp_type = SDHCI_CMD_RESP_R1;
728 cmd.trans_mode = SDHCI_MMC_READ;
729 cmd.data_present = 0x1;
730 cmd.data.data_ptr = tuning_data;
731 cmd.data.blk_sz = size;
732 cmd.data.num_blocks = 0x1;
733
734 /* send command */
735 if (!sdhci_send_command(host, &cmd) && !memcmp(tuning_data, tuning_block, size))
736 tuned_phases[tuned_phase_cnt++] = phase;
737
738 phase++;
739 }
740
Channagoud Kadabie106d1f2014-04-25 18:26:26 -0700741 /*
742 * Check if all the tuning phases passed */
743 if (tuned_phase_cnt == MAX_PHASES)
744 {
745 /* Change the driver type & rerun tuning */
Channagoud Kadabie4cab762014-07-08 17:26:06 -0700746 while(++drv_type <= MX_DRV_SUPPORTED_HS200)
Channagoud Kadabie106d1f2014-04-25 18:26:26 -0700747 {
748 drv_type_changed = mmc_set_drv_type(host, card, drv_type);
749 if (drv_type_changed)
750 {
751 goto retry_tuning;
752 }
753 }
754 }
755
756 /* Restore the driver strength to default value */
757 if (drv_type_changed)
758 mmc_set_drv_type(host, card, 0);
759
Channagoud Kadabi9b8f8fc2013-07-26 12:02:49 -0700760 /* Find the appropriate tuned phase */
761 if (tuned_phase_cnt)
762 {
Channagoud Kadabie632e252014-03-31 15:26:00 -0700763 DBG("\n Tuned phase\n");
764 for (i = 0 ; i < tuned_phase_cnt ; i++)
765 {
766 DBG("%d\t", tuned_phases[i]);
767 }
768
Channagoud Kadabi9b8f8fc2013-07-26 12:02:49 -0700769 ret = sdhci_msm_find_appropriate_phase(host, tuned_phases, tuned_phase_cnt);
770
771 if (ret < 0)
772 {
773 dprintf(CRITICAL, "Failed in selecting the tuning phase\n");
774 ret = 1;
775 goto free;
776 }
777
778 phase = (uint32_t) ret;
779 ret = 0;
780
Channagoud Kadabie632e252014-03-31 15:26:00 -0700781 DBG("\n: %s: Tuned Phase: 0x%08x\n", __func__, phase);
782
783 if (sdhci_msm_config_dll(host, phase))
784 goto free;
Channagoud Kadabi9b8f8fc2013-07-26 12:02:49 -0700785
786 /* Save the tuned phase */
787 host->msm_host->saved_phase = phase;
788 }
789 else
790 {
791 dprintf(CRITICAL, "Failed to get tuned phase\n");
792 ret = 1;
793 }
794
795free:
796 free(tuning_data);
797out:
798 /* Tuning done */
799 host->tuning_in_progress = false;
800 host->msm_host->tuning_done = true;
801 return ret;
Channagoud Kadabiafb8e172013-05-23 13:55:47 -0700802}
Channagoud Kadabi24146af2014-01-24 17:22:08 -0800803
804/*
805 * API to disable HC mode
806 */
807void sdhci_mode_disable(struct sdhci_host *host)
808{
809 /* Disable HC mode */
810 RMWREG32((host->msm_host->pwrctl_base + SDCC_MCI_HC_MODE), SDHCI_HC_START_BIT, SDHCI_HC_WIDTH, 0);
811}
812