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