mirror of https://github.com/OpenIPC/firmware.git
714 lines
20 KiB
Diff
714 lines
20 KiB
Diff
diff -drupN a/drivers/mmc/host/sunxi-mmc-debug.c b/drivers/mmc/host/sunxi-mmc-debug.c
|
|
--- a/drivers/mmc/host/sunxi-mmc-debug.c 1970-01-01 03:00:00.000000000 +0300
|
|
+++ b/drivers/mmc/host/sunxi-mmc-debug.c 2022-06-12 05:28:14.000000000 +0300
|
|
@@ -0,0 +1,709 @@
|
|
+/*
|
|
+* Sunxi SD/MMC host driver
|
|
+*
|
|
+* Copyright (C) 2015 AllWinnertech Ltd.
|
|
+* Author: lixiang <lixiang@allwinnertech>
|
|
+*
|
|
+* 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 "as is" WITHOUT ANY WARRANTY of any
|
|
+* kind, whether express or implied; without even the implied warranty
|
|
+* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+* GNU General Public License for more details.
|
|
+*/
|
|
+
|
|
+
|
|
+#include <linux/clk.h>
|
|
+#include <linux/clk/sunxi.h>
|
|
+
|
|
+#include <linux/gpio.h>
|
|
+#include <linux/platform_device.h>
|
|
+#include <linux/spinlock.h>
|
|
+#include <linux/scatterlist.h>
|
|
+#include <linux/dma-mapping.h>
|
|
+#include <linux/slab.h>
|
|
+#include <linux/reset.h>
|
|
+
|
|
+#include <linux/of_address.h>
|
|
+#include <linux/of_gpio.h>
|
|
+#include <linux/of_platform.h>
|
|
+#include <linux/stat.h>
|
|
+
|
|
+#include <linux/mmc/host.h>
|
|
+#include "sunxi-mmc.h"
|
|
+#include "sunxi-mmc-debug.h"
|
|
+#include "sunxi-mmc-export.h"
|
|
+#include "sunxi-mmc-sun50iw1p1-2.h"
|
|
+#include "sunxi-mmc-panic.h"
|
|
+
|
|
+
|
|
+#define GPIO_BASE_ADDR 0x1c20800
|
|
+/*nc platform no use these value*/
|
|
+#define CCMU_BASE_ADDR_BEFORE_V2P1H 0x1c20000
|
|
+
|
|
+#define SUNXI_MMC_MAX_HOST_PRT_ADDR 0x150
|
|
+#define SUNXI_MMC_MAX_GPIO_PRT_ADDR 0x120
|
|
+#define SUNXI_GPIOIC_PRT_EADDR 0x380
|
|
+#define SUNXI_GPIOIC_PRT_SADDR 0x200
|
|
+
|
|
+/*mmc bus clock gating register*/
|
|
+#define SUNXI_BCLKG_SADDR 0x60
|
|
+#define SUNXI_BCLKG_EADDR 0x80
|
|
+
|
|
+/*mmc moudule clock register*/
|
|
+#define SUNXI_CLK_PRT_SADDR 0x80
|
|
+#define SUNXI_CLK_PRT_EADDR 0xa0
|
|
+
|
|
+/*mmc bus soft reset register*/
|
|
+#define SUNXI_BSRES_SADDR 0x2C0
|
|
+#define SUNXI_BSRES_EADDR 0x2DC
|
|
+
|
|
+
|
|
+/*NC mmc bus gating,reset,moudule clouck register*/
|
|
+#define SUNXI_NCCM_EADDR 0x850
|
|
+#define SUNXI_NCCM_SADDR 0x830
|
|
+
|
|
+/*NC mmc PLL PERI register*/
|
|
+#define SUNXI_PP_NCM_EADDR 0x2C
|
|
+#define SUNXI_PP_NCM_SADDR 0x20
|
|
+
|
|
+#define SUNXI_DEG_MAX_MAP_REG 0x900
|
|
+
|
|
+static struct device_attribute dump_register[3];
|
|
+
|
|
+void sunxi_mmc_dumphex32(struct sunxi_mmc_host *host, char *name, char *base,
|
|
+ int len)
|
|
+{
|
|
+ u32 i;
|
|
+
|
|
+ pr_cont("dump %s registers:", name);
|
|
+ for (i = 0; i < len; i += 4) {
|
|
+ if (!(i&0xf))
|
|
+ pr_cont("\n0x%p : ", base + i);
|
|
+ pr_cont("0x%08x ", __raw_readl(host->reg_base+i));
|
|
+ }
|
|
+ pr_cont("\n");
|
|
+}
|
|
+
|
|
+void sunxi_mmc_dump_des(struct sunxi_mmc_host *host, char *base, int len)
|
|
+{
|
|
+ u32 i;
|
|
+
|
|
+ pr_cont("dump des mem\n");
|
|
+ for (i = 0; i < len; i += 4) {
|
|
+ if (!(i&0xf))
|
|
+ pr_cont("\n0x%p : ", base + i);
|
|
+ pr_cont("0x%08x ", *(u32 *)(base+i));
|
|
+ }
|
|
+ pr_cont("\n");
|
|
+}
|
|
+
|
|
+static unsigned int sunxi_mmc_get_rate(uint64_t bytes, uint64_t time_us)
|
|
+{
|
|
+ uint64_t ns;
|
|
+
|
|
+ ns = time_us * 1000;
|
|
+ bytes *= 1000000000;
|
|
+
|
|
+ while (ns > UINT_MAX) {
|
|
+ bytes >>= 1;
|
|
+ ns >>= 1;
|
|
+ }
|
|
+
|
|
+ if (!ns)
|
|
+ return 0;
|
|
+
|
|
+ do_div(bytes, (uint32_t)ns);
|
|
+
|
|
+ return bytes;
|
|
+}
|
|
+
|
|
+static void sunxi_mmc_filter_rate(struct sunxi_mmc_host *host, struct mmc_data *data, int64_t bytes, uint64_t time_us)
|
|
+{
|
|
+ unsigned int rate = 0;
|
|
+
|
|
+ if (!(host->filter_sector)
|
|
+ || !(host->filter_speed))
|
|
+ return;
|
|
+
|
|
+ if ((data->blocks) >= (host->filter_sector)) {
|
|
+ rate = sunxi_mmc_get_rate(bytes, time_us);
|
|
+ if (rate < (host->filter_speed))
|
|
+ printk("c=%u,a=0x%8x,""bs=%5u,""t=%9lluus,""sp=%7uKB/s\n",
|
|
+ data->mrq->cmd->opcode, data->mrq->cmd->arg,
|
|
+ data->blocks, time_us, rate/1024);
|
|
+ }
|
|
+}
|
|
+
|
|
+
|
|
+static ssize_t maual_insert_show(struct device *dev,
|
|
+ struct device_attribute *attr, char *buf)
|
|
+{
|
|
+ int ret;
|
|
+
|
|
+ ret =
|
|
+ snprintf(buf, PAGE_SIZE,
|
|
+ "Usage: \"echo 1 > insert\" to scan card\n");
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static ssize_t maual_insert_store(struct device *dev,
|
|
+ struct device_attribute *attr,
|
|
+ const char *buf, size_t count)
|
|
+{
|
|
+ int ret;
|
|
+
|
|
+ unsigned long insert = 0;
|
|
+ struct platform_device *pdev = to_platform_device(dev);
|
|
+ struct mmc_host *mmc = platform_get_drvdata(pdev);
|
|
+
|
|
+ ret = kstrtoul(buf, 0, &insert);
|
|
+ if (ret) {
|
|
+ ret = -EINVAL;
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ dev_info(dev, "insert %ld\n", insert);
|
|
+ if (insert)
|
|
+ mmc_detect_change(mmc, 0);
|
|
+ else
|
|
+ dev_info(dev, "no detect change\n");
|
|
+
|
|
+ ret = count;
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+int sunxi_mmc_res_start_addr(const char * const res_str,
|
|
+ resource_size_t *res_addr)
|
|
+{
|
|
+ struct device_node *np = NULL;
|
|
+ int ret = 0;
|
|
+ struct resource res;
|
|
+
|
|
+ if (res_str == NULL || res_addr == NULL) {
|
|
+ pr_err("input arg is error\n");
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ np = of_find_node_by_type(NULL, res_str);
|
|
+ if (IS_ERR(np)) {
|
|
+ pr_err("Can not find device type\n");
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ ret = of_address_to_resource(np, 0, &res);
|
|
+ if (ret || !res.start) {
|
|
+ pr_err("Can not find resouce\n");
|
|
+ return -EINVAL;
|
|
+ }
|
|
+ *res_addr = res.start;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+void sunxi_dump_reg(struct mmc_host *mmc)
|
|
+{
|
|
+ int i = 0;
|
|
+ struct sunxi_mmc_host *host = mmc_priv(mmc);
|
|
+ int ret = 0;
|
|
+ void __iomem *gpio_ptr = NULL;
|
|
+ void __iomem *ccmu_ptr = NULL;
|
|
+ resource_size_t res_saddr_ccmu;
|
|
+ resource_size_t res_saddr_gpio;
|
|
+
|
|
+ ret = sunxi_mmc_res_start_addr("clocks", &res_saddr_ccmu);
|
|
+ if (ret < 0)
|
|
+ return;
|
|
+ ccmu_ptr = ioremap(res_saddr_ccmu, SUNXI_DEG_MAX_MAP_REG);
|
|
+ if (ccmu_ptr == NULL) {
|
|
+ pr_err("Can not map ccmu resource\n");
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ ret = sunxi_mmc_res_start_addr("pio", &res_saddr_gpio);
|
|
+ if (ret < 0)
|
|
+ return;
|
|
+ gpio_ptr = ioremap(res_saddr_gpio, SUNXI_DEG_MAX_MAP_REG);
|
|
+ if (gpio_ptr == NULL) {
|
|
+ pr_err("Can not map gpio resource\n");
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ pr_cont("Dump %s (p%x) regs :\n", mmc_hostname(mmc), host->phy_index);
|
|
+ for (i = 0; i < SUNXI_MMC_MAX_HOST_PRT_ADDR; i += 4) {
|
|
+ if (!(i&0xf))
|
|
+ pr_cont("\n0x%p : ", (host->reg_base + i));
|
|
+ pr_cont("%08x ", readl(host->reg_base + i));
|
|
+ }
|
|
+ pr_cont("\n");
|
|
+
|
|
+
|
|
+ pr_cont("Dump gpio regs:\n");
|
|
+ for (i = 0; i < SUNXI_MMC_MAX_GPIO_PRT_ADDR; i += 4) {
|
|
+ if (!(i&0xf))
|
|
+ pr_cont("\n0x%p : ", (gpio_ptr + i));
|
|
+ pr_cont("%08x ", readl(gpio_ptr + i));
|
|
+ }
|
|
+ pr_cont("\n");
|
|
+
|
|
+ pr_cont("Dump gpio irqc regs:\n");
|
|
+ for (i = SUNXI_GPIOIC_PRT_SADDR; i < SUNXI_GPIOIC_PRT_EADDR; i += 4) {
|
|
+ if (!(i&0xf))
|
|
+ pr_cont("\n0x%p : ", (gpio_ptr + i));
|
|
+ pr_cont("%08x ", readl(gpio_ptr + i));
|
|
+ }
|
|
+ pr_cont("\n");
|
|
+
|
|
+ if (res_saddr_ccmu == CCMU_BASE_ADDR_BEFORE_V2P1H) {
|
|
+ pr_cont("Dump ccmu regs:gating\n");
|
|
+ for (i = SUNXI_BCLKG_SADDR; i < SUNXI_BCLKG_EADDR; i += 4) {
|
|
+ if (!(i&0xf))
|
|
+ pr_cont("\n0x%p : ", (ccmu_ptr + i));
|
|
+ pr_cont("%08x ", readl(ccmu_ptr + i));
|
|
+ }
|
|
+ pr_cont("\n");
|
|
+
|
|
+ pr_cont("Dump ccmu regs:module clk\n");
|
|
+ for (i = SUNXI_CLK_PRT_SADDR; i < SUNXI_CLK_PRT_EADDR; i += 4) {
|
|
+ if (!(i&0xf))
|
|
+ pr_cont("\n0x%p : ", (ccmu_ptr + i));
|
|
+ pr_cont("%08x ", readl(ccmu_ptr + i));
|
|
+ }
|
|
+ pr_cont("\n");
|
|
+
|
|
+ pr_cont("Dump ccmu regs:reset\n");
|
|
+ for (i = SUNXI_BSRES_SADDR; i < SUNXI_BSRES_EADDR; i += 4) {
|
|
+ if (!(i&0xf))
|
|
+ pr_cont("\n0x%p : ", (ccmu_ptr + i));
|
|
+ pr_cont("%08x ", readl(ccmu_ptr + i));
|
|
+ }
|
|
+ pr_cont("\n");
|
|
+ } else {
|
|
+ pr_cont("Dump ccmu regs:pll,gating,reset,module clk\n");
|
|
+
|
|
+ for (i = SUNXI_PP_NCM_SADDR; i < SUNXI_PP_NCM_EADDR; i += 4) {
|
|
+ if (!(i&0xf))
|
|
+ pr_cont("\n0x%p : ", (ccmu_ptr + i));
|
|
+ pr_cont("%08x ", readl(ccmu_ptr + i));
|
|
+ }
|
|
+ pr_cont("\n");
|
|
+
|
|
+ for (i = SUNXI_NCCM_SADDR; i < SUNXI_NCCM_EADDR; i += 4) {
|
|
+ if (!(i&0xf))
|
|
+ pr_cont("\n0x%p : ", (ccmu_ptr + i));
|
|
+ pr_cont("%08x ", readl(ccmu_ptr + i));
|
|
+ }
|
|
+ pr_cont("\n");
|
|
+ }
|
|
+
|
|
+ iounmap(gpio_ptr);
|
|
+ iounmap(ccmu_ptr);
|
|
+
|
|
+}
|
|
+
|
|
+static ssize_t dump_host_reg_show(struct device *dev,
|
|
+ struct device_attribute *attr, char *buf)
|
|
+{
|
|
+ char *p = buf;
|
|
+ int i = 0;
|
|
+ struct platform_device *pdev = to_platform_device(dev);
|
|
+ struct mmc_host *mmc = platform_get_drvdata(pdev);
|
|
+ struct sunxi_mmc_host *host = mmc_priv(mmc);
|
|
+
|
|
+ p += sprintf(p, "Dump sdmmc regs:\n");
|
|
+ for (i = 0; i < SUNXI_MMC_MAX_HOST_PRT_ADDR; i += 4) {
|
|
+ if (!(i&0xf))
|
|
+ p += sprintf(p, "\n0x%p : ", (host->reg_base + i));
|
|
+ p += sprintf(p, "%08x ", readl(host->reg_base + i));
|
|
+ }
|
|
+ p += sprintf(p, "\n");
|
|
+
|
|
+ return p - buf;
|
|
+
|
|
+}
|
|
+
|
|
+static ssize_t dump_gpio_reg_show(struct device *dev,
|
|
+ struct device_attribute *attr, char *buf)
|
|
+{
|
|
+ char *p = buf;
|
|
+ int i = 0;
|
|
+ void __iomem *gpio_ptr = NULL;
|
|
+ resource_size_t res_saddr_gpio;
|
|
+ int ret = 0;
|
|
+
|
|
+ ret = sunxi_mmc_res_start_addr("pio", &res_saddr_gpio);
|
|
+ if (ret < 0)
|
|
+ goto out;
|
|
+
|
|
+ gpio_ptr = ioremap(res_saddr_gpio, SUNXI_DEG_MAX_MAP_REG);
|
|
+ if (!gpio_ptr) {
|
|
+ pr_err("Can not map gpio resource\n");
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ p += sprintf(p, "Dump gpio regs:\n");
|
|
+ for (i = 0; i < SUNXI_MMC_MAX_GPIO_PRT_ADDR; i += 4) {
|
|
+ if (!(i&0xf))
|
|
+ p += sprintf(p, "\n0x%p : ", (gpio_ptr + i));
|
|
+ p += sprintf(p, "%08x ", readl(gpio_ptr + i));
|
|
+ }
|
|
+ p += sprintf(p, "\n");
|
|
+
|
|
+ p += sprintf(p, "Dump gpio irqc regs:\n");
|
|
+ for (i = SUNXI_GPIOIC_PRT_SADDR; i < SUNXI_GPIOIC_PRT_EADDR; i += 4) {
|
|
+ if (!(i&0xf))
|
|
+ p += sprintf(p, "\n0x%p : ", (gpio_ptr + i));
|
|
+ p += sprintf(p, "%08x ", readl(gpio_ptr + i));
|
|
+ }
|
|
+ p += sprintf(p, "\n");
|
|
+
|
|
+ iounmap(gpio_ptr);
|
|
+out:
|
|
+ return p-buf;
|
|
+
|
|
+}
|
|
+
|
|
+static ssize_t dump_ccmu_reg_show(struct device *dev,
|
|
+ struct device_attribute *attr, char *buf)
|
|
+{
|
|
+ char *p = buf;
|
|
+ int i = 0;
|
|
+ void __iomem *ccmu_ptr = NULL;
|
|
+ int ret = 0;
|
|
+ resource_size_t res_saddr_ccmu;
|
|
+
|
|
+ ret = sunxi_mmc_res_start_addr("clocks", &res_saddr_ccmu);
|
|
+ if (ret < 0)
|
|
+ goto out;
|
|
+
|
|
+ ccmu_ptr = ioremap(res_saddr_ccmu, SUNXI_DEG_MAX_MAP_REG);
|
|
+ if (!ccmu_ptr) {
|
|
+ pr_err("Can not map ccmu resource\n");
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ p += sprintf(p, "Dump ccmu\n");
|
|
+ if (res_saddr_ccmu == CCMU_BASE_ADDR_BEFORE_V2P1H) {
|
|
+
|
|
+ p += sprintf(p, "Dump ccmu regs:gating\n");
|
|
+ for (i = SUNXI_BCLKG_SADDR; i < SUNXI_BCLKG_EADDR; i += 4) {
|
|
+ if (!(i&0xf))
|
|
+ p += sprintf(p, "\n0x%p : ", (ccmu_ptr + i));
|
|
+ p += sprintf(p, "%08x ", readl(ccmu_ptr + i));
|
|
+ }
|
|
+ p += sprintf(p, "\n");
|
|
+
|
|
+ p += sprintf(p, "Dump ccmu regs:module clk\n");
|
|
+ for (i = SUNXI_CLK_PRT_SADDR; i < SUNXI_CLK_PRT_EADDR; i += 4) {
|
|
+ if (!(i&0xf))
|
|
+ p += sprintf(p, "\n0x%p : ", (ccmu_ptr + i));
|
|
+ p += sprintf(p, "%08x ", readl(ccmu_ptr + i));
|
|
+ }
|
|
+ p += sprintf(p, "\n");
|
|
+
|
|
+ p += sprintf(p, "Dump ccmu regs:reset\n");
|
|
+ for (i = SUNXI_BSRES_SADDR; i < SUNXI_BSRES_EADDR; i += 4) {
|
|
+ if (!(i&0xf))
|
|
+ p += sprintf(p, "\n0x%p : ", (ccmu_ptr + i));
|
|
+ p += sprintf(p, "%08x ", readl(ccmu_ptr + i));
|
|
+ }
|
|
+ p += sprintf(p, "\n");
|
|
+
|
|
+ } else {
|
|
+ p += sprintf(p, "Dump ccmu regs:pll,gating,reset,module clk\n");
|
|
+
|
|
+ for (i = SUNXI_PP_NCM_SADDR; i < SUNXI_PP_NCM_EADDR; i += 4) {
|
|
+ if (!(i&0xf))
|
|
+ p += sprintf(p, "\n0x%p : ", (ccmu_ptr + i));
|
|
+ p += sprintf(p, "%08x ", readl(ccmu_ptr + i));
|
|
+ }
|
|
+ p += sprintf(p, "\n");
|
|
+
|
|
+ for (i = SUNXI_NCCM_SADDR; i < SUNXI_NCCM_EADDR; i += 4) {
|
|
+ if (!(i&0xf))
|
|
+ p += sprintf(p, "\n0x%p : ", (ccmu_ptr + i));
|
|
+ p += sprintf(p, "%08x ", readl(ccmu_ptr + i));
|
|
+ }
|
|
+ p += sprintf(p, "\n");
|
|
+ }
|
|
+ p += sprintf(p, "\n");
|
|
+
|
|
+ iounmap(ccmu_ptr);
|
|
+
|
|
+out:
|
|
+ return p-buf;
|
|
+
|
|
+}
|
|
+
|
|
+static ssize_t dump_clk_dly_show(struct device *dev,
|
|
+ struct device_attribute *attr, char *buf)
|
|
+{
|
|
+ char *p = buf;
|
|
+ struct platform_device *pdev = to_platform_device(dev);
|
|
+ struct mmc_host *mmc = platform_get_drvdata(pdev);
|
|
+ struct sunxi_mmc_host *host = mmc_priv(mmc);
|
|
+
|
|
+ if (host->sunxi_mmc_dump_dly_table)
|
|
+ host->sunxi_mmc_dump_dly_table(host);
|
|
+ else
|
|
+ dev_warn(mmc_dev(mmc), "not found the dump dly table\n");
|
|
+
|
|
+ return p - buf;
|
|
+}
|
|
+
|
|
+int sunxi_mmc_uperf_stat(struct sunxi_mmc_host *host,
|
|
+ struct mmc_data *data,
|
|
+ struct mmc_request *mrq_busy,
|
|
+ bool bhalf)
|
|
+{
|
|
+ ktime_t diff;
|
|
+
|
|
+ if (!bhalf) {
|
|
+ if (host->perf_enable && data) {
|
|
+ diff = ktime_sub(ktime_get(), host->perf.start);
|
|
+ if (data->flags & MMC_DATA_READ) {
|
|
+ host->perf.rbytes += data->bytes_xfered;
|
|
+ host->perf.rtime =
|
|
+ ktime_add(host->perf.rtime, diff);
|
|
+ } else if (data->flags & MMC_DATA_WRITE) {
|
|
+ if (!mrq_busy) {
|
|
+ host->perf.wbytes +=
|
|
+ data->bytes_xfered;
|
|
+ host->perf.wtime =
|
|
+ ktime_add(host->perf.wtime, diff);
|
|
+ sunxi_mmc_filter_rate(host, data, data->bytes_xfered, ktime_to_us(diff));
|
|
+ }
|
|
+ host->perf.wbytestran += data->bytes_xfered;
|
|
+ host->perf.wtimetran =
|
|
+ ktime_add(host->perf.wtimetran, diff);
|
|
+ }
|
|
+ }
|
|
+ } else {
|
|
+ if (host->perf_enable
|
|
+ && mrq_busy->data
|
|
+ && (mrq_busy->data->flags & MMC_DATA_WRITE)) {
|
|
+ diff = ktime_sub(ktime_get(), host->perf.start);
|
|
+ host->perf.wbytes += mrq_busy->data->bytes_xfered;
|
|
+ host->perf.wtime = ktime_add(host->perf.wtime, diff);
|
|
+ sunxi_mmc_filter_rate(host, data, data->bytes_xfered, ktime_to_us(diff));
|
|
+ }
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(sunxi_mmc_uperf_stat);
|
|
+
|
|
+static ssize_t
|
|
+sunxi_mmc_show_perf(struct device *dev, struct device_attribute *attr, char *buf)
|
|
+{
|
|
+ struct platform_device *pdev = to_platform_device(dev);
|
|
+ struct mmc_host *mmc = platform_get_drvdata(pdev);
|
|
+ struct sunxi_mmc_host *host = mmc_priv(mmc);
|
|
+ int64_t rtime_drv, wtime_drv, wtime_drv_tran;
|
|
+ int64_t rbytes_drv, wbytes_drv, wbytes_drv_tran;
|
|
+
|
|
+
|
|
+ mmc_claim_host(mmc);
|
|
+
|
|
+ rbytes_drv = host->perf.rbytes;
|
|
+ wbytes_drv = host->perf.wbytes;
|
|
+ wbytes_drv_tran = host->perf.wbytestran;
|
|
+
|
|
+ rtime_drv = ktime_to_us(host->perf.rtime);
|
|
+ wtime_drv = ktime_to_us(host->perf.wtime);
|
|
+ wtime_drv_tran = ktime_to_us(host->perf.wtimetran);
|
|
+
|
|
+ mmc_release_host(mmc);
|
|
+
|
|
+ return snprintf(buf, PAGE_SIZE, "Write performance at host driver Level:"
|
|
+ "%lld bytes in %lld microseconds\n"
|
|
+ "Read performance at host driver Level:"
|
|
+ "%lld bytes in %lld microseconds\n"
|
|
+ "write performance at host driver Level(no wait busy):"
|
|
+ "%lld bytes in %lld microseconds\n",
|
|
+ wbytes_drv, wtime_drv,
|
|
+ rbytes_drv, rtime_drv,
|
|
+ wbytes_drv_tran, wtime_drv_tran);
|
|
+}
|
|
+
|
|
+static ssize_t
|
|
+sunxi_mmc_set_perf(struct device *dev, struct device_attribute *attr,
|
|
+ const char *buf, size_t count)
|
|
+{
|
|
+ struct platform_device *pdev = to_platform_device(dev);
|
|
+ struct mmc_host *mmc = platform_get_drvdata(pdev);
|
|
+ struct sunxi_mmc_host *host = mmc_priv(mmc);
|
|
+ int64_t value;
|
|
+
|
|
+ sscanf(buf, "%lld", &value);
|
|
+ printk("set perf value %lld\n", value);
|
|
+
|
|
+ mmc_claim_host(mmc);
|
|
+ if (!value) {
|
|
+ memset(&host->perf, 0, sizeof(host->perf));
|
|
+ host->perf_enable = false;
|
|
+ } else {
|
|
+ host->perf_enable = true;
|
|
+ }
|
|
+ mmc_release_host(mmc);
|
|
+
|
|
+ return count;
|
|
+}
|
|
+
|
|
+static ssize_t
|
|
+sunxi_mmc_show_filter_sector(struct device *dev, struct device_attribute *attr, char *buf)
|
|
+{
|
|
+ struct platform_device *pdev = to_platform_device(dev);
|
|
+ struct mmc_host *mmc = platform_get_drvdata(pdev);
|
|
+ struct sunxi_mmc_host *host = mmc_priv(mmc);
|
|
+
|
|
+ return snprintf(buf, PAGE_SIZE, "filter speed %d\n", host->filter_sector);
|
|
+}
|
|
+
|
|
+static ssize_t
|
|
+sunxi_mmc_set_filter_sector(struct device *dev, struct device_attribute *attr,
|
|
+ const char *buf, size_t count)
|
|
+{
|
|
+ struct platform_device *pdev = to_platform_device(dev);
|
|
+ struct mmc_host *mmc = platform_get_drvdata(pdev);
|
|
+ struct sunxi_mmc_host *host = mmc_priv(mmc);
|
|
+ int64_t value;
|
|
+
|
|
+ sscanf(buf, "%lld", &value);
|
|
+ printk("get filter sector %lld\n", value);
|
|
+ host->filter_sector = value;
|
|
+
|
|
+ return count;
|
|
+}
|
|
+
|
|
+
|
|
+static ssize_t
|
|
+sunxi_mmc_show_filter_speed(struct device *dev, struct device_attribute *attr, char *buf)
|
|
+{
|
|
+ struct platform_device *pdev = to_platform_device(dev);
|
|
+ struct mmc_host *mmc = platform_get_drvdata(pdev);
|
|
+ struct sunxi_mmc_host *host = mmc_priv(mmc);
|
|
+
|
|
+ return snprintf(buf, PAGE_SIZE, "filter speed %d\n", host->filter_speed);
|
|
+}
|
|
+
|
|
+static ssize_t
|
|
+sunxi_mmc_set_filter_speed(struct device *dev, struct device_attribute *attr,
|
|
+ const char *buf, size_t count)
|
|
+{
|
|
+ struct platform_device *pdev = to_platform_device(dev);
|
|
+ struct mmc_host *mmc = platform_get_drvdata(pdev);
|
|
+ struct sunxi_mmc_host *host = mmc_priv(mmc);
|
|
+ int64_t value;
|
|
+
|
|
+ sscanf(buf, "%lld", &value);
|
|
+ printk("get filter speed %lld\n", value);
|
|
+ host->filter_speed = value;
|
|
+
|
|
+ return count;
|
|
+}
|
|
+
|
|
+
|
|
+
|
|
+
|
|
+
|
|
+int mmc_create_sys_fs(struct sunxi_mmc_host *host, struct platform_device *pdev)
|
|
+{
|
|
+ int ret;
|
|
+
|
|
+ host->maual_insert.show = maual_insert_show;
|
|
+ host->maual_insert.store = maual_insert_store;
|
|
+ sysfs_attr_init(&(host->maual_insert.attr));
|
|
+ host->maual_insert.attr.name = "sunxi_insert";
|
|
+ host->maual_insert.attr.mode = S_IRUGO | S_IWUSR;
|
|
+ ret = device_create_file(&pdev->dev, &host->maual_insert);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ host->host_perf.show = sunxi_mmc_show_perf;
|
|
+ host->host_perf.store = sunxi_mmc_set_perf;
|
|
+ sysfs_attr_init(&(host->host_perf.attr));
|
|
+ host->host_perf.attr.mode = S_IRUGO | S_IWUSR;
|
|
+ host->host_perf.attr.name = "sunxi_host_perf";
|
|
+ ret = device_create_file(&pdev->dev, &host->host_perf);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ host->filter_sector_perf.show = sunxi_mmc_show_filter_sector;
|
|
+ host->filter_sector_perf.store = sunxi_mmc_set_filter_sector;
|
|
+ sysfs_attr_init(&(host->filter_sector_perf.attr));
|
|
+ host->filter_sector_perf.attr.name = "sunxi_host_filter_w_sector";
|
|
+ host->filter_sector_perf.attr.mode = S_IRUGO | S_IWUSR;
|
|
+ ret = device_create_file(&pdev->dev, &host->filter_sector_perf);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ host->filter_speed_perf.show = sunxi_mmc_show_filter_speed;;
|
|
+ host->filter_speed_perf.store = sunxi_mmc_set_filter_speed;;
|
|
+ sysfs_attr_init(&(host->filter_speed_perf.attr));
|
|
+ host->filter_speed_perf.attr.name = "sunxi_host_filter_w_speed";
|
|
+ host->filter_speed_perf.attr.mode = S_IRUGO | S_IWUSR;
|
|
+ ret = device_create_file(&pdev->dev, &host->filter_speed_perf);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+
|
|
+ host->dump_register = dump_register;
|
|
+ host->dump_register[0].show = dump_host_reg_show;
|
|
+ sysfs_attr_init(&(host->dump_register[0].attr));
|
|
+ host->dump_register[0].attr.name = "sunxi_dump_host_register";
|
|
+ host->dump_register[0].attr.mode = S_IRUGO;
|
|
+ ret = device_create_file(&pdev->dev, &host->dump_register[0]);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ host->dump_register[1].show = dump_gpio_reg_show;
|
|
+ sysfs_attr_init(&(host->dump_register[1].attr));
|
|
+ host->dump_register[1].attr.name = "sunxi_dump_gpio_register";
|
|
+ host->dump_register[1].attr.mode = S_IRUGO;
|
|
+ ret = device_create_file(&pdev->dev, &host->dump_register[1]);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ host->dump_register[2].show = dump_ccmu_reg_show;
|
|
+ sysfs_attr_init(&(host->dump_register[2].attr));
|
|
+ host->dump_register[2].attr.name = "sunxi_dump_ccmu_register";
|
|
+ host->dump_register[2].attr.mode = S_IRUGO;
|
|
+ ret = device_create_file(&pdev->dev, &host->dump_register[2]);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ host->dump_clk_dly.show = dump_clk_dly_show;
|
|
+ sysfs_attr_init(&(host->dump_clk_dly.attr));
|
|
+ host->dump_clk_dly.attr.name = "sunxi_dump_clk_dly";
|
|
+ host->dump_clk_dly.attr.mode = S_IRUGO;
|
|
+ ret = device_create_file(&pdev->dev, &host->dump_clk_dly);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ host->host_mwr.show = sunxi_mmc_panic_rtest;
|
|
+ host->host_mwr.store = sunxi_mmc_pancic_wrtest;
|
|
+ sysfs_attr_init(host->host_mwr.attr);
|
|
+ host->host_mwr.attr.name = "sunxi_host_panic_wr";
|
|
+ host->host_mwr.attr.mode = S_IRUGO | S_IWUSR;
|
|
+ ret = device_create_file(&pdev->dev, &host->host_mwr);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(mmc_create_sys_fs);
|
|
+
|
|
+void mmc_remove_sys_fs(struct sunxi_mmc_host *host,
|
|
+ struct platform_device *pdev)
|
|
+{
|
|
+ device_remove_file(&pdev->dev, &host->host_mwr);
|
|
+ device_remove_file(&pdev->dev, &host->host_perf);
|
|
+ device_remove_file(&pdev->dev, &host->maual_insert);
|
|
+ device_remove_file(&pdev->dev, &host->dump_register[0]);
|
|
+ device_remove_file(&pdev->dev, &host->dump_register[1]);
|
|
+ device_remove_file(&pdev->dev, &host->dump_register[2]);
|
|
+ device_remove_file(&pdev->dev, &host->dump_clk_dly);
|
|
+ device_remove_file(&pdev->dev, &host->filter_sector_perf);
|
|
+ device_remove_file(&pdev->dev, &host->filter_speed_perf);
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(mmc_remove_sys_fs);
|