[Feature]add MT2731_MP2_MR2_SVN388 baseline version

Change-Id: Ief04314834b31e27effab435d3ca8ba33b499059
diff --git a/src/kernel/linux/v4.14/drivers/mmc/host/mtk-sdio-proc.c b/src/kernel/linux/v4.14/drivers/mmc/host/mtk-sdio-proc.c
new file mode 100644
index 0000000..a22845a
--- /dev/null
+++ b/src/kernel/linux/v4.14/drivers/mmc/host/mtk-sdio-proc.c
@@ -0,0 +1,468 @@
+/*
+ * Copyright (c) 2014-2015 MediaTek Inc.
+ * Author: Chaotian.Jing <chaotian.jing@mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/kthread.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/proc_fs.h>
+#include <linux/string.h>
+#include <linux/uaccess.h>
+#include <linux/vmalloc.h>
+#include <linux/fs.h>
+#include <linux/seq_file.h>
+#include <linux/slab.h>
+#include <linux/time.h>
+#include <linux/random.h>
+
+#include <linux/mmc/card.h>
+#include <linux/mmc/core.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/mmc.h>
+#include <linux/mmc/sd.h>
+#include <linux/mmc/sdio.h>
+#include <linux/mmc/sdio_func.h>
+
+#include "../core/core.h"
+
+enum {
+	Read = 0,
+	Write = 1,
+	Hqa_read = 2,
+	Hqa_write = 3,
+	Reset = 4,
+	Stress_read = 5,
+	Stress_write = 6,
+	SDIO_read_fix_Tput = 7,
+	SDIO_write_fix_Tput = 8,
+};
+
+static struct mmc_host *host_arry[3];
+static int max_id;
+
+/**
+ * define some count timer.
+ */
+#define KAL_TIME_INTERVAL_DECLARATION()  struct timeval __rTs, __rTe
+#define KAL_REC_TIME_START()             do_gettimeofday(&__rTs)
+#define KAL_REC_TIME_END()	             do_gettimeofday(&__rTe)
+#define KAL_GET_TIME_INTERVAL() \
+((__rTe.tv_sec * USEC_PER_SEC + __rTe.tv_usec) - \
+(__rTs.tv_sec * USEC_PER_SEC + __rTs.tv_usec))
+
+#define SDIO_XFER_SIZE 0x40000
+
+/**
+ * sdio_proc_show dispaly the common cccr and cis.
+ */
+static int sdio_proc_show(struct seq_file *m, void *v)
+{
+	seq_puts(m, "\n=========================================\n");
+	seq_puts(m, "read cmd format:\n");
+	seq_puts(m, "  echo hostid 0 0xReg 0xfunction > /proc/sdio\n");
+
+	seq_puts(m, "write cmd format:\n");
+	seq_puts(m, "  echo hostid 1 0xReg 0xfunction 0xvalue > /proc/sdio\n");
+
+	seq_puts(m, "multi read cmd format:\n");
+	seq_puts(m, "  echo hostid 2 0x13 0x0 > /proc/sdio\n");
+
+	seq_puts(m, "multi write cmd format:\n");
+	seq_puts(m, "  echo hostid 3 0x13 0x0 0xvalue > /proc/sdio\n");
+	seq_puts(m, "Notice:value is the read result!\n");
+
+	seq_puts(m, "reset sdio cmd format:\n");
+	seq_puts(m, "  echo hostid 4 0x0 0x0 > /proc/sdio\n");
+
+	seq_puts(m, "throughput read cmd format:\n");
+	seq_puts(m, "  echo hostid 5 0xb0 0x1 > /proc/sdio\n");
+
+	seq_puts(m, "throughtput write cmd format:\n");
+	seq_puts(m, "  echo hostid 6 0xb0 0x1 > /proc/sdio\n");
+
+	seq_puts(m, "target throughput read cmd format:\n");
+	seq_puts(m, "  echo hostid 7 0xb0 0x1 0xT-put 0xcount > /proc/sdio\n");
+
+	seq_puts(m, "target throughtput write cmd format:\n");
+	seq_puts(m, "  echo hostid 8 0xb0 0x1 0xT-put 0xcount > /proc/sdio\n");
+
+	seq_puts(m, "target throughtput write cmd format for desense (random pattern):\n");
+	seq_puts(m, "  echo hostid 8 0xb0 0x1 0xT-put 0xcount 0x1 > /proc/sdio\n");
+
+	seq_puts(m, "=========================================\n");
+
+	return 0;
+}
+
+/**
+ * sdio_proc_write - read/write sdio function register.
+ */
+static ssize_t sdio_proc_write(struct file *file, const char *buf,
+		size_t count, loff_t *f_pos)
+{
+	struct mmc_host *host;
+	struct mmc_card *card;
+	struct sdio_func *func = NULL;
+	struct mmc_ios *ios;
+	char *cmd_buf, *str_hand;
+	unsigned char *fac_buf = NULL;
+	unsigned int id, cmd, addr, fn, value = 0, hqa_result, offset = 0;
+	unsigned int extra = 0;
+	unsigned char result;
+	int i = 0, ret, usec_sleep;
+	unsigned long count_r = 0, total = 0;
+
+	KAL_TIME_INTERVAL_DECLARATION();
+	__kernel_suseconds_t usec, r_usec;
+
+	cmd_buf = kzalloc((count + 1), GFP_KERNEL);
+	if (!cmd_buf)
+		return count;
+
+	str_hand = kzalloc(2, GFP_KERNEL);
+	if (!str_hand) {
+		kfree(cmd_buf);
+		return count;
+	}
+
+	ret = copy_from_user(cmd_buf, buf, count);
+	if (ret < 0)
+		goto end;
+
+	*(cmd_buf + count) = '\0';
+	ret = sscanf(cmd_buf, "%x %x %x %x %x %x %x",
+			&id, &cmd, &addr, &fn, &value, &offset, &extra);
+	if (ret == 0) {
+		ret = sscanf(cmd_buf, "%s", str_hand);
+		if (ret == 0)
+			pr_info("please enter cmd.\n");
+
+		goto end;
+	}
+
+	if (id < max_id && id >= 0) {
+		host = host_arry[id];
+		if (!host) {
+			pr_info("host %d NULL\n", id);
+			goto end;
+		}
+	} else {
+		pr_info("host %d number is invalid, max(%d)\n",
+			id, max_id - 1);
+		goto end;
+	}
+
+	WARN_ON(!host);
+	ios = &host->ios;
+	card = host->card;
+
+	func = kzalloc(sizeof(struct sdio_func), GFP_KERNEL);
+	if (!func) {
+		kfree(cmd_buf);
+		kfree(str_hand);
+		return count;
+	}
+
+	/* Judge whether request fn is over the max functions. */
+	if (fn > card->sdio_funcs) {
+		dev_info(mmc_dev(host), "the fn is over the max sdio funcs.\n");
+		goto end;
+	}
+
+	if (fn) {
+		/**
+		 * The test read/write api don't need more func
+		 * information. So we just use the card & func->num
+		 * to the new struct func.
+		 */
+		if (card->sdio_func[fn - 1]) {
+			func->card = card;
+			func->num = card->sdio_func[fn - 1]->num;
+			func->tuples = card->sdio_func[fn - 1]->tuples;
+			func->tmpbuf = card->sdio_func[fn - 1]->tmpbuf;
+			hqa_result = card->sdio_func[fn - 1]->max_blksize;
+			func->max_blksize = hqa_result;
+			if ((cmd == Hqa_read) || (cmd == Hqa_write)) {
+				func->cur_blksize = 8;
+			} else if ((cmd == Stress_write) ||
+					(cmd == Stress_read) ||
+					(cmd == SDIO_read_fix_Tput) ||
+					(cmd == SDIO_write_fix_Tput)) {
+				func->cur_blksize = 0x200;
+				fac_buf = kmalloc(SDIO_XFER_SIZE, GFP_KERNEL);
+				if (!fac_buf) {
+					kfree(func);
+					goto end;
+				}
+				if (extra == 1) {
+					ret = wait_for_random_bytes();
+					if (ret)
+						dev_info(mmc_dev(host),
+						"wait random bytes fail.\n");
+					get_random_bytes(fac_buf,
+						SDIO_XFER_SIZE);
+				} else
+					memset(fac_buf, 0x5a, SDIO_XFER_SIZE);
+			} else {
+				func->cur_blksize = 1;
+			}
+		} else {
+			dev_info(mmc_dev(host), "func %d is null,.\n", fn);
+		}
+	} else {
+		/**
+		 * function 0 should not need struct func.
+		 * but the api need the parameter, so we create
+		 * the a new func for function 0.
+		 */
+		func->card = card;
+		func->tuples = card->tuples;
+		func->num = 0;
+		func->max_blksize = 16;
+		if ((cmd == Hqa_read) || (cmd == Hqa_write))
+			func->cur_blksize = 16;
+		else
+			func->cur_blksize = 1;
+
+		func->tmpbuf = kmalloc(func->cur_blksize, GFP_KERNEL);
+		if (!func->tmpbuf) {
+			kfree(func);
+			goto end;
+		}
+		memset(func->tmpbuf, 0, func->cur_blksize);
+	}
+
+	sdio_claim_host(func);
+
+	switch (cmd) {
+	case Read:
+		dev_info(mmc_dev(host), "read addr:%x, fn:%d.\n", addr, fn);
+		ret = 0;
+		if (fn == 0)
+			result = sdio_f0_readb(func, addr, &ret);
+		else
+			result = sdio_readb(func, addr, &ret);
+
+		if (ret)
+			dev_info(mmc_dev(host), "Read fail(%d).\n", ret);
+		else
+			dev_info(mmc_dev(host), "f%d reg(%x) is 0x%02x.\n",
+					func->num, addr, result);
+		break;
+	case Write:
+		dev_info(mmc_dev(host), "write addr:%x, value:%x, fn:%d.\n",
+				addr, (u8)value, fn);
+		ret = 0;
+		if (fn == 0)
+			/* (0xF0 - 0xFF) are permiited for func0 */
+			sdio_f0_writeb(func, (u8)value, addr, &ret);
+		else
+			sdio_writeb(func, (u8)value, addr, &ret);
+
+		if (ret)
+			dev_info(mmc_dev(host), "write fail(%d).\n", ret);
+		else
+			dev_info(mmc_dev(host), "write success(%d).\n", ret);
+
+		break;
+	case Hqa_read:
+		dev_info(mmc_dev(host), "read addr:%x, fn %d\n", addr, fn);
+		i = 0;
+		hqa_result = 0;
+		do {
+			ret = 0;
+			hqa_result = sdio_readl(func, addr, &ret);
+			if (ret)
+				dev_info(mmc_dev(host), "Read f%d reg(%x) fail(%d).\n",
+						func->num, addr, ret);
+			i = i + 1;
+		} while (i < 0x10000);
+		dev_info(mmc_dev(host), "Read result: 0x%02x.\n", hqa_result);
+		break;
+	case Hqa_write:
+		dev_info(mmc_dev(host), "write addr:%x, value:%x, fn %d\n",
+				addr, value, fn);
+		i = 0;
+		hqa_result = 0;
+		do {
+			ret = 0;
+			sdio_writel(func, value, addr, &ret);
+			if (ret)
+				dev_info(mmc_dev(host), "write f%d reg(%x) fail(%d).\n",
+						func->num, addr, ret);
+			i = i + 1;
+		} while (i < 0x10000);
+		dev_info(mmc_dev(host), "write success(%d).\n", ret);
+		break;
+	case Reset:
+		mmc_hw_reset(host);
+		break;
+	case Stress_read:
+	case Stress_write:
+		/* value is loop count, default 400 if not set */
+		if (value == 0)
+			value = 400;
+
+		i = 0;
+		total = 0;
+
+		KAL_REC_TIME_START();
+		do {
+			if (cmd == Stress_read)
+				ret = sdio_readsb(func, fac_buf,
+					addr, SDIO_XFER_SIZE);
+			else
+				ret = sdio_writesb(func, addr,
+					fac_buf, SDIO_XFER_SIZE);
+			if (ret)
+				count_r = count_r + 1;
+			else
+				total += SDIO_XFER_SIZE / 1024;
+			i = i + 1;
+		} while (i < value);
+		KAL_REC_TIME_END();
+		usec = KAL_GET_TIME_INTERVAL();
+		dev_info(mmc_dev(host),
+			"%s %lu Kbps, loop:%u, msec:%ld, err:%lx, buf:0x%08x...\n",
+			cmd == Stress_read ? "read":"write",
+			total / (usec / USEC_PER_MSEC) * 1024 * 8,
+			value, (usec / USEC_PER_MSEC), count_r,
+			*(unsigned int *)fac_buf);
+		break;
+	case SDIO_read_fix_Tput:
+	case SDIO_write_fix_Tput:
+		/* value is target T-put Mbps, offset is loop count */
+		if (value == 0 || offset == 0) {
+			dev_info(mmc_dev(host), "cmd:%d, err input\n",
+				cmd);
+			break;
+		}
+
+		i = 0;
+		r_usec = 0;
+		total = 0;
+
+		sdio_release_host(func);
+
+		do {
+			sdio_claim_host(func);
+
+			/* evaluate speed */
+			KAL_REC_TIME_START();
+			if (cmd == SDIO_read_fix_Tput)
+				ret = sdio_readsb(func, fac_buf,
+					addr, SDIO_XFER_SIZE);
+			else
+				ret = sdio_writesb(func, addr,
+					fac_buf, SDIO_XFER_SIZE);
+			KAL_REC_TIME_END();
+			usec = KAL_GET_TIME_INTERVAL();
+
+			sdio_release_host(func);
+
+			if (ret) {
+				dev_info(mmc_dev(host), "error.\n");
+				count_r = count_r + 1;
+			} else
+				total += (SDIO_XFER_SIZE / 1024);
+
+			/* calculate manual delay to target speed */
+			usec_sleep = SDIO_XFER_SIZE * 8 / value - usec;
+			if (usec_sleep > 0)
+				usleep_range(usec_sleep,
+					usec_sleep + 100);
+
+			KAL_REC_TIME_END();
+			r_usec += KAL_GET_TIME_INTERVAL();
+
+			i = i + 1;
+		} while (i < offset);
+
+		sdio_claim_host(func);
+
+		dev_info(mmc_dev(host),
+			"%s %lu Kbps(%u Mbps), msec:%ld, loop:%u, err:%lx, buf:0x%08x...\n",
+			cmd == SDIO_read_fix_Tput ? "read":"write",
+			total / (r_usec / USEC_PER_MSEC) * 1024 * 8,
+			value, r_usec / USEC_PER_MSEC, offset, count_r,
+			*(unsigned int *)fac_buf);
+		break;
+	default:
+		dev_info(mmc_dev(host), "cmd is not valid.\n");
+		break;
+	}
+
+	sdio_release_host(func);
+	kfree(func);
+
+end:
+	kfree(str_hand);
+	kfree(cmd_buf);
+	kfree(fac_buf);
+
+	return count;
+}
+
+/**
+ * open function show some stable information.
+ */
+static int sdio_proc_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, sdio_proc_show, inode->i_private);
+}
+
+/**
+ * sdio pre is our own function.
+ * seq or single pre is the kernel function.
+ */
+static const struct file_operations sdio_proc_fops = {
+	.owner = THIS_MODULE,
+	.open = sdio_proc_open,
+	.release = single_release,
+	.write = sdio_proc_write,
+	.read = seq_read,
+	.llseek = seq_lseek,
+};
+
+int sdio_proc_init(struct mmc_host *host_init)
+{
+	struct proc_dir_entry *prEntry;
+	static int flag;
+
+	if (!strcmp(mmc_hostname(host_init), "mmc0")) {
+		host_arry[0] = host_init;
+		max_id = 1;
+	} else if (!strcmp(mmc_hostname(host_init), "mmc1")) {
+		host_arry[1] = host_init;
+		max_id = 2;
+	} else if (!strcmp(mmc_hostname(host_init), "mmc2")) {
+		host_arry[2] = host_init;
+		max_id = 3;
+	} else
+		return 0;
+
+	if (!flag)
+		prEntry = proc_create("sdio", 0660, NULL, &sdio_proc_fops);
+	else
+		return 0;
+
+	if (prEntry) {
+		flag = 1;
+		dev_info(mmc_dev(host_init), "/proc/sdio is created.\n");
+	} else
+		dev_info(mmc_dev(host_init), "create /proc/sdio failed.\n");
+
+	return 0;
+}