• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 * Sunxi SD/MMC host driver
3 *
4 * Copyright (C) 2015 AllWinnertech Ltd.
5 * Author: lixiang <lixiang@allwinnertech>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 *
11 * This program is distributed "as is" WITHOUT ANY WARRANTY of any
12 * kind, whether express or implied; without even the implied warranty
13 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 * GNU General Public License for more details.
15 */
16 
17 
18 #include <linux/clk.h>
19 #include <linux/reset/sunxi.h>
20 
21 #include <linux/gpio.h>
22 #include <linux/platform_device.h>
23 #include <linux/spinlock.h>
24 #include <linux/scatterlist.h>
25 #include <linux/dma-mapping.h>
26 #include <linux/slab.h>
27 #include <linux/reset.h>
28 
29 #include <linux/of_address.h>
30 #include <linux/of_gpio.h>
31 #include <linux/of_platform.h>
32 #include <linux/stat.h>
33 
34 #include <linux/mmc/core.h>
35 #include <linux/mmc/host.h>
36 #include "sunxi-mmc.h"
37 #include "sunxi-mmc-debug.h"
38 #include "sunxi-mmc-export.h"
39 #include "sunxi-mmc-sun50iw1p1-2.h"
40 #include "sunxi-mmc-panic.h"
41 
42 
43 #define GPIO_BASE_ADDR	0x1c20800
44 /*nc platform no use these value*/
45 #define CCMU_BASE_ADDR_BEFORE_V2P1H	0x1c20000
46 
47 #define SUNXI_MMC_MAX_HOST_PRT_ADDR  0x150
48 #define SUNXI_MMC_MAX_GPIO_PRT_ADDR	0x120
49 #define SUNXI_GPIOIC_PRT_EADDR	0x380
50 #define SUNXI_GPIOIC_PRT_SADDR	0x200
51 
52 /*mmc bus clock gating register*/
53 #define SUNXI_BCLKG_SADDR  0x60
54 #define SUNXI_BCLKG_EADDR	0x80
55 
56 /*mmc moudule clock register*/
57 #define SUNXI_CLK_PRT_SADDR  0x80
58 #define SUNXI_CLK_PRT_EADDR	0xa0
59 
60 /*mmc bus soft reset register*/
61 #define SUNXI_BSRES_SADDR  0x2C0
62 #define SUNXI_BSRES_EADDR	0x2DC
63 
64 
65 /*NC mmc bus gating,reset,moudule clouck register*/
66 #define SUNXI_NCCM_EADDR	0x850
67 #define SUNXI_NCCM_SADDR	0x830
68 
69 /*NC mmc PLL PERI register*/
70 #define SUNXI_PP_NCM_EADDR	0x2C
71 #define SUNXI_PP_NCM_SADDR	0x20
72 
73 #define SUNXI_DEG_MAX_MAP_REG	0x900
74 
75 static struct device_attribute dump_register[3];
76 
sunxi_mmc_dumphex32(struct sunxi_mmc_host * host,char * name,char * base,int len)77 void sunxi_mmc_dumphex32(struct sunxi_mmc_host *host, char *name, char *base,
78 			 int len)
79 {
80 	u32 i;
81 
82 	pr_cont("dump %s registers:", name);
83 	for (i = 0; i < len; i += 4) {
84 		if (!(i&0xf))
85 			pr_cont("\n0x%px : ", base + i);
86 		pr_cont("0x%08x ", __raw_readl(base+i));
87 	}
88 	pr_cont("\n");
89 }
90 
sunxi_mmc_dump_des(struct sunxi_mmc_host * host,char * base,int len)91 void sunxi_mmc_dump_des(struct sunxi_mmc_host *host, char *base, int len)
92 {
93 	u32 i;
94 
95 	pr_cont("dump des mem\n");
96 	for (i = 0; i < len; i += 4) {
97 		if (!(i&0xf))
98 			pr_cont("\n0x%px : ", base + i);
99 		pr_cont("0x%08x ", *(u32 *)(base+i));
100 	}
101 	pr_cont("\n");
102 }
103 
sunxi_mmc_get_rate(uint64_t bytes,uint64_t time_us)104 static unsigned int sunxi_mmc_get_rate(uint64_t bytes, uint64_t time_us)
105 {
106 	uint64_t ns;
107 
108 	ns = time_us * 1000;
109 	bytes *= 1000000000;
110 
111 	while (ns > UINT_MAX) {
112 		bytes >>= 1;
113 		ns >>= 1;
114 	}
115 
116 	if (!ns)
117 		return 0;
118 
119 	do_div(bytes, (uint32_t)ns);
120 
121 	return bytes;
122 }
123 
sunxi_mmc_filter_rate(struct sunxi_mmc_host * host,struct mmc_data * data,int64_t bytes,uint64_t time_us)124 static void sunxi_mmc_filter_rate(struct sunxi_mmc_host *host, struct mmc_data *data, int64_t bytes, uint64_t time_us)
125 {
126 	unsigned int rate = 0;
127 
128 	if (!(host->filter_sector)
129 		|| !(host->filter_speed))
130 		return;
131 
132 	if ((data->blocks) >= (host->filter_sector)) {
133 		rate = sunxi_mmc_get_rate(bytes, time_us);
134 		if (rate < (host->filter_speed))
135 			printk("c=%u,a=0x%8x,""bs=%5u,""t=%9lluus,""sp=%7uKB/s\n",
136 			data->mrq->cmd->opcode, data->mrq->cmd->arg,
137 			data->blocks, time_us, rate/1024);
138 	}
139 }
140 
141 
maual_insert_show(struct device * dev,struct device_attribute * attr,char * buf)142 static ssize_t maual_insert_show(struct device *dev,
143 				 struct device_attribute *attr, char *buf)
144 {
145 	int ret;
146 
147 	ret =
148 	    snprintf(buf, PAGE_SIZE,
149 		     "Usage: \"echo 1 > insert\" to scan card\n");
150 	return ret;
151 }
152 
maual_insert_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)153 static ssize_t maual_insert_store(struct device *dev,
154 				  struct device_attribute *attr,
155 				  const char *buf, size_t count)
156 {
157 	int ret;
158 
159 	unsigned long insert = 0;
160 	struct platform_device *pdev = to_platform_device(dev);
161 	struct mmc_host *mmc = platform_get_drvdata(pdev);
162 
163 	ret = kstrtoul(buf, 0, &insert);
164 	if (ret) {
165 		ret = -EINVAL;
166 		return ret;
167 	}
168 
169 	SM_INFO(dev, "insert %ld\n", insert);
170 	if (insert)
171 		mmc_detect_change(mmc, 0);
172 	else
173 		SM_INFO(dev, "no detect change\n");
174 
175 	ret = count;
176 	return ret;
177 }
178 
sunxi_mmc_res_start_addr(const char * const res_str,resource_size_t * res_addr)179 int sunxi_mmc_res_start_addr(const char * const res_str,
180 		resource_size_t *res_addr)
181 {
182 	struct device_node *np = NULL;
183 	int ret = 0;
184 	struct resource res;
185 
186 	if (res_str == NULL || res_addr == NULL) {
187 		pr_err("input arg is error\n");
188 		return -EINVAL;
189 	}
190 
191 	np = of_find_node_by_type(NULL, res_str);
192 	if (IS_ERR(np)) {
193 		pr_err("Can not find device type\n");
194 		return -EINVAL;
195 	}
196 
197 	ret = of_address_to_resource(np, 0, &res);
198 	if (ret || !res.start) {
199 		pr_err("Can not find resouce\n");
200 		return -EINVAL;
201 	}
202 	*res_addr = res.start;
203 
204 	return 0;
205 }
206 
sunxi_dump_reg(struct mmc_host * mmc)207 void sunxi_dump_reg(struct mmc_host *mmc)
208 {
209 	int i = 0;
210 	struct sunxi_mmc_host *host = mmc_priv(mmc);
211 	int ret = 0;
212 	void __iomem *gpio_ptr =  NULL;
213 	void __iomem *ccmu_ptr =  NULL;
214 	resource_size_t res_saddr_ccmu;
215 	resource_size_t res_saddr_gpio;
216 
217 
218 	pr_cont("Dump %s (p%x) regs :\n", mmc_hostname(mmc), host->phy_index);
219 	for (i = 0; i < SUNXI_MMC_MAX_HOST_PRT_ADDR; i += 4) {
220 		if (!(i&0xf))
221 			pr_cont("\n0x%px : ", (host->reg_base + i));
222 		pr_cont("%08x ", readl(host->reg_base + i));
223 	}
224 	pr_cont("\n");
225 
226 	ret = sunxi_mmc_res_start_addr("pio", &res_saddr_gpio);
227 	if (ret < 0)
228 		goto map_ccmu;
229 	gpio_ptr = ioremap(res_saddr_gpio, SUNXI_DEG_MAX_MAP_REG);
230 	if (gpio_ptr == NULL) {
231 		pr_err("Can not map gpio resource\n");
232 		goto map_ccmu;
233 	}
234 
235 	pr_cont("Dump gpio regs:\n");
236 	for (i = 0; i < SUNXI_MMC_MAX_GPIO_PRT_ADDR; i += 4) {
237 		if (!(i&0xf))
238 			pr_cont("\n0x%px : ", (gpio_ptr + i));
239 		pr_cont("%08x ", readl(gpio_ptr + i));
240 	}
241 	pr_cont("\n");
242 
243 	pr_cont("Dump gpio irqc regs:\n");
244 	for (i = SUNXI_GPIOIC_PRT_SADDR; i < SUNXI_GPIOIC_PRT_EADDR; i += 4) {
245 		if (!(i&0xf))
246 			pr_cont("\n0x%px : ", (gpio_ptr + i));
247 		pr_cont("%08x ", readl(gpio_ptr + i));
248 	}
249 	pr_cont("\n");
250 
251 	iounmap(gpio_ptr);
252 
253 map_ccmu:
254 	ret = sunxi_mmc_res_start_addr("clocks", &res_saddr_ccmu);
255 	if (ret < 0)
256 		return;
257 	ccmu_ptr = ioremap(res_saddr_ccmu, SUNXI_DEG_MAX_MAP_REG);
258 	if (ccmu_ptr == NULL) {
259 		pr_err("Can not map ccmu resource\n");
260 		return;
261 	}
262 
263 	if (res_saddr_ccmu == CCMU_BASE_ADDR_BEFORE_V2P1H) {
264 		pr_cont("Dump ccmu regs:gating\n");
265 		for (i = SUNXI_BCLKG_SADDR; i < SUNXI_BCLKG_EADDR; i += 4) {
266 			if (!(i&0xf))
267 				pr_cont("\n0x%px : ", (ccmu_ptr + i));
268 			pr_cont("%08x ", readl(ccmu_ptr + i));
269 		}
270 		pr_cont("\n");
271 
272 		pr_cont("Dump ccmu regs:module clk\n");
273 		for (i = SUNXI_CLK_PRT_SADDR; i < SUNXI_CLK_PRT_EADDR; i += 4) {
274 			if (!(i&0xf))
275 				pr_cont("\n0x%px : ", (ccmu_ptr + i));
276 			pr_cont("%08x ", readl(ccmu_ptr + i));
277 		}
278 		pr_cont("\n");
279 
280 		pr_cont("Dump ccmu regs:reset\n");
281 		for (i = SUNXI_BSRES_SADDR; i < SUNXI_BSRES_EADDR; i += 4) {
282 			if (!(i&0xf))
283 				pr_cont("\n0x%px : ", (ccmu_ptr + i));
284 			pr_cont("%08x ", readl(ccmu_ptr + i));
285 		}
286 		pr_cont("\n");
287 	} else {
288 		pr_cont("Dump ccmu regs:pll,gating,reset,module clk\n");
289 
290 		for (i = SUNXI_PP_NCM_SADDR; i < SUNXI_PP_NCM_EADDR; i += 4) {
291 			if (!(i&0xf))
292 				pr_cont("\n0x%px : ", (ccmu_ptr + i));
293 			pr_cont("%08x ", readl(ccmu_ptr + i));
294 		}
295 		pr_cont("\n");
296 
297 		for (i = SUNXI_NCCM_SADDR; i < SUNXI_NCCM_EADDR; i += 4) {
298 			if (!(i&0xf))
299 				pr_cont("\n0x%px : ", (ccmu_ptr + i));
300 			pr_cont("%08x ", readl(ccmu_ptr + i));
301 		}
302 		pr_cont("\n");
303 	}
304 
305 	iounmap(ccmu_ptr);
306 
307 }
308 
309 
310 
sunxi_remap_writel(resource_size_t phy_addr,u32 val)311 int sunxi_remap_writel(resource_size_t  phy_addr, u32 val)
312 {
313 	void __iomem *v_addr =  NULL;
314 
315 	v_addr = ioremap(phy_addr, 8);
316 	if (v_addr == NULL) {
317 		pr_err("Can not map addr %x resource\n", (unsigned int)phy_addr);
318 		return -EIO;
319 	}
320 	writel(val, v_addr);
321 	printk("addr %x, val %x\n", (unsigned int)phy_addr, readl(v_addr));
322 
323 	iounmap(v_addr);
324 	return 0;
325 }
326 
327 
sunxi_remap_readl(resource_size_t phy_addr,u32 * pval)328 int sunxi_remap_readl(resource_size_t  phy_addr, u32 *pval)
329 {
330 	void __iomem *v_addr =  NULL;
331 
332 	v_addr = ioremap(phy_addr, 8);
333 	if (v_addr == NULL) {
334 		pr_err("Can not map %x resource\n", (unsigned int)phy_addr);
335 		return -EIO;
336 	}
337 
338 	*pval = readl(v_addr);
339 	printk("addr %x val %x\n", (unsigned int)phy_addr, readl(v_addr));
340 
341 	iounmap(v_addr);
342 	return 0;
343 }
344 
345 
346 
347 
dump_host_reg_show(struct device * dev,struct device_attribute * attr,char * buf)348 static ssize_t dump_host_reg_show(struct device *dev,
349 				  struct device_attribute *attr, char *buf)
350 {
351 	char *p = buf;
352 	int i = 0;
353 	struct platform_device *pdev = to_platform_device(dev);
354 	struct mmc_host *mmc = platform_get_drvdata(pdev);
355 	struct sunxi_mmc_host *host = mmc_priv(mmc);
356 
357 	p += sprintf(p, "Dump sdmmc regs:\n");
358 	for (i = 0; i < SUNXI_MMC_MAX_HOST_PRT_ADDR; i += 4) {
359 		if (!(i&0xf))
360 			p += sprintf(p, "\n0x%lx : ", (size_t)(host->reg_base + i));
361 		p += sprintf(p, "%08x ", readl(host->reg_base + i));
362 	}
363 	p += sprintf(p, "\n");
364 
365 	return p - buf;
366 
367 }
368 
dump_gpio_reg_show(struct device * dev,struct device_attribute * attr,char * buf)369 static ssize_t dump_gpio_reg_show(struct device *dev,
370 				  struct device_attribute *attr, char *buf)
371 {
372 	char *p = buf;
373 	int i = 0;
374 	void __iomem *gpio_ptr =  NULL;
375 	resource_size_t res_saddr_gpio;
376 	int ret = 0;
377 
378 	ret = sunxi_mmc_res_start_addr("pio", &res_saddr_gpio);
379 	if (ret < 0)
380 		goto out;
381 
382 	gpio_ptr = ioremap(res_saddr_gpio, SUNXI_DEG_MAX_MAP_REG);
383 	if (!gpio_ptr) {
384 		pr_err("Can not map gpio resource\n");
385 		goto out;
386 	}
387 
388 	p += sprintf(p, "Dump gpio regs:\n");
389 	for (i = 0; i < SUNXI_MMC_MAX_GPIO_PRT_ADDR; i += 4) {
390 		if (!(i&0xf))
391 			p += sprintf(p, "\n0x%lx : ", (size_t)(gpio_ptr + i));
392 		p += sprintf(p, "%08x ", readl(gpio_ptr + i));
393 	}
394 	p += sprintf(p, "\n");
395 
396 	p += sprintf(p, "Dump gpio irqc regs:\n");
397 	for (i = SUNXI_GPIOIC_PRT_SADDR; i < SUNXI_GPIOIC_PRT_EADDR; i += 4) {
398 		if (!(i&0xf))
399 			p += sprintf(p, "\n0x%lx : ", (size_t) (gpio_ptr + i));
400 		p += sprintf(p, "%08x ", readl(gpio_ptr + i));
401 	}
402 	p += sprintf(p, "\n");
403 
404 	iounmap(gpio_ptr);
405 out:
406 	return p-buf;
407 
408 }
409 
dump_ccmu_reg_show(struct device * dev,struct device_attribute * attr,char * buf)410 static ssize_t dump_ccmu_reg_show(struct device *dev,
411 				  struct device_attribute *attr, char *buf)
412 {
413 	char *p = buf;
414 	int i = 0;
415 	void __iomem *ccmu_ptr =  NULL;
416 	int ret = 0;
417 	resource_size_t res_saddr_ccmu;
418 
419 	ret = sunxi_mmc_res_start_addr("clocks", &res_saddr_ccmu);
420 	if (ret < 0)
421 		goto out;
422 
423 	ccmu_ptr = ioremap(res_saddr_ccmu, SUNXI_DEG_MAX_MAP_REG);
424 	if (!ccmu_ptr) {
425 		pr_err("Can not map ccmu resource\n");
426 		goto out;
427 	}
428 
429 	p += sprintf(p, "Dump ccmu\n");
430 	if (res_saddr_ccmu == CCMU_BASE_ADDR_BEFORE_V2P1H) {
431 
432 		p += sprintf(p, "Dump ccmu regs:gating\n");
433 		for (i = SUNXI_BCLKG_SADDR; i < SUNXI_BCLKG_EADDR; i += 4) {
434 			if (!(i&0xf))
435 				p += sprintf(p, "\n0x%lx : ", (size_t)(ccmu_ptr + i));
436 			p += sprintf(p, "%08x ", readl(ccmu_ptr + i));
437 		}
438 		p += sprintf(p, "\n");
439 
440 		p += sprintf(p, "Dump ccmu regs:module clk\n");
441 		for (i = SUNXI_CLK_PRT_SADDR; i < SUNXI_CLK_PRT_EADDR; i += 4) {
442 			if (!(i&0xf))
443 				p += sprintf(p, "\n0x%lx : ", (size_t)(ccmu_ptr + i));
444 			p += sprintf(p, "%08x ", readl(ccmu_ptr + i));
445 		}
446 		p += sprintf(p, "\n");
447 
448 		p += sprintf(p, "Dump ccmu regs:reset\n");
449 		for (i = SUNXI_BSRES_SADDR; i < SUNXI_BSRES_EADDR; i += 4) {
450 			if (!(i&0xf))
451 				p += sprintf(p, "\n0x%lx : ", (size_t)(ccmu_ptr + i));
452 			p += sprintf(p, "%08x ", readl(ccmu_ptr + i));
453 		}
454 		p += sprintf(p, "\n");
455 
456 	} else {
457 		p += sprintf(p, "Dump ccmu regs:pll,gating,reset,module clk\n");
458 
459 		for (i = SUNXI_PP_NCM_SADDR; i < SUNXI_PP_NCM_EADDR; i += 4) {
460 			if (!(i&0xf))
461 				p += sprintf(p, "\n0x%lx : ", (size_t)(ccmu_ptr + i));
462 			p += sprintf(p, "%08x ", readl(ccmu_ptr + i));
463 		}
464 		p += sprintf(p, "\n");
465 
466 		for (i = SUNXI_NCCM_SADDR; i < SUNXI_NCCM_EADDR; i += 4) {
467 			if (!(i&0xf))
468 				p += sprintf(p, "\n0x%lx : ", (size_t)(ccmu_ptr + i));
469 			p += sprintf(p, "%08x ", readl(ccmu_ptr + i));
470 		}
471 		p += sprintf(p, "\n");
472 	}
473 	p += sprintf(p, "\n");
474 
475 	iounmap(ccmu_ptr);
476 
477 out:
478 	return p-buf;
479 
480 }
481 
dump_clk_dly_show(struct device * dev,struct device_attribute * attr,char * buf)482 static ssize_t dump_clk_dly_show(struct device *dev,
483 				 struct device_attribute *attr, char *buf)
484 {
485 	char *p = buf;
486 	struct platform_device *pdev = to_platform_device(dev);
487 	struct mmc_host *mmc = platform_get_drvdata(pdev);
488 	struct sunxi_mmc_host *host = mmc_priv(mmc);
489 
490 	if (host->sunxi_mmc_dump_dly_table)
491 		host->sunxi_mmc_dump_dly_table(host);
492 	else
493 		SM_WARN(mmc_dev(mmc), "not found the dump dly table\n");
494 
495 	return p - buf;
496 }
497 
sunxi_mmc_uperf_stat(struct sunxi_mmc_host * host,struct mmc_data * data,struct mmc_request * mrq_busy,bool bhalf)498 int sunxi_mmc_uperf_stat(struct sunxi_mmc_host *host,
499 	struct mmc_data *data,
500 	struct mmc_request *mrq_busy,
501 	bool bhalf)
502 {
503 	ktime_t diff;
504 
505 	if (!bhalf) {
506 		if (host->perf_enable && data) {
507 			diff = ktime_sub(ktime_get(), host->perf.start);
508 			if (data->flags & MMC_DATA_READ) {
509 				host->perf.rbytes += data->bytes_xfered;
510 				host->perf.rtime =
511 					ktime_add(host->perf.rtime, diff);
512 			} else if (data->flags & MMC_DATA_WRITE) {
513 				if (!mrq_busy) {
514 					host->perf.wbytes +=
515 						data->bytes_xfered;
516 					host->perf.wtime =
517 					ktime_add(host->perf.wtime, diff);
518 					sunxi_mmc_filter_rate(host, data, data->bytes_xfered, ktime_to_us(diff));
519 				}
520 				host->perf.wbytestran += data->bytes_xfered;
521 				host->perf.wtimetran =
522 					ktime_add(host->perf.wtimetran, diff);
523 			}
524 		}
525 	} else {
526 		if (host->perf_enable
527 			&& mrq_busy->data
528 			&& (mrq_busy->data->flags & MMC_DATA_WRITE)) {
529 			diff = ktime_sub(ktime_get(), host->perf.start);
530 			host->perf.wbytes += mrq_busy->data->bytes_xfered;
531 			host->perf.wtime = ktime_add(host->perf.wtime, diff);
532 			sunxi_mmc_filter_rate(host, data, data->bytes_xfered, ktime_to_us(diff));
533 		}
534 	}
535 	return 0;
536 }
537 EXPORT_SYMBOL_GPL(sunxi_mmc_uperf_stat);
538 
539 static ssize_t
sunxi_mmc_show_perf(struct device * dev,struct device_attribute * attr,char * buf)540 sunxi_mmc_show_perf(struct device *dev, struct device_attribute *attr, char *buf)
541 {
542 	struct platform_device *pdev = to_platform_device(dev);
543 	struct mmc_host	*mmc = platform_get_drvdata(pdev);
544 	struct sunxi_mmc_host *host = mmc_priv(mmc);
545 	int64_t rtime_drv, wtime_drv, wtime_drv_tran;
546 	int64_t rbytes_drv, wbytes_drv, wbytes_drv_tran;
547 
548 
549 	mmc_claim_host(mmc);
550 
551 	rbytes_drv = host->perf.rbytes;
552 	wbytes_drv = host->perf.wbytes;
553 	wbytes_drv_tran = host->perf.wbytestran;
554 
555 	rtime_drv = ktime_to_us(host->perf.rtime);
556 	wtime_drv = ktime_to_us(host->perf.wtime);
557 	wtime_drv_tran = ktime_to_us(host->perf.wtimetran);
558 
559 	mmc_release_host(mmc);
560 
561 	return snprintf(buf, PAGE_SIZE, "Write performance at host driver Level:"
562 					"%lld bytes in %lld microseconds\n"
563 					"Read performance at host driver Level:"
564 					"%lld bytes in %lld microseconds\n"
565 					"write performance at host driver Level(no wait busy):"
566 					"%lld bytes in %lld microseconds\n",
567 					wbytes_drv, wtime_drv,
568 					rbytes_drv, rtime_drv,
569 					wbytes_drv_tran, wtime_drv_tran);
570 }
571 
572 static ssize_t
sunxi_mmc_set_perf(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)573 sunxi_mmc_set_perf(struct device *dev, struct device_attribute *attr,
574 		const char *buf, size_t count)
575 {
576 	struct platform_device *pdev = to_platform_device(dev);
577 	struct mmc_host	*mmc = platform_get_drvdata(pdev);
578 	struct sunxi_mmc_host *host = mmc_priv(mmc);
579 	int64_t value;
580 
581 	sscanf(buf, "%lld", &value);
582 	printk("set perf value %lld\n", value);
583 
584 	mmc_claim_host(mmc);
585 	if (!value) {
586 		memset(&host->perf, 0, sizeof(host->perf));
587 		host->perf_enable = false;
588 	} else {
589 		host->perf_enable = true;
590 	}
591 	mmc_release_host(mmc);
592 
593 	return count;
594 }
595 
596 extern void sunxi_mmc_set_ds_dl_raw(struct sunxi_mmc_host *host, int sunxi_ds_dl);
597 extern void sunxi_mmc_set_samp_dl_raw(struct sunxi_mmc_host *host, int sunxi_samp_dl);
598 
599 int sunxi_mmc_bus_clk_en(struct sunxi_mmc_host *host, int enable);
600 void sunxi_mmc_regs_save(struct sunxi_mmc_host *host);
601 void sunxi_mmc_regs_restore(struct sunxi_mmc_host *host);
602 
603 static ssize_t
sunxi_mmc_set_samp_dly_sys(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)604 sunxi_mmc_set_samp_dly_sys(struct device *dev, struct device_attribute *attr,
605 				const char *buf, size_t count)
606 {
607 	struct platform_device *pdev = to_platform_device(dev);
608 	struct mmc_host	*mmc = platform_get_drvdata(pdev);
609 	struct sunxi_mmc_host *host = mmc_priv(mmc);
610 	int64_t value;
611 
612 	sscanf(buf, "%lld", &value);
613 	printk("set sample delay %lld\n", value);
614 	mmc_claim_host(mmc);
615 	sunxi_mmc_set_samp_dl_raw(host, value);
616 	mmc_release_host(mmc);
617 
618 	return count;
619 }
620 
621 static ssize_t
sunxi_mmc_set_ds_dly_sys(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)622 sunxi_mmc_set_ds_dly_sys(struct device *dev, struct device_attribute *attr,
623 				const char *buf, size_t count)
624 {
625 	struct platform_device *pdev = to_platform_device(dev);
626 	struct mmc_host	*mmc = platform_get_drvdata(pdev);
627 	struct sunxi_mmc_host *host = mmc_priv(mmc);
628 	int64_t value;
629 
630 	sscanf(buf, "%lld", &value);
631 	printk("set ds delay %lld\n", value);
632 	mmc_claim_host(mmc);
633 	sunxi_mmc_set_ds_dl_raw(host, value);
634 	mmc_release_host(mmc);
635 
636 	return count;
637 }
638 
639 static ssize_t
sunxi_mmc_send_status(struct device * dev,struct device_attribute * attr,char * buf)640 sunxi_mmc_send_status(struct device *dev, struct device_attribute *attr, char *buf)
641 {
642 	struct platform_device *pdev = to_platform_device(dev);
643 	struct mmc_host	*mmc = platform_get_drvdata(pdev);
644 	u32 status = 0;
645 
646 	mmc_claim_host(mmc);
647 	mmc_send_status(mmc->card, &status);
648 	printk("mmc status %x\n", status);
649 	mmc_release_host(mmc);
650 
651 	return (ssize_t)buf;
652 }
653 
654 static ssize_t
sunxi_mmc_show_filter_sector(struct device * dev,struct device_attribute * attr,char * buf)655 sunxi_mmc_show_filter_sector(struct device *dev, struct device_attribute *attr, char *buf)
656 {
657 	struct platform_device *pdev = to_platform_device(dev);
658 	struct mmc_host	*mmc = platform_get_drvdata(pdev);
659 	struct sunxi_mmc_host *host = mmc_priv(mmc);
660 
661 	return snprintf(buf, PAGE_SIZE, "filter speed %d\n", host->filter_sector);
662 }
663 
664 static ssize_t
sunxi_mmc_set_filter_sector(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)665 sunxi_mmc_set_filter_sector(struct device *dev, struct device_attribute *attr,
666 		const char *buf, size_t count)
667 {
668 	struct platform_device *pdev = to_platform_device(dev);
669 	struct mmc_host	*mmc = platform_get_drvdata(pdev);
670 	struct sunxi_mmc_host *host = mmc_priv(mmc);
671 	int64_t value;
672 
673 	sscanf(buf, "%lld", &value);
674 	printk("get filter sector %lld\n", value);
675 	host->filter_sector = value;
676 
677 	return count;
678 }
679 
680 #ifdef CONFIG_AW_MMC_DEBUG
681 static ssize_t
sunxi_mmc_show_dbglevel(struct device * dev,struct device_attribute * attr,char * buf)682 sunxi_mmc_show_dbglevel(struct device *dev, struct device_attribute *attr, char *buf)
683 {
684 	struct platform_device *pdev = to_platform_device(dev);
685 	struct mmc_host	*mmc = platform_get_drvdata(pdev);
686 	struct sunxi_mmc_host *host = mmc_priv(mmc);
687 
688 	return snprintf(buf, PAGE_SIZE, "Current debuglevel %d\n", host->debuglevel);
689 }
690 
691 static ssize_t
sunxi_mmc_set_dbglevel(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)692 sunxi_mmc_set_dbglevel(struct device *dev, struct device_attribute *attr,
693 		const char *buf, size_t count)
694 {
695 	struct platform_device *pdev = to_platform_device(dev);
696 	struct mmc_host	*mmc = platform_get_drvdata(pdev);
697 	struct sunxi_mmc_host *host = mmc_priv(mmc);
698 	int64_t value;
699 
700 	sscanf(buf, "%lld", &value);
701 	printk("set debug level %lld\n", value);
702 	host->debuglevel = value;
703 
704 	return count;
705 }
706 #endif
707 
708 
709 static ssize_t
sunxi_mmc_show_filter_speed(struct device * dev,struct device_attribute * attr,char * buf)710 sunxi_mmc_show_filter_speed(struct device *dev, struct device_attribute *attr, char *buf)
711 {
712 	struct platform_device *pdev = to_platform_device(dev);
713 	struct mmc_host	*mmc = platform_get_drvdata(pdev);
714 	struct sunxi_mmc_host *host = mmc_priv(mmc);
715 
716 	return snprintf(buf, PAGE_SIZE, "filter speed %d\n", host->filter_speed);
717 }
718 
719 static ssize_t
sunxi_mmc_set_filter_speed(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)720 sunxi_mmc_set_filter_speed(struct device *dev, struct device_attribute *attr,
721 		const char *buf, size_t count)
722 {
723 	struct platform_device *pdev = to_platform_device(dev);
724 	struct mmc_host	*mmc = platform_get_drvdata(pdev);
725 	struct sunxi_mmc_host *host = mmc_priv(mmc);
726 	int64_t value;
727 
728 	sscanf(buf, "%lld", &value);
729 	printk("get filter speed %lld\n", value);
730 	host->filter_speed = value;
731 
732 	return count;
733 }
734 
735 
736 
737 
738 
mmc_create_sys_fs(struct sunxi_mmc_host * host,struct platform_device * pdev)739 int mmc_create_sys_fs(struct sunxi_mmc_host *host, struct platform_device *pdev)
740 {
741 	int ret;
742 
743 	host->maual_insert.show = maual_insert_show;
744 	host->maual_insert.store = maual_insert_store;
745 	sysfs_attr_init(&(host->maual_insert.attr));
746 	host->maual_insert.attr.name = "sunxi_insert";
747 	host->maual_insert.attr.mode = S_IRUGO | S_IWUSR;
748 	ret = device_create_file(&pdev->dev, &host->maual_insert);
749 	if (ret)
750 		return ret;
751 
752 	host->host_perf.show = sunxi_mmc_show_perf;
753 	host->host_perf.store = sunxi_mmc_set_perf;
754 	sysfs_attr_init(&(host->host_perf.attr));
755 	host->host_perf.attr.mode = S_IRUGO | S_IWUSR;
756 	host->host_perf.attr.name = "sunxi_host_perf";
757 	ret = device_create_file(&pdev->dev, &host->host_perf);
758 	if (ret)
759 		return ret;
760 
761 	host->filter_sector_perf.show = sunxi_mmc_show_filter_sector;
762 	host->filter_sector_perf.store = sunxi_mmc_set_filter_sector;
763 	sysfs_attr_init(&(host->filter_sector_perf.attr));
764 	host->filter_sector_perf.attr.name = "sunxi_host_filter_w_sector";
765 	host->filter_sector_perf.attr.mode = S_IRUGO | S_IWUSR;
766 	ret = device_create_file(&pdev->dev, &host->filter_sector_perf);
767 	if (ret)
768 		return ret;
769 
770 	host->filter_speed_perf.show = sunxi_mmc_show_filter_speed;;
771 	host->filter_speed_perf.store = sunxi_mmc_set_filter_speed;;
772 	sysfs_attr_init(&(host->filter_speed_perf.attr));
773 	host->filter_speed_perf.attr.name = "sunxi_host_filter_w_speed";
774 	host->filter_speed_perf.attr.mode = S_IRUGO | S_IWUSR;
775 	ret = device_create_file(&pdev->dev, &host->filter_speed_perf);
776 	if (ret)
777 		return ret;
778 
779 
780 	host->dump_register = dump_register;
781 	host->dump_register[0].show = dump_host_reg_show;
782 	sysfs_attr_init(&(host->dump_register[0].attr));
783 	host->dump_register[0].attr.name = "sunxi_dump_host_register";
784 	host->dump_register[0].attr.mode = S_IRUGO;
785 	ret = device_create_file(&pdev->dev, &host->dump_register[0]);
786 	if (ret)
787 		return ret;
788 
789 	host->dump_register[1].show = dump_gpio_reg_show;
790 	sysfs_attr_init(&(host->dump_register[1].attr));
791 	host->dump_register[1].attr.name = "sunxi_dump_gpio_register";
792 	host->dump_register[1].attr.mode = S_IRUGO;
793 	ret = device_create_file(&pdev->dev, &host->dump_register[1]);
794 	if (ret)
795 		return ret;
796 
797 	host->dump_register[2].show = dump_ccmu_reg_show;
798 	sysfs_attr_init(&(host->dump_register[2].attr));
799 	host->dump_register[2].attr.name = "sunxi_dump_ccmu_register";
800 	host->dump_register[2].attr.mode = S_IRUGO;
801 	ret = device_create_file(&pdev->dev, &host->dump_register[2]);
802 	if (ret)
803 		return ret;
804 
805 	host->dump_clk_dly.show = dump_clk_dly_show;
806 	sysfs_attr_init(&(host->dump_clk_dly.attr));
807 	host->dump_clk_dly.attr.name = "sunxi_dump_clk_dly";
808 	host->dump_clk_dly.attr.mode = S_IRUGO;
809 	ret = device_create_file(&pdev->dev, &host->dump_clk_dly);
810 	if (ret)
811 		return ret;
812 
813 	host->host_sample_dly.show = NULL;
814 	host->host_sample_dly.store = sunxi_mmc_set_samp_dly_sys;
815 	sysfs_attr_init(&(host->host_sample_dly.attr));
816 	host->host_sample_dly.attr.name = "sunxi_host_set_sample_dly";
817 	host->host_sample_dly.attr.mode =  S_IWUSR;
818 	ret = device_create_file(&pdev->dev, &host->host_sample_dly);
819 	if (ret)
820 		return ret;
821 
822 	host->host_ds_dly.show = NULL;
823 	host->host_ds_dly.store = sunxi_mmc_set_ds_dly_sys;
824 	sysfs_attr_init(&(host->host_ds_dly.attr));
825 	host->host_ds_dly.attr.name = "sunxi_host_set_ds_dly";
826 	host->host_ds_dly.attr.mode =  S_IWUSR;
827 	ret = device_create_file(&pdev->dev, &host->host_ds_dly);
828 	if (ret)
829 		return ret;
830 
831 	host->host_send_status.show = sunxi_mmc_send_status;
832 	host->host_send_status.store = NULL;
833 	sysfs_attr_init(&(host->host_send_status.attr));
834 	host->host_send_status.attr.name = "sunxi_mmc_send_status";
835 	host->host_send_status.attr.mode =  S_IRUGO;
836 	ret = device_create_file(&pdev->dev, &host->host_send_status);
837 	if (ret)
838 		return ret;
839 #ifdef CONFIG_AW_MMC_DEBUG
840 	host->host_debuglevel.show = sunxi_mmc_show_dbglevel;
841 	host->host_debuglevel.store = sunxi_mmc_set_dbglevel;
842 	sysfs_attr_init(&(host->debuglevel.attr));
843 	host->host_debuglevel.attr.name = "sunxi_debug_level";
844 	host->host_debuglevel.attr.mode = S_IRUGO | S_IWUSR;
845 	ret = device_create_file(&pdev->dev, &host->host_debuglevel);
846 	if (ret)
847 		return ret;
848 #endif
849 
850 	host->host_mwr.show = sunxi_mmc_panic_rtest;
851 	host->host_mwr.store = sunxi_mmc_pancic_wrtest;
852 	sysfs_attr_init(&(host->host_mwr.attr));
853 	host->host_mwr.attr.name = "sunxi_host_panic_wr";
854 	host->host_mwr.attr.mode = S_IRUGO | S_IWUSR;
855 	ret = device_create_file(&pdev->dev, &host->host_mwr);
856 
857 	return ret;
858 }
859 EXPORT_SYMBOL_GPL(mmc_create_sys_fs);
860 
mmc_remove_sys_fs(struct sunxi_mmc_host * host,struct platform_device * pdev)861 void mmc_remove_sys_fs(struct sunxi_mmc_host *host,
862 		       struct platform_device *pdev)
863 {
864 	device_remove_file(&pdev->dev, &host->host_mwr);
865 	device_remove_file(&pdev->dev, &host->host_perf);
866 	device_remove_file(&pdev->dev, &host->maual_insert);
867 	device_remove_file(&pdev->dev, &host->dump_register[0]);
868 	device_remove_file(&pdev->dev, &host->dump_register[1]);
869 	device_remove_file(&pdev->dev, &host->dump_register[2]);
870 	device_remove_file(&pdev->dev, &host->dump_clk_dly);
871 	device_remove_file(&pdev->dev, &host->filter_sector_perf);
872 	device_remove_file(&pdev->dev, &host->filter_speed_perf);
873 	device_remove_file(&pdev->dev, &host->host_sample_dly);
874 	device_remove_file(&pdev->dev, &host->host_ds_dly);
875 	device_remove_file(&pdev->dev, &host->host_send_status);
876 }
877 EXPORT_SYMBOL_GPL(mmc_remove_sys_fs);
878