• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2020 HiSilicon (Shanghai) Technologies CO., LIMITED.
3  *
4  * This program is free software; you can redistribute  it and/or modify it
5  * under  the terms of  the GNU General  Public License as published by the
6  * Free Software Foundation;  either version 2 of the  License, or (at your
7  * option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16  *
17  */
18 
19 #include <common.h>
20 #include <malloc.h>
21 #include <sdhci.h>
22 #include "mmc_private.h"
23 
24 #define MIN_FREQ	400000
25 #define NOT_FOUND	(-1)
26 #define PHASE_SCALE	32
27 #define EDGE_TUNING_PHASE_STEP	4
28 
29 static void hisi_enable_sample(struct sdhci_host *host);
30 static void hisi_set_drv_phase(struct sdhci_host *host,	unsigned int phase);
31 static void hisi_set_sampl_phase(struct sdhci_host *host, unsigned int phase);
32 static void hisi_wait_sampl_dll_slave_ready(struct sdhci_host *host);
33 static void hisi_enable_card_clk(struct sdhci_host *host);
34 static void hisi_disable_card_clk(struct sdhci_host *host);
35 static void hisi_enable_internal_clk(struct sdhci_host *host);
36 static void hisi_disable_internal_clk(struct sdhci_host *host);
37 
38 #if defined(CONFIG_TARGET_HI3556AV100) || defined(CONFIG_TARGET_HI3519AV100)
39 #include <asm/arch-hi3556av100/platform.h>
40 #include "hisi_hi3556av100.c"
41 #endif
42 
43 #if defined(CONFIG_TARGET_HI3559AV100) || defined(CONFIG_TARGET_HI3569V100)
44 #include <asm/arch-hi3559av100/platform.h>
45 #include "hisi_hi3559av100.c"
46 #endif
47 
48 #ifdef CONFIG_TARGET_HI3516EV200
49 #include <asm/arch-hi3516ev200/platform.h>
50 #include "hisi_hi3516ev200.c"
51 #endif
52 
53 #ifdef CONFIG_TARGET_HI3516EV300
54 #include <asm/arch-hi3516ev300/platform.h>
55 #include "hisi_hi3516ev300.c"
56 #endif
57 
58 #ifdef CONFIG_TARGET_HI3518EV300
59 #include <asm/arch-hi3518ev300/platform.h>
60 #include "hisi_hi3518ev300.c"
61 #endif
62 
63 #ifdef CONFIG_TARGET_HI3516DV200
64 #include <asm/arch-hi3516dv200/platform.h>
65 #include "hisi_hi3516dv200.c"
66 #endif
67 
68 #ifdef CONFIG_TARGET_HI3531DV200
69 #include <asm/arch-hi3531dv200/platform.h>
70 #include "hisi_hi3531dv200.c"
71 #endif
72 
73 #ifdef CONFIG_TARGET_HI3535AV100
74 #include <asm/arch-hi3531dv200/platform.h>
75 #include "hisi_hi3531dv200.c"
76 #endif
77 
78 #ifdef CONFIG_TARGET_HI3521DV200
79 #include <asm/arch-hi3521dv200/platform.h>
80 #include "hisi_hi3521dv200.c"
81 #endif
82 
83 #ifdef CONFIG_TARGET_HI3520DV500
84 #include <asm/arch-hi3521dv200/platform.h>
85 #include "hisi_hi3521dv200.c"
86 #endif
87 
hisi_enable_card_clk(struct sdhci_host * host)88 static void hisi_enable_card_clk(struct sdhci_host *host)
89 {
90 	u16 clk;
91 
92 	clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
93 	clk |= SDHCI_CLOCK_CARD_EN;
94 	sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
95 }
96 
hisi_disable_card_clk(struct sdhci_host * host)97 static void hisi_disable_card_clk(struct sdhci_host *host)
98 {
99 	u16 clk;
100 
101 	clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
102 	clk &= ~SDHCI_CLOCK_CARD_EN;
103 	sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
104 }
105 
hisi_enable_internal_clk(struct sdhci_host * host)106 static void hisi_enable_internal_clk(struct sdhci_host *host)
107 {
108 	u16 clk;
109 	u16 timeout = 20;
110 
111 	clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
112 	clk |= SDHCI_CLOCK_INT_EN | SDHCI_CLOCK_PLL_EN;
113 	sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
114 
115 	/* Wait max 20 ms */
116 	clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
117 	while (!(clk & SDHCI_CLOCK_INT_STABLE)) {
118 		if (timeout == 0) {
119 			printf("%s: Internal clock never stabilised.\n",
120 					__func__);
121 			return;
122 		}
123 		timeout--;
124 		udelay(1000); /* delay 1000us */
125 		clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
126 	}
127 }
128 
hisi_disable_internal_clk(struct sdhci_host * host)129 static void __maybe_unused hisi_disable_internal_clk(struct sdhci_host *host)
130 {
131 	u16 clk;
132 
133 	clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
134 	clk &= ~SDHCI_CLOCK_INT_EN;
135 	sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
136 }
137 
hisi_set_drv_phase(struct sdhci_host * host,unsigned int phase)138 static void hisi_set_drv_phase(struct sdhci_host *host, unsigned int phase)
139 {
140 	uintptr_t crg_addr;
141 	unsigned int reg;
142 
143 	crg_addr = host->type == MMC_TYPE_MMC ?
144 		REG_EMMC_DRV_DLL_CTRL : REG_SDIO0_DRV_DLL_CTRL;
145 	reg = readl(crg_addr);
146 	reg &= ~SDIO_DRV_PHASE_SEL_MASK;
147 	reg |= sdio_drv_sel(phase);
148 	writel(reg, crg_addr);
149 }
150 
hisi_enable_sample(struct sdhci_host * host)151 static void hisi_enable_sample(struct sdhci_host *host)
152 {
153 	unsigned int reg;
154 
155 	reg = sdhci_readl(host, SDHCI_AT_CTRL);
156 	reg |= SDHCI_SAMPLE_EN;
157 	sdhci_writel(host, reg, SDHCI_AT_CTRL);
158 }
159 
hisi_set_sampl_phase(struct sdhci_host * host,unsigned int phase)160 static void hisi_set_sampl_phase(struct sdhci_host *host, unsigned int phase)
161 {
162 	unsigned int reg;
163 
164 	reg = sdhci_readl(host, SDHCI_AT_STAT);
165 	reg &= ~SDHCI_PHASE_SEL_MASK;
166 	reg |= phase;
167 	sdhci_writel(host, reg, SDHCI_AT_STAT);
168 }
169 
hisi_wait_sampl_dll_slave_ready(struct sdhci_host * host)170 static void hisi_wait_sampl_dll_slave_ready(struct sdhci_host *host)
171 {
172 	unsigned int reg;
173 	unsigned int timeout = 20;
174 	uintptr_t reg_addr;
175 
176 	reg_addr = host->type == MMC_TYPE_MMC ?
177 		REG_EMMC_SAMPL_DLL_STATUS : REG_SDIO0_SAMPL_DLL_STATUS;
178 	do {
179 		reg = readl(reg_addr);
180 		if (reg & SDIO_SAMPL_DLL_SLAVE_READY)
181 			return;
182 
183 		udelay(1000); /* delay 1000us */
184 		timeout--;
185 	} while (timeout > 0);
186 
187 	printf("sdhci-hisi: SAMPL DLL slave not ready.\n");
188 }
189 
hisi_enable_edge_tuning(struct sdhci_host * host)190 static void hisi_enable_edge_tuning(struct sdhci_host *host)
191 {
192 	unsigned int reg;
193 
194 	reg = readl(REG_EMMC_SAMPLB_DLL_CTRL);
195 	reg &= ~SDIO_SAMPLB_DLL_CLK_MASK;
196 	reg |= sdio_samplb_sel(8); /* sel 8 */
197 	writel(reg, REG_EMMC_SAMPLB_DLL_CTRL);
198 
199 	reg = sdhci_readl(host, SDHCI_MULTI_CYCLE);
200 	reg |= SDHCI_EDGE_DETECT_EN;
201 	sdhci_writel(host, reg, SDHCI_MULTI_CYCLE);
202 }
203 
hisi_disable_edge_tuning(struct sdhci_host * host)204 static void hisi_disable_edge_tuning(struct sdhci_host *host)
205 {
206 	unsigned int reg;
207 
208 	reg = sdhci_readl(host, SDHCI_MULTI_CYCLE);
209 	reg &= ~SDHCI_EDGE_DETECT_EN;
210 	sdhci_writel(host, reg, SDHCI_MULTI_CYCLE);
211 }
212 
hisi_select_sampl_phase(struct sdhci_host * host,unsigned int phase)213 static void hisi_select_sampl_phase(struct sdhci_host *host, unsigned int phase)
214 {
215 	hisi_disable_card_clk(host);
216 	hisi_set_sampl_phase(host, phase);
217 	hisi_wait_sampl_dll_slave_ready(host);
218 	hisi_enable_card_clk(host);
219 	udelay(1);
220 }
221 
hisi_send_tuning(struct sdhci_host * host,u32 opcode,int * cmd_error)222 static int hisi_send_tuning(struct sdhci_host *host, u32 opcode, int* cmd_error)
223 {
224 	int count, err;
225 	const int tuning_num = 1;
226 
227 	count = 0;
228 	do {
229 		err = mmc_send_tuning(host->mmc, opcode, NULL);
230 		if (err)
231 			break;
232 
233 		count++;
234 	} while (count < tuning_num);
235 
236 	return err;
237 }
238 
hisi_mmc_exec_tuning(struct sdhci_host * host,unsigned int opcode)239 static int hisi_mmc_exec_tuning(struct sdhci_host *host, unsigned int opcode)
240 {
241 	unsigned int index, val;
242 	unsigned int edge_p2f, edge_f2p, start, end, phase;
243 	unsigned int fall, rise, fall_updat_flag;
244 	unsigned int found;
245 	unsigned int prev_found = 0;
246 	int err;
247 	int prev_err = 0;
248 	unsigned short ctrl;
249 
250 	hisi_wait_drv_dll_lock(host);
251 	hisi_enable_sampl_dll_slave(host);
252 	hisi_enable_sample(host);
253 	hisi_enable_edge_tuning(host);
254 	host->is_tuning = 1;
255 
256 	start = 0;
257 	end = PHASE_SCALE / EDGE_TUNING_PHASE_STEP;
258 
259 	edge_p2f = start;
260 	edge_f2p = end;
261 	for (index = 0; index <= end; index++) {
262 		hisi_select_sampl_phase(host, index * EDGE_TUNING_PHASE_STEP);
263 
264 		err = mmc_send_tuning(host->mmc, opcode, NULL);
265 		if (!err) {
266 			val = sdhci_readl(host, SDHCI_MULTI_CYCLE);
267 			found = val & SDHCI_FOUND_EDGE;
268 		} else {
269 			found = 1;
270 		}
271 
272 		if (prev_found && !found)
273 			edge_f2p = index;
274 		else if (!prev_found && found)
275 			edge_p2f = index;
276 
277 		if ((edge_p2f != start) && (edge_f2p != end))
278 			break;
279 
280 		prev_found = found;
281 	}
282 
283 	if ((edge_p2f == start) && (edge_f2p == end)) {
284 		printf("sdhci-hisi: tuning failed! can not found edge!\n");
285 		return -1;
286 	}
287 
288 	hisi_disable_edge_tuning(host);
289 
290 	start = edge_p2f * EDGE_TUNING_PHASE_STEP;
291 	end = edge_f2p * EDGE_TUNING_PHASE_STEP;
292 	if (end <= start)
293 		end += PHASE_SCALE;
294 
295 	fall = start;
296 	rise = end;
297 	fall_updat_flag = 0;
298 	for (index = start; index <= end; index++) {
299 		hisi_select_sampl_phase(host, index % PHASE_SCALE);
300 
301 		err = hisi_send_tuning(host, opcode, NULL);
302 		if (err)
303 			debug("sdhci-hisi: send tuning CMD%u fail! phase:%u err:%d\n",
304 				opcode, index, err);
305 
306 		if (err && index == start) {
307 			if (!fall_updat_flag) {
308 				fall_updat_flag = 1;
309 				fall = start;
310 			}
311 		} else {
312 			if (!prev_err && err) {
313 				if (!fall_updat_flag) {
314 					fall_updat_flag = 1;
315 					fall = index;
316 				}
317 			}
318 		}
319 
320 		if (prev_err && !err)
321 			rise = index;
322 
323 		if (err && index == end)
324 			rise = end;
325 
326 		prev_err = err;
327 	}
328 
329 	phase = ((fall + rise) / 2 + PHASE_SCALE / 2) % PHASE_SCALE; /* 2 for cal average */
330 
331 	printf("sdhci-hisi: tuning done! valid phase shift [%u, %u] Final Phase:%u\n",
332 			rise % PHASE_SCALE, fall % PHASE_SCALE, phase);
333 
334 	host->tuning_phase = phase;
335 	hisi_select_sampl_phase(host, phase);
336 
337 	ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
338 	ctrl |= SDHCI_CTRL_TUNED_CLK;
339 	sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
340 	host->is_tuning = 0;
341 
342 	return 0;
343 }
344 
hisi_sdhci_set_host_caps(struct sdhci_host * host)345 void hisi_sdhci_set_host_caps(struct sdhci_host *host)
346 {
347 	host->host_caps = MMC_MODE_HS | MMC_MODE_HS_52MHz |
348 			  MMC_MODE_HS200 | MMC_MODE_4BIT;
349 
350 #if defined(CONFIG_TARGET_HI3531DV200) || defined(CONFIG_TARGET_HI3535AV100) ||\
351 	defined(CONFIG_TARGET_HI3521DV200) || defined(CONFIG_TARGET_HI3520DV500)
352 	if (get_mmc_bus_width() == MMC_BUS_WIDTH_8_BIT)
353 		host->host_caps |= MMC_MODE_HS400_ES |
354 			MMC_MODE_HS400 | MMC_MODE_8BIT;
355 #elif !(defined(CONFIG_TARGET_HI3516EV200) || defined(CONFIG_TARGET_HI3518EV300))
356 	host->host_caps |= MMC_MODE_HS400_ES | MMC_MODE_HS400 |
357 			   MMC_MODE_8BIT;
358 #endif
359 }
360 
hisi_sdhci_add_port(int index,uintptr_t regbase,u32 type)361 int hisi_sdhci_add_port(int index, uintptr_t regbase, u32 type)
362 {
363 	struct sdhci_host *host = NULL;
364 
365 	if (type == MMC_TYPE_MMC)
366 		emmc_hardware_init();
367 	else
368 		sd_hardware_init();
369 
370 	host = calloc(1, sizeof(struct sdhci_host));
371 	if (host == NULL) {
372 		puts("sdhci_host malloc fail!\n");
373 		return -ENOMEM;
374 	}
375 
376 	host->name = "hisi-sdhci";
377 	host->index = index;
378 	host->type = type;
379 	host->ioaddr = (void *)regbase;
380 	host->quirks = 0;
381 	host->set_clock = hisi_mmc_set_clk;
382 	host->priv_init = hisi_mmc_priv_init;
383 	host->set_control_reg = hisi_mmc_set_ioconfig;
384 #ifdef MMC_SUPPORTS_TUNING
385 	host->execute_tuning = hisi_mmc_exec_tuning;
386 #endif
387 	hisi_sdhci_set_host_caps(host);
388 	add_sdhci(host, CONFIG_HISI_SDHCI_MAX_FREQ, MIN_FREQ);
389 	return 0;
390 }
391 
print_mmcinfo(struct mmc * mmc)392 static void print_mmcinfo(struct mmc *mmc)
393 {
394 	printf("MMC/SD Card:\n");
395 	printf("    MID:         0x%x\n", mmc->cid[0] >> 24); /* bit24 - 31 */
396 	printf("    Read Block:  %d Bytes\n", mmc->read_bl_len);
397 	printf("    Write Block: %d Bytes\n", mmc->write_bl_len);
398 	printf("    Chip Size:   %s Bytes (%s)\n",
399 			ultohstr(mmc->capacity),
400 			mmc->high_capacity ? "High Capacity" : "Low Capacity");
401 	printf("    Name:        \"%c%c%c%c%c\"\n",
402 			mmc->cid[0] & 0xff,           /* bit0   -  7 */
403 			(mmc->cid[1] >> 24),          /* bit24 - 32 */
404 			(mmc->cid[1] >> 16) & 0xff,   /* bit16 - 23 */
405 			(mmc->cid[1] >> 8) & 0xff,    /* bit8   - 15 */
406 			mmc->cid[1] & 0xff);          /* bit0   -  7 */
407 
408 	printf("    Chip Type:   %s\n"
409 			"    Version:     %d.%d\n",
410 			IS_SD(mmc) ? "SD" : "MMC",
411 			EXTRACT_SDMMC_MAJOR_VERSION(mmc->version),
412 			EXTRACT_SDMMC_MINOR_VERSION(mmc->version));
413 
414 	printf("    Speed:       %sHz\n", ultohstr(mmc->clock));
415 	printf("    Bus Width:   %dbit\n", mmc->bus_width);
416 	printf("    Mode:        %s\n", mmc->strobe_enhanced ? "HS400ES" :
417 			mmc->selected_mode == MMC_HS_400 ? "HS400" :
418 			mmc->selected_mode == MMC_HS_200 ? "HS200" : "HS");
419 }
420 
hisi_mmc_init(int dev_num)421 int hisi_mmc_init(int dev_num)
422 {
423 	struct mmc *mmc = find_mmc_device(dev_num);
424 	int ret;
425 
426 	if (mmc == NULL) {
427 		printf("mmc device not found!!\n");
428 		return -EINVAL;
429 	}
430 
431 #if defined(CONFIG_TARGET_HI3531DV200) || defined(CONFIG_TARGET_HI3535AV100) || \
432 	defined(CONFIG_TARGET_HI3521DV200) || defined(CONFIG_TARGET_HI3520DV500)
433 	mmc->dev_num = dev_num;
434 	mmc->ocr_from_bootrom = dev_num == 0 ? get_ocr_from_bootrom() : 0;
435 	writel(0, REG_SAVE_HCS); /* clear flag reg */
436 	printf("mmc->ocr_from_bootrom 0x%08x\n", mmc->ocr_from_bootrom);
437 #endif
438 	ret = mmc_init(mmc);
439 	if (ret)
440 		return ret;
441 
442 	if (!IS_SD(mmc)) {
443 		print_mmcinfo(mmc);
444 		return mmc_set_boot_config(mmc);
445 	}
446 
447 	return 0;
448 }
449 
printf_mmc(int dev_num)450 void printf_mmc(int dev_num)
451 {
452 	struct mmc *mmc = find_mmc_device(dev_num);
453 
454 	if (mmc != NULL)
455 		print_mmcinfo(mmc);
456 }
457