diff options
author | Lars-Peter Clausen <lars@metafoo.de> | 2015-03-26 19:46:01 +0000 |
---|---|---|
committer | Lars-Peter Clausen <lars@metafoo.de> | 2015-03-26 19:46:01 +0000 |
commit | b18f5eb44a31d7d73b31519175c366630413ac8a (patch) | |
tree | 954b52e1dba2a37e9d1958f453eef26e12ef26fa /target/linux/xburst/patches-3.10 | |
parent | c25bf32f8dc8cd47a1e78e1701dc79da55529f93 (diff) | |
download | master-31e0f0ae-b18f5eb44a31d7d73b31519175c366630413ac8a.tar.gz master-31e0f0ae-b18f5eb44a31d7d73b31519175c366630413ac8a.tar.bz2 master-31e0f0ae-b18f5eb44a31d7d73b31519175c366630413ac8a.zip |
xburst: Update to 3.18
Update the xburst target to kernel version 3.18 and also remove the broken 3.10 support.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
SVN-Revision: 45031
Diffstat (limited to 'target/linux/xburst/patches-3.10')
16 files changed, 0 insertions, 4974 deletions
diff --git a/target/linux/xburst/patches-3.10/001-ubi-Read-only-the-vid-header-instead-of-the-whole-pa.patch b/target/linux/xburst/patches-3.10/001-ubi-Read-only-the-vid-header-instead-of-the-whole-pa.patch deleted file mode 100644 index 5991635e6f..0000000000 --- a/target/linux/xburst/patches-3.10/001-ubi-Read-only-the-vid-header-instead-of-the-whole-pa.patch +++ /dev/null @@ -1,22 +0,0 @@ -From 10fd63ee59dd9de4174f92f2f292b82fe46f1546 Mon Sep 17 00:00:00 2001 -From: Lars-Peter Clausen <lars@metafoo.de> -Date: Tue, 15 Mar 2011 12:49:15 +0100 -Subject: [PATCH 01/16] ubi: Read only the vid header instead of the whole - page - -Signed-off-by: Lars-Peter Clausen <lars@metafoo.de> ---- - drivers/mtd/ubi/io.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/drivers/mtd/ubi/io.c -+++ b/drivers/mtd/ubi/io.c -@@ -1019,7 +1019,7 @@ int ubi_io_read_vid_hdr(struct ubi_devic - - p = (char *)vid_hdr - ubi->vid_hdr_shift; - read_err = ubi_io_read(ubi, p, pnum, ubi->vid_hdr_aloffset, -- ubi->vid_hdr_alsize); -+ UBI_VID_HDR_SIZE + ubi->vid_hdr_shift); - if (read_err && read_err != UBI_IO_BITFLIPS && !mtd_is_eccerr(read_err)) - return read_err; - diff --git a/target/linux/xburst/patches-3.10/002-NAND-Optimize-NAND_ECC_HW_OOB_FIRST-read.patch b/target/linux/xburst/patches-3.10/002-NAND-Optimize-NAND_ECC_HW_OOB_FIRST-read.patch deleted file mode 100644 index 57f53b7ab1..0000000000 --- a/target/linux/xburst/patches-3.10/002-NAND-Optimize-NAND_ECC_HW_OOB_FIRST-read.patch +++ /dev/null @@ -1,45 +0,0 @@ -From f2b7099d3986e59aab5792cecc052e440caf2cdd Mon Sep 17 00:00:00 2001 -From: Lars-Peter Clausen <lars@metafoo.de> -Date: Sat, 26 Feb 2011 15:30:07 +0100 -Subject: [PATCH 02/16] NAND: Optimize NAND_ECC_HW_OOB_FIRST read - -Avoid sending unnecessary READ commands to the chip. - -Signed-off-by: Lars-Peter Clausen <lars@metafoo.de> ---- - drivers/mtd/nand/nand_base.c | 17 +++++++++++++---- - 1 file changed, 13 insertions(+), 4 deletions(-) - ---- a/drivers/mtd/nand/nand_base.c -+++ b/drivers/mtd/nand/nand_base.c -@@ -1278,9 +1278,16 @@ static int nand_read_page_hwecc_oob_firs - unsigned int max_bitflips = 0; - - /* Read the OOB area first */ -- chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); -- chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); -- chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page); -+ /* Read the OOB area first */ -+ if (mtd->writesize > 512) { -+ chip->cmdfunc(mtd, NAND_CMD_READ0, mtd->writesize, page); -+ chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); -+ chip->cmdfunc(mtd, NAND_CMD_RNDOUT, 0, -1); -+ } else { -+ chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); -+ chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); -+ chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page); -+ } - - for (i = 0; i < chip->ecc.total; i++) - ecc_code[i] = chip->oob_poi[eccpos[i]]; -@@ -1455,7 +1462,9 @@ static int nand_do_read_ops(struct mtd_i - if (realpage != chip->pagebuf || oob) { - bufpoi = aligned ? buf : chip->buffers->databuf; - -- chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page); -+ if (chip->ecc.mode != NAND_ECC_HW_OOB_FIRST) { -+ chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page); -+ } - - /* - * Now read the page into the buffer. Absent an error, diff --git a/target/linux/xburst/patches-3.10/003-NAND-Add-support-for-subpage-reads-for-NAND_ECC_HW_O.patch b/target/linux/xburst/patches-3.10/003-NAND-Add-support-for-subpage-reads-for-NAND_ECC_HW_O.patch deleted file mode 100644 index ba40603c1d..0000000000 --- a/target/linux/xburst/patches-3.10/003-NAND-Add-support-for-subpage-reads-for-NAND_ECC_HW_O.patch +++ /dev/null @@ -1,134 +0,0 @@ -From 90e325c5e16db262818bca442b00f5ac10b9c852 Mon Sep 17 00:00:00 2001 -From: Lars-Peter Clausen <lars@metafoo.de> -Date: Tue, 15 Mar 2011 12:33:41 +0100 -Subject: [PATCH 03/16] NAND: Add support for subpage reads for - NAND_ECC_HW_OOB_FIRST - -Signed-off-by: Lars-Peter Clausen <lars@metafoo.de> ---- - drivers/mtd/nand/nand_base.c | 80 ++++++++++++++++++++++++++++++++++++++++-- - include/linux/mtd/nand.h | 2 +- - 2 files changed, 78 insertions(+), 4 deletions(-) - ---- a/drivers/mtd/nand/nand_base.c -+++ b/drivers/mtd/nand/nand_base.c -@@ -1118,7 +1118,7 @@ static int nand_read_page_swecc(struct m - * @bufpoi: buffer to store read data - */ - static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, -- uint32_t data_offs, uint32_t readlen, uint8_t *bufpoi) -+ uint32_t data_offs, uint32_t readlen, uint8_t *bufpoi, int page) - { - int start_step, end_step, num_steps; - uint32_t *eccpos = chip->ecc.layout->eccpos; -@@ -1311,6 +1311,75 @@ static int nand_read_page_hwecc_oob_firs - } - - /** -+ * nand_read_subpage_hwecc_oob_first - [REPLACABLE] hw ecc based sub-page read function -+ * @mtd: mtd info structure -+ * @chip: nand chip info structure -+ * @data_offs: offset of requested data within the page -+ * @readlen: data length -+ * @bufpoi: buffer to store read data -+ * @page: page number to read -+ * -+ * Hardware ECC for large page chips, require OOB to be read first. -+ * For this ECC mode, the write_page method is re-used from ECC_HW. -+ * These methods read/write ECC from the OOB area, unlike the -+ * ECC_HW_SYNDROME support with multiple ECC steps, follows the -+ * "infix ECC" scheme and reads/writes ECC from the data area, by -+ * overwriting the NAND manufacturer bad block markings. -+ */ -+static int nand_read_subpage_hwecc_oob_first(struct mtd_info *mtd, struct nand_chip *chip, -+ uint32_t data_offs, uint32_t readlen, uint8_t *bufpoi, int page) -+{ -+ int start_step, end_step, num_steps; -+ uint32_t *eccpos = chip->ecc.layout->eccpos; -+ uint8_t *p; -+ int data_col_addr; -+ int eccsize = chip->ecc.size; -+ int eccbytes = chip->ecc.bytes; -+ uint8_t *ecc_code = chip->buffers->ecccode; -+ uint8_t *ecc_calc = chip->buffers->ecccalc; -+ int i; -+ -+ /* Column address wihin the page aligned to ECC size */ -+ start_step = data_offs / chip->ecc.size; -+ end_step = (data_offs + readlen - 1) / chip->ecc.size; -+ num_steps = end_step - start_step + 1; -+ -+ data_col_addr = start_step * chip->ecc.size; -+ -+ /* Read the OOB area first */ -+ if (mtd->writesize > 512) { -+ chip->cmdfunc(mtd, NAND_CMD_READ0, mtd->writesize, page); -+ chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); -+ chip->cmdfunc(mtd, NAND_CMD_RNDOUT, data_col_addr, -1); -+ } else { -+ chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); -+ chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); -+ chip->cmdfunc(mtd, NAND_CMD_READ0, data_col_addr, page); -+ } -+ -+ for (i = 0; i < chip->ecc.total; i++) -+ ecc_code[i] = chip->oob_poi[eccpos[i]]; -+ -+ p = bufpoi + data_col_addr; -+ -+ for (i = eccbytes * start_step; num_steps; num_steps--, i += eccbytes, p += eccsize) { -+ int stat; -+ -+ chip->ecc.hwctl(mtd, NAND_ECC_READ); -+ chip->read_buf(mtd, p, eccsize); -+ chip->ecc.calculate(mtd, p, &ecc_calc[i]); -+ -+ stat = chip->ecc.correct(mtd, p, &ecc_code[i], NULL); -+ if (stat < 0) -+ mtd->ecc_stats.failed++; -+ else -+ mtd->ecc_stats.corrected += stat; -+ } -+ -+ return 0; -+} -+ -+/** - * nand_read_page_syndrome - [REPLACEABLE] hardware ECC syndrome based page read - * @mtd: mtd info structure - * @chip: nand chip info structure -@@ -1477,7 +1546,7 @@ static int nand_do_read_ops(struct mtd_i - else if (!aligned && NAND_HAS_SUBPAGE_READ(chip) && - !oob) - ret = chip->ecc.read_subpage(mtd, chip, -- col, bytes, bufpoi); -+ col, bytes, bufpoi, page); - else - ret = chip->ecc.read_page(mtd, chip, bufpoi, - oob_required, page); -@@ -3488,8 +3557,13 @@ int nand_scan_tail(struct mtd_info *mtd) - "hardware ECC not possible\n"); - BUG(); - } -- if (!chip->ecc.read_page) -+ if (!chip->ecc.read_page) { - chip->ecc.read_page = nand_read_page_hwecc_oob_first; -+ if (!chip->ecc.read_subpage) { -+ chip->ecc.read_subpage = nand_read_subpage_hwecc_oob_first; -+ chip->options |= NAND_SUBPAGE_READ; -+ } -+ } - - case NAND_ECC_HW: - /* Use standard hwecc read page function? */ ---- a/include/linux/mtd/nand.h -+++ b/include/linux/mtd/nand.h -@@ -349,7 +349,7 @@ struct nand_ecc_ctrl { - int (*read_page)(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf, int oob_required, int page); - int (*read_subpage)(struct mtd_info *mtd, struct nand_chip *chip, -- uint32_t offs, uint32_t len, uint8_t *buf); -+ uint32_t offs, uint32_t len, uint8_t *buf, int page); - int (*write_subpage)(struct mtd_info *mtd, struct nand_chip *chip, - uint32_t offset, uint32_t data_len, - const uint8_t *data_buf, int oob_required); diff --git a/target/linux/xburst/patches-3.10/004-MMC-JZ4740-Remove-duplicated-code.patch b/target/linux/xburst/patches-3.10/004-MMC-JZ4740-Remove-duplicated-code.patch deleted file mode 100644 index 0d4ff65e92..0000000000 --- a/target/linux/xburst/patches-3.10/004-MMC-JZ4740-Remove-duplicated-code.patch +++ /dev/null @@ -1,24 +0,0 @@ -From 3e46e1ea552c3cc5fb64dfeab22124a0e8b94495 Mon Sep 17 00:00:00 2001 -From: Paul Cercueil <paul@crapouillou.net> -Date: Sun, 3 Jun 2012 12:45:23 +0200 -Subject: [PATCH 04/16] MMC: JZ4740: Remove duplicated code. - -Signed-off-by: Lars-Peter Clausen <lars@metafoo.de> ---- - drivers/mmc/host/jz4740_mmc.c | 5 ----- - 1 file changed, 5 deletions(-) - ---- a/drivers/mmc/host/jz4740_mmc.c -+++ b/drivers/mmc/host/jz4740_mmc.c -@@ -560,11 +560,6 @@ static irqreturn_t jz_mmc_irq(int irq, v - if (cmd->data) - cmd->data->error = -EIO; - cmd->error = -EIO; -- } else if (status & (JZ_MMC_STATUS_CRC_READ_ERROR | -- JZ_MMC_STATUS_CRC_WRITE_ERROR)) { -- if (cmd->data) -- cmd->data->error = -EIO; -- cmd->error = -EIO; - } - - jz4740_mmc_set_irq_enabled(host, irq_reg, false); diff --git a/target/linux/xburst/patches-3.10/005-MMC-JZ4740-Fix-handling-of-read-errors.patch b/target/linux/xburst/patches-3.10/005-MMC-JZ4740-Fix-handling-of-read-errors.patch deleted file mode 100644 index 598d518e0f..0000000000 --- a/target/linux/xburst/patches-3.10/005-MMC-JZ4740-Fix-handling-of-read-errors.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 81d112d6c0e16fd0136ce2c5f511ba81ed1f23d2 Mon Sep 17 00:00:00 2001 -From: Paul Cercueil <paul@crapouillou.net> -Date: Sun, 3 Jun 2012 13:07:19 +0200 -Subject: [PATCH 05/16] MMC: JZ4740: Fix handling of read errors. - -For no reason, the code handling write errors was implemented while -the code handling read errors was missing. - -Signed-off-by: Lars-Peter Clausen <lars@metafoo.de> ---- - drivers/mmc/host/jz4740_mmc.c | 8 ++++++++ - 1 file changed, 8 insertions(+) - ---- a/drivers/mmc/host/jz4740_mmc.c -+++ b/drivers/mmc/host/jz4740_mmc.c -@@ -231,6 +231,14 @@ static void jz4740_mmc_transfer_check_st - host->req->cmd->error = -EIO; - data->error = -EIO; - } -+ } else if (status & JZ_MMC_STATUS_READ_ERROR_MASK) { -+ if (status & (JZ_MMC_STATUS_TIMEOUT_READ)) { -+ host->req->cmd->error = -ETIMEDOUT; -+ data->error = -ETIMEDOUT; -+ } else { -+ host->req->cmd->error = -EIO; -+ data->error = -EIO; -+ } - } - } - diff --git a/target/linux/xburst/patches-3.10/006-ASoC-JZ4740-delay-activation-of-the-DAC-to-work-arou.patch b/target/linux/xburst/patches-3.10/006-ASoC-JZ4740-delay-activation-of-the-DAC-to-work-arou.patch deleted file mode 100644 index 7a7ce73ec1..0000000000 --- a/target/linux/xburst/patches-3.10/006-ASoC-JZ4740-delay-activation-of-the-DAC-to-work-arou.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 46c628ae74578382ec324405dd4caafdbf3838bd Mon Sep 17 00:00:00 2001 -From: Paul Cercueil <paul@crapouillou.net> -Date: Sat, 16 Jun 2012 19:36:31 +0200 -Subject: [PATCH 06/16] ASoC: JZ4740: delay activation of the DAC to work - around a sound bug. - -A proper fix of that bug would require a big rewrite of the driver, -which (I hope) will be done eventually. - -Signed-off-by: Lars-Peter Clausen <lars@metafoo.de> ---- - sound/soc/codecs/jz4740.c | 9 ++++++--- - 1 file changed, 6 insertions(+), 3 deletions(-) - ---- a/sound/soc/codecs/jz4740.c -+++ b/sound/soc/codecs/jz4740.c -@@ -249,12 +249,15 @@ static int jz4740_codec_set_bias_level(s - case SND_SOC_BIAS_ON: - break; - case SND_SOC_BIAS_PREPARE: -- mask = JZ4740_CODEC_1_VREF_DISABLE | -- JZ4740_CODEC_1_VREF_AMP_DISABLE | -- JZ4740_CODEC_1_HEADPHONE_POWERDOWN_M; -+ mask = JZ4740_CODEC_1_HEADPHONE_POWERDOWN_M; - value = 0; - - regmap_update_bits(regmap, JZ4740_REG_CODEC_1, mask, value); -+ -+ msleep(500); -+ mask = JZ4740_CODEC_1_VREF_DISABLE | -+ JZ4740_CODEC_1_VREF_AMP_DISABLE; -+ regmap_update_bits(regmap, JZ4740_REG_CODEC_1, mask, 0); - break; - case SND_SOC_BIAS_STANDBY: - /* The only way to clear the suspend flag is to reset the codec */ diff --git a/target/linux/xburst/patches-3.10/007-RTC-JZ4740-Init-the-regulator-register-on-startup.patch b/target/linux/xburst/patches-3.10/007-RTC-JZ4740-Init-the-regulator-register-on-startup.patch deleted file mode 100644 index dc66b009ef..0000000000 --- a/target/linux/xburst/patches-3.10/007-RTC-JZ4740-Init-the-regulator-register-on-startup.patch +++ /dev/null @@ -1,56 +0,0 @@ -From aff616f4a33bd3a9ab1506fdbe97fcfe285cb7b0 Mon Sep 17 00:00:00 2001 -From: Paul Cercueil <paul@crapouillou.net> -Date: Thu, 13 Sep 2012 00:09:20 +0200 -Subject: [PATCH 07/16] RTC: JZ4740: Init the "regulator" register on startup. - -This register controls the accuracy of the RTC. uC/OS-II use -the RTC as a 100Hz clock, and writes a completely wrong value -on that register, that we have to overwrite if we want a working -real-time clock. - -Signed-off-by: Paul Cercueil <paul@crapouillou.net> -Signed-off-by: Lars-Peter Clausen <lars@metafoo.de> ---- - drivers/rtc/rtc-jz4740.c | 17 +++++++++++++++++ - 1 file changed, 17 insertions(+) - ---- a/drivers/rtc/rtc-jz4740.c -+++ b/drivers/rtc/rtc-jz4740.c -@@ -14,6 +14,7 @@ - * - */ - -+#include <linux/clk.h> - #include <linux/kernel.h> - #include <linux/module.h> - #include <linux/platform_device.h> -@@ -215,6 +216,7 @@ static int jz4740_rtc_probe(struct platf - int ret; - struct jz4740_rtc *rtc; - uint32_t scratchpad; -+ struct clk *rtc_clk; - - rtc = kzalloc(sizeof(*rtc), GFP_KERNEL); - if (!rtc) -@@ -280,6 +282,21 @@ static int jz4740_rtc_probe(struct platf - } - } - -+ rtc_clk = clk_get(&pdev->dev, "rtc"); -+ if (IS_ERR(rtc_clk)) { -+ dev_err(&pdev->dev, "Failed to get RTC clock\n"); -+ goto err_free_irq; -+ } -+ -+ /* TODO: initialize the ADJC bits (25:16) to fine-tune -+ * the accuracy of the RTC */ -+ ret = jz4740_rtc_reg_write(rtc, JZ_REG_RTC_REGULATOR, -+ (clk_get_rate(rtc_clk) - 1) & 0xffff); -+ clk_put(rtc_clk); -+ -+ if (ret) -+ dev_warn(&pdev->dev, "Could not update RTC regulator register\n"); -+ - return 0; - - err_free_irq: diff --git a/target/linux/xburst/patches-3.10/008-Add-jz4740-udc-driver.patch b/target/linux/xburst/patches-3.10/008-Add-jz4740-udc-driver.patch deleted file mode 100644 index 88b2b5a823..0000000000 --- a/target/linux/xburst/patches-3.10/008-Add-jz4740-udc-driver.patch +++ /dev/null @@ -1,2315 +0,0 @@ -From b3e08e29f6f32dfb400374dc96d0a2f61e6adceb Mon Sep 17 00:00:00 2001 -From: Lars-Peter Clausen <lars@metafoo.de> -Date: Sat, 24 Apr 2010 12:18:46 +0200 -Subject: [PATCH 08/16] Add jz4740 udc driver - -Signed-off-by: Lars-Peter Clausen <lars@metafoo.de> ---- - drivers/usb/gadget/Kconfig | 8 + - drivers/usb/gadget/Makefile | 1 + - drivers/usb/gadget/gadget_chips.h | 1 + - drivers/usb/gadget/jz4740_udc.c | 2155 +++++++++++++++++++++++++++++++++++++ - drivers/usb/gadget/jz4740_udc.h | 101 ++ - 5 files changed, 2266 insertions(+) - create mode 100644 drivers/usb/gadget/jz4740_udc.c - create mode 100644 drivers/usb/gadget/jz4740_udc.h - ---- a/drivers/usb/gadget/Kconfig -+++ b/drivers/usb/gadget/Kconfig -@@ -192,6 +192,14 @@ config USB_FUSB300 - help - Faraday usb device controller FUSB300 driver - -+config USB_JZ4740 -+ tristate "JZ4740 UDC" -+ depends on MACH_JZ4740 -+ select USB_GADGET_DUALSPEED -+ help -+ Select this to support the Ingenic JZ4740 processor -+ high speed USB device controller. -+ - config USB_OMAP - tristate "OMAP USB Device Controller" - depends on ARCH_OMAP1 ---- a/drivers/usb/gadget/Makefile -+++ b/drivers/usb/gadget/Makefile -@@ -34,6 +34,7 @@ obj-$(CONFIG_USB_MV_UDC) += mv_udc.o - mv_udc-y := mv_udc_core.o - obj-$(CONFIG_USB_FUSB300) += fusb300_udc.o - obj-$(CONFIG_USB_MV_U3D) += mv_u3d_core.o -+obj-$(CONFIG_USB_JZ4740) += jz4740_udc.o - - # USB Functions - usb_f_acm-y := f_acm.o ---- a/drivers/usb/gadget/gadget_chips.h -+++ b/drivers/usb/gadget/gadget_chips.h -@@ -29,6 +29,7 @@ - */ - #define gadget_is_at91(g) (!strcmp("at91_udc", (g)->name)) - #define gadget_is_goku(g) (!strcmp("goku_udc", (g)->name)) -+#define gadget_is_jz4740(g) (!strcmp("ingenic_hsusb", (g)->name)) - #define gadget_is_musbhdrc(g) (!strcmp("musb-hdrc", (g)->name)) - #define gadget_is_net2280(g) (!strcmp("net2280", (g)->name)) - #define gadget_is_pxa(g) (!strcmp("pxa25x_udc", (g)->name)) ---- /dev/null -+++ b/drivers/usb/gadget/jz4740_udc.c -@@ -0,0 +1,2155 @@ -+/* -+ * linux/drivers/usb/gadget/jz4740_udc.c -+ * -+ * Ingenic JZ4740 on-chip high speed USB device controller -+ * -+ * Copyright (C) 2006 - 2008 Ingenic Semiconductor Inc. -+ * Author: <jlwei@ingenic.cn> -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ */ -+ -+/* -+ * This device has ep0, two bulk-in/interrupt-in endpoints, and one bulk-out endpoint. -+ * -+ * - Endpoint numbering is fixed: ep0, ep1in-int, ep2in-bulk, ep1out-bulk. -+ * - DMA works with bulk-in (channel 1) and bulk-out (channel 2) endpoints. -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/platform_device.h> -+#include <linux/delay.h> -+#include <linux/ioport.h> -+#include <linux/slab.h> -+#include <linux/errno.h> -+#include <linux/init.h> -+#include <linux/list.h> -+#include <linux/interrupt.h> -+#include <linux/proc_fs.h> -+#include <linux/usb.h> -+#include <linux/usb/gadget.h> -+#include <linux/clk.h> -+ -+#include <asm/byteorder.h> -+#include <asm/io.h> -+#include <asm/irq.h> -+#include <asm/mach-jz4740/clock.h> -+ -+#include "jz4740_udc.h" -+ -+#define JZ_REG_UDC_FADDR 0x00 /* Function Address 8-bit */ -+#define JZ_REG_UDC_POWER 0x01 /* Power Management 8-bit */ -+#define JZ_REG_UDC_INTRIN 0x02 /* Interrupt IN 16-bit */ -+#define JZ_REG_UDC_INTROUT 0x04 /* Interrupt OUT 16-bit */ -+#define JZ_REG_UDC_INTRINE 0x06 /* Intr IN enable 16-bit */ -+#define JZ_REG_UDC_INTROUTE 0x08 /* Intr OUT enable 16-bit */ -+#define JZ_REG_UDC_INTRUSB 0x0a /* Interrupt USB 8-bit */ -+#define JZ_REG_UDC_INTRUSBE 0x0b /* Interrupt USB Enable 8-bit */ -+#define JZ_REG_UDC_FRAME 0x0c /* Frame number 16-bit */ -+#define JZ_REG_UDC_INDEX 0x0e /* Index register 8-bit */ -+#define JZ_REG_UDC_TESTMODE 0x0f /* USB test mode 8-bit */ -+ -+#define JZ_REG_UDC_CSR0 0x12 /* EP0 CSR 8-bit */ -+#define JZ_REG_UDC_INMAXP 0x10 /* EP1-2 IN Max Pkt Size 16-bit */ -+#define JZ_REG_UDC_INCSR 0x12 /* EP1-2 IN CSR LSB 8/16bit */ -+#define JZ_REG_UDC_INCSRH 0x13 /* EP1-2 IN CSR MSB 8-bit */ -+ -+#define JZ_REG_UDC_OUTMAXP 0x14 /* EP1 OUT Max Pkt Size 16-bit */ -+#define JZ_REG_UDC_OUTCSR 0x16 /* EP1 OUT CSR LSB 8/16bit */ -+#define JZ_REG_UDC_OUTCSRH 0x17 /* EP1 OUT CSR MSB 8-bit */ -+#define JZ_REG_UDC_OUTCOUNT 0x18 /* bytes in EP0/1 OUT FIFO 16-bit */ -+ -+#define JZ_REG_UDC_EP_FIFO(x) (4 * (x) + 0x20) -+ -+#define JZ_REG_UDC_EPINFO 0x78 /* Endpoint information */ -+#define JZ_REG_UDC_RAMINFO 0x79 /* RAM information */ -+ -+#define JZ_REG_UDC_INTR 0x200 /* DMA pending interrupts */ -+#define JZ_REG_UDC_CNTL1 0x204 /* DMA channel 1 control */ -+#define JZ_REG_UDC_ADDR1 0x208 /* DMA channel 1 AHB memory addr */ -+#define JZ_REG_UDC_COUNT1 0x20c /* DMA channel 1 byte count */ -+#define JZ_REG_UDC_CNTL2 0x214 /* DMA channel 2 control */ -+#define JZ_REG_UDC_ADDR2 0x218 /* DMA channel 2 AHB memory addr */ -+#define JZ_REG_UDC_COUNT2 0x21c /* DMA channel 2 byte count */ -+ -+/* Power register bit masks */ -+#define USB_POWER_SUSPENDM 0x01 -+#define USB_POWER_RESUME 0x04 -+#define USB_POWER_HSMODE 0x10 -+#define USB_POWER_HSENAB 0x20 -+#define USB_POWER_SOFTCONN 0x40 -+ -+/* Interrupt register bit masks */ -+#define USB_INTR_SUSPEND 0x01 -+#define USB_INTR_RESUME 0x02 -+#define USB_INTR_RESET 0x04 -+ -+#define USB_INTR_EP0 0x0001 -+#define USB_INTR_INEP1 0x0002 -+#define USB_INTR_INEP2 0x0004 -+#define USB_INTR_OUTEP1 0x0002 -+ -+/* CSR0 bit masks */ -+#define USB_CSR0_OUTPKTRDY 0x01 -+#define USB_CSR0_INPKTRDY 0x02 -+#define USB_CSR0_SENTSTALL 0x04 -+#define USB_CSR0_DATAEND 0x08 -+#define USB_CSR0_SETUPEND 0x10 -+#define USB_CSR0_SENDSTALL 0x20 -+#define USB_CSR0_SVDOUTPKTRDY 0x40 -+#define USB_CSR0_SVDSETUPEND 0x80 -+ -+/* Endpoint CSR register bits */ -+#define USB_INCSRH_AUTOSET 0x80 -+#define USB_INCSRH_ISO 0x40 -+#define USB_INCSRH_MODE 0x20 -+#define USB_INCSRH_DMAREQENAB 0x10 -+#define USB_INCSRH_DMAREQMODE 0x04 -+#define USB_INCSR_CDT 0x40 -+#define USB_INCSR_SENTSTALL 0x20 -+#define USB_INCSR_SENDSTALL 0x10 -+#define USB_INCSR_FF 0x08 -+#define USB_INCSR_UNDERRUN 0x04 -+#define USB_INCSR_FFNOTEMPT 0x02 -+#define USB_INCSR_INPKTRDY 0x01 -+ -+#define USB_OUTCSRH_AUTOCLR 0x80 -+#define USB_OUTCSRH_ISO 0x40 -+#define USB_OUTCSRH_DMAREQENAB 0x20 -+#define USB_OUTCSRH_DNYT 0x10 -+#define USB_OUTCSRH_DMAREQMODE 0x08 -+#define USB_OUTCSR_CDT 0x80 -+#define USB_OUTCSR_SENTSTALL 0x40 -+#define USB_OUTCSR_SENDSTALL 0x20 -+#define USB_OUTCSR_FF 0x10 -+#define USB_OUTCSR_DATAERR 0x08 -+#define USB_OUTCSR_OVERRUN 0x04 -+#define USB_OUTCSR_FFFULL 0x02 -+#define USB_OUTCSR_OUTPKTRDY 0x01 -+ -+/* DMA control bits */ -+#define USB_CNTL_ENA 0x01 -+#define USB_CNTL_DIR_IN 0x02 -+#define USB_CNTL_MODE_1 0x04 -+#define USB_CNTL_INTR_EN 0x08 -+#define USB_CNTL_EP(n) ((n) << 4) -+#define USB_CNTL_BURST_0 (0 << 9) -+#define USB_CNTL_BURST_4 (1 << 9) -+#define USB_CNTL_BURST_8 (2 << 9) -+#define USB_CNTL_BURST_16 (3 << 9) -+ -+ -+#ifndef DEBUG -+# define DEBUG(fmt,args...) do {} while(0) -+#endif -+#ifndef DEBUG_EP0 -+# define NO_STATES -+# define DEBUG_EP0(fmt,args...) do {} while(0) -+#endif -+#ifndef DEBUG_SETUP -+# define DEBUG_SETUP(fmt,args...) do {} while(0) -+#endif -+ -+/* -+ * Local declarations. -+ */ -+static void jz4740_ep0_kick(struct jz4740_udc *dev, struct jz4740_ep *ep); -+static void jz4740_handle_ep0(struct jz4740_udc *dev, uint32_t intr); -+ -+static void done(struct jz4740_ep *ep, struct jz4740_request *req, -+ int status); -+static void pio_irq_enable(struct jz4740_ep *ep); -+static void pio_irq_disable(struct jz4740_ep *ep); -+static void stop_activity(struct jz4740_udc *dev, -+ struct usb_gadget_driver *driver); -+static void nuke(struct jz4740_ep *ep, int status); -+static void flush(struct jz4740_ep *ep); -+static void udc_set_address(struct jz4740_udc *dev, unsigned char address); -+ -+/*-------------------------------------------------------------------------*/ -+ -+/* inline functions of register read/write/set/clear */ -+ -+static inline uint8_t usb_readb(struct jz4740_udc *udc, size_t reg) -+{ -+ return readb(udc->base + reg); -+} -+ -+static inline uint16_t usb_readw(struct jz4740_udc *udc, size_t reg) -+{ -+ return readw(udc->base + reg); -+} -+ -+static inline uint32_t usb_readl(struct jz4740_udc *udc, size_t reg) -+{ -+ return readl(udc->base + reg); -+} -+ -+static inline void usb_writeb(struct jz4740_udc *udc, size_t reg, uint8_t val) -+{ -+ writeb(val, udc->base + reg); -+} -+ -+static inline void usb_writew(struct jz4740_udc *udc, size_t reg, uint16_t val) -+{ -+ writew(val, udc->base + reg); -+} -+ -+static inline void usb_writel(struct jz4740_udc *udc, size_t reg, uint32_t val) -+{ -+ writel(val, udc->base + reg); -+} -+ -+static inline void usb_setb(struct jz4740_udc *udc, size_t reg, uint8_t mask) -+{ -+ usb_writeb(udc, reg, usb_readb(udc, reg) | mask); -+} -+ -+static inline void usb_setw(struct jz4740_udc *udc, size_t reg, uint16_t mask) -+{ -+ usb_writew(udc, reg, usb_readw(udc, reg) | mask); -+} -+ -+static inline void usb_clearb(struct jz4740_udc *udc, size_t reg, uint8_t mask) -+{ -+ usb_writeb(udc, reg, usb_readb(udc, reg) & ~mask); -+} -+ -+static inline void usb_clearw(struct jz4740_udc *udc, size_t reg, uint16_t mask) -+{ -+ usb_writew(udc, reg, usb_readw(udc, reg) & ~mask); -+} -+ -+/*-------------------------------------------------------------------------*/ -+ -+static inline void jz_udc_set_index(struct jz4740_udc *udc, uint8_t index) -+{ -+ usb_writeb(udc, JZ_REG_UDC_INDEX, index); -+} -+ -+static inline void jz_udc_select_ep(struct jz4740_ep *ep) -+{ -+ jz_udc_set_index(ep->dev, ep_index(ep)); -+} -+ -+static inline int write_packet(struct jz4740_ep *ep, -+ struct jz4740_request *req, unsigned int count) -+{ -+ uint8_t *buf; -+ unsigned int length; -+ void __iomem *fifo = ep->dev->base + ep->fifo; -+ -+ DEBUG("%s:%s[%d]\n", __FILE__, __func__, __LINE__); -+ -+ buf = req->req.buf + req->req.actual; -+ -+ length = req->req.length - req->req.actual; -+ if (length > count) -+ length = count; -+ req->req.actual += length; -+ -+ DEBUG("Write %d (count %d), fifo %x\n", length, count, ep->fifo); -+ -+ writesl(fifo, buf, length >> 2); -+ writesb(fifo, &buf[length - (length & 3)], length & 3); -+ -+ return length; -+} -+ -+static int read_packet(struct jz4740_ep *ep, -+ struct jz4740_request *req, unsigned int count) -+{ -+ uint8_t *buf; -+ unsigned int length; -+ void __iomem *fifo = ep->dev->base + ep->fifo; -+ DEBUG("%s:%s[%d]\n", __FILE__, __func__, __LINE__); -+ -+ buf = req->req.buf + req->req.actual; -+ -+ length = req->req.length - req->req.actual; -+ if (length > count) -+ length = count; -+ req->req.actual += length; -+ -+ DEBUG("Read %d, fifo %x\n", length, ep->fifo); -+ -+ readsl(fifo, buf, length >> 2); -+ readsb(fifo, &buf[length - (length & 3)], length & 3); -+ -+ return length; -+} -+ -+/*-------------------------------------------------------------------------*/ -+ -+/* -+ * udc_disable - disable USB device controller -+ */ -+static void udc_disable(struct jz4740_udc *dev) -+{ -+ DEBUG("%s:%s[%d]\n", __FILE__, __func__, __LINE__); -+ -+ udc_set_address(dev, 0); -+ -+ /* Disable interrupts */ -+ usb_writew(dev, JZ_REG_UDC_INTRINE, 0); -+ usb_writew(dev, JZ_REG_UDC_INTROUTE, 0); -+ usb_writeb(dev, JZ_REG_UDC_INTRUSBE, 0); -+ -+ /* Disable DMA */ -+ usb_writel(dev, JZ_REG_UDC_CNTL1, 0); -+ usb_writel(dev, JZ_REG_UDC_CNTL2, 0); -+ -+ /* Disconnect from usb */ -+ usb_clearb(dev, JZ_REG_UDC_POWER, USB_POWER_SOFTCONN); -+ -+ /* Disable the USB PHY */ -+ clk_disable_unprepare(dev->clk); -+ -+ dev->ep0state = WAIT_FOR_SETUP; -+ dev->gadget.speed = USB_SPEED_UNKNOWN; -+ -+ return; -+} -+ -+/* -+ * udc_reinit - initialize software state -+ */ -+static void udc_reinit(struct jz4740_udc *dev) -+{ -+ int i; -+ DEBUG("%s:%s[%d]\n", __FILE__, __func__, __LINE__); -+ -+ /* device/ep0 records init */ -+ INIT_LIST_HEAD(&dev->gadget.ep_list); -+ INIT_LIST_HEAD(&dev->gadget.ep0->ep_list); -+ dev->ep0state = WAIT_FOR_SETUP; -+ -+ for (i = 0; i < UDC_MAX_ENDPOINTS; i++) { -+ struct jz4740_ep *ep = &dev->ep[i]; -+ -+ if (i != 0) -+ list_add_tail(&ep->ep.ep_list, &dev->gadget.ep_list); -+ -+ INIT_LIST_HEAD(&ep->queue); -+ ep->desc = 0; -+ ep->stopped = 0; -+ } -+} -+ -+/* until it's enabled, this UDC should be completely invisible -+ * to any USB host. -+ */ -+static void udc_enable(struct jz4740_udc *dev) -+{ -+ int i; -+ DEBUG("%s:%s[%d]\n", __FILE__, __func__, __LINE__); -+ -+ /* UDC state is incorrect - Added by River */ -+ if (dev->state != UDC_STATE_ENABLE) { -+ return; -+ } -+ -+ dev->gadget.speed = USB_SPEED_UNKNOWN; -+ -+ /* Flush FIFO for each */ -+ for (i = 0; i < UDC_MAX_ENDPOINTS; i++) { -+ struct jz4740_ep *ep = &dev->ep[i]; -+ -+ jz_udc_select_ep(ep); -+ flush(ep); -+ } -+ -+ /* Set this bit to allow the UDC entering low-power mode when -+ * there are no actions on the USB bus. -+ * UDC still works during this bit was set. -+ */ -+ jz4740_clock_udc_enable_auto_suspend(); -+ -+ /* Enable the USB PHY */ -+ clk_prepare_enable(dev->clk); -+ -+ /* Disable interrupts */ -+/* usb_writew(dev, JZ_REG_UDC_INTRINE, 0); -+ usb_writew(dev, JZ_REG_UDC_INTROUTE, 0); -+ usb_writeb(dev, JZ_REG_UDC_INTRUSBE, 0);*/ -+ -+ /* Enable interrupts */ -+ usb_setw(dev, JZ_REG_UDC_INTRINE, USB_INTR_EP0); -+ usb_setb(dev, JZ_REG_UDC_INTRUSBE, USB_INTR_RESET); -+ /* Don't enable rest of the interrupts */ -+ /* usb_setw(dev, JZ_REG_UDC_INTRINE, USB_INTR_INEP1 | USB_INTR_INEP2); -+ usb_setw(dev, JZ_REG_UDC_INTROUTE, USB_INTR_OUTEP1); */ -+ -+ /* Enable SUSPEND */ -+ /* usb_setb(dev, JZ_REG_UDC_POWER, USB_POWER_SUSPENDM); */ -+ -+ /* Enable HS Mode */ -+ usb_setb(dev, JZ_REG_UDC_POWER, USB_POWER_HSENAB); -+ -+ /* Let host detect UDC: -+ * Software must write a 1 to the PMR:USB_POWER_SOFTCONN bit to turn this -+ * transistor on and pull the USBDP pin HIGH. -+ */ -+ usb_setb(dev, JZ_REG_UDC_POWER, USB_POWER_SOFTCONN); -+ -+ return; -+} -+ -+/*-------------------------------------------------------------------------*/ -+ -+/* keeping it simple: -+ * - one bus driver, initted first; -+ * - one function driver, initted second -+ */ -+ -+/* -+ * Register entry point for the peripheral controller driver. -+ */ -+ -+static int jz4740_udc_start(struct usb_gadget *gadget, -+ struct usb_gadget_driver *driver) -+{ -+ struct jz4740_udc *udc = container_of(gadget, struct jz4740_udc, gadget); -+ -+ /* hook up the driver */ -+ udc->driver = driver; -+ -+ -+ /* then enable host detection and ep0; and we're ready -+ * for set_configuration as well as eventual disconnect. -+ */ -+ udc_enable(udc); -+ -+ DEBUG("%s: registered gadget driver '%s'\n", gadget->name, -+ driver->driver.name); -+ -+ return 0; -+} -+ -+static void stop_activity(struct jz4740_udc *dev, -+ struct usb_gadget_driver *driver) -+{ -+ int i; -+ -+ DEBUG("%s:%s[%d]\n", __FILE__, __func__, __LINE__); -+ -+ /* don't disconnect drivers more than once */ -+ if (dev->gadget.speed == USB_SPEED_UNKNOWN) -+ driver = 0; -+ dev->gadget.speed = USB_SPEED_UNKNOWN; -+ -+ /* prevent new request submissions, kill any outstanding requests */ -+ for (i = 0; i < UDC_MAX_ENDPOINTS; i++) { -+ struct jz4740_ep *ep = &dev->ep[i]; -+ -+ ep->stopped = 1; -+ -+ jz_udc_select_ep(ep); -+ nuke(ep, -ESHUTDOWN); -+ } -+ -+ /* report disconnect; the driver is already quiesced */ -+ if (driver) { -+ spin_unlock(&dev->lock); -+ driver->disconnect(&dev->gadget); -+ spin_lock(&dev->lock); -+ } -+ -+ /* re-init driver-visible data structures */ -+ udc_reinit(dev); -+} -+ -+ -+/* -+ * Unregister entry point for the peripheral controller driver. -+ */ -+static int jz4740_udc_stop(struct usb_gadget *gadget, -+ struct usb_gadget_driver *driver) -+{ -+ struct jz4740_udc *udc = container_of(gadget, struct jz4740_udc, gadget); -+ unsigned long flags; -+ DEBUG("%s:%s[%d]\n", __FILE__, __func__, __LINE__); -+ -+ spin_lock_irqsave(&udc->lock, flags); -+ udc->driver = NULL; -+ stop_activity(udc, driver); -+ spin_unlock_irqrestore(&udc->lock, flags); -+ -+ udc_disable(udc); -+ -+ DEBUG("unregistered driver '%s'\n", driver->driver.name); -+ -+ return 0; -+} -+ -+/*-------------------------------------------------------------------------*/ -+ -+/** Write request to FIFO (max write == maxp size) -+ * Return: 0 = still running, 1 = completed, negative = errno -+ * NOTE: INDEX register must be set for EP -+ */ -+static int write_fifo(struct jz4740_ep *ep, struct jz4740_request *req) -+{ -+ struct jz4740_udc *dev = ep->dev; -+ uint32_t max, csr; -+ -+ DEBUG("%s:%s[%d]\n", __FILE__, __func__, __LINE__); -+ max = le16_to_cpu(ep->desc->wMaxPacketSize); -+ -+ csr = usb_readb(dev, ep->csr); -+ -+ if (!(csr & USB_INCSR_FFNOTEMPT)) { -+ unsigned count; -+ int is_last, is_short; -+ -+ count = write_packet(ep, req, max); -+ usb_setb(dev, ep->csr, USB_INCSR_INPKTRDY); -+ -+ /* last packet is usually short (or a zlp) */ -+ if (unlikely(count != max)) -+ is_last = is_short = 1; -+ else { -+ if (likely(req->req.length != req->req.actual) -+ || req->req.zero) -+ is_last = 0; -+ else -+ is_last = 1; -+ /* interrupt/iso maxpacket may not fill the fifo */ -+ is_short = unlikely(max < ep_maxpacket(ep)); -+ } -+ -+ DEBUG("%s: wrote %s %d bytes%s%s %d left %p\n", __FUNCTION__, -+ ep->ep.name, count, -+ is_last ? "/L" : "", is_short ? "/S" : "", -+ req->req.length - req->req.actual, req); -+ -+ /* requests complete when all IN data is in the FIFO */ -+ if (is_last) { -+ done(ep, req, 0); -+ if (list_empty(&ep->queue)) { -+ pio_irq_disable(ep); -+ } -+ return 1; -+ } -+ } else { -+ DEBUG("Hmm.. %d ep FIFO is not empty!\n", ep_index(ep)); -+ } -+ -+ return 0; -+} -+ -+/** Read to request from FIFO (max read == bytes in fifo) -+ * Return: 0 = still running, 1 = completed, negative = errno -+ * NOTE: INDEX register must be set for EP -+ */ -+static int read_fifo(struct jz4740_ep *ep, struct jz4740_request *req) -+{ -+ struct jz4740_udc *dev = ep->dev; -+ uint32_t csr; -+ unsigned count, is_short; -+ -+ /* make sure there's a packet in the FIFO. */ -+ csr = usb_readb(dev, ep->csr); -+ if (!(csr & USB_OUTCSR_OUTPKTRDY)) { -+ DEBUG("%s: Packet NOT ready!\n", __FUNCTION__); -+ return -EINVAL; -+ } -+ -+ /* read all bytes from this packet */ -+ count = usb_readw(dev, JZ_REG_UDC_OUTCOUNT); -+ -+ is_short = (count < ep->ep.maxpacket); -+ -+ count = read_packet(ep, req, count); -+ -+ DEBUG("read %s %02x, %d bytes%s req %p %d/%d\n", -+ ep->ep.name, csr, count, -+ is_short ? "/S" : "", req, req->req.actual, req->req.length); -+ -+ /* Clear OutPktRdy */ -+ usb_clearb(dev, ep->csr, USB_OUTCSR_OUTPKTRDY); -+ -+ /* completion */ -+ if (is_short || req->req.actual == req->req.length) { -+ done(ep, req, 0); -+ -+ if (list_empty(&ep->queue)) -+ pio_irq_disable(ep); -+ return 1; -+ } -+ -+ /* finished that packet. the next one may be waiting... */ -+ return 0; -+} -+ -+/* -+ * done - retire a request; caller blocked irqs -+ * INDEX register is preserved to keep same -+ */ -+static void done(struct jz4740_ep *ep, struct jz4740_request *req, int status) -+{ -+ unsigned int stopped = ep->stopped; -+ uint32_t index; -+ -+ DEBUG("%s, %p\n", __FUNCTION__, ep); -+ list_del_init(&req->queue); -+ -+ if (likely(req->req.status == -EINPROGRESS)) -+ req->req.status = status; -+ else -+ status = req->req.status; -+ -+ if (status && status != -ESHUTDOWN) -+ DEBUG("complete %s req %p stat %d len %u/%u\n", -+ ep->ep.name, &req->req, status, -+ req->req.actual, req->req.length); -+ -+ /* don't modify queue heads during completion callback */ -+ ep->stopped = 1; -+ /* Read current index (completion may modify it) */ -+ index = usb_readb(ep->dev, JZ_REG_UDC_INDEX); -+ spin_unlock_irqrestore(&ep->dev->lock, ep->dev->lock_flags); -+ -+ req->req.complete(&ep->ep, &req->req); -+ -+ spin_lock_irqsave(&ep->dev->lock, ep->dev->lock_flags); -+ /* Restore index */ -+ jz_udc_set_index(ep->dev, index); -+ ep->stopped = stopped; -+} -+ -+static inline unsigned int jz4740_udc_ep_irq_enable_reg(struct jz4740_ep *ep) -+{ -+ if (ep_is_in(ep)) -+ return JZ_REG_UDC_INTRINE; -+ else -+ return JZ_REG_UDC_INTROUTE; -+} -+ -+/** Enable EP interrupt */ -+static void pio_irq_enable(struct jz4740_ep *ep) -+{ -+ DEBUG("%s: EP%d %s\n", __FUNCTION__, ep_index(ep), ep_is_in(ep) ? "IN": "OUT"); -+ -+ usb_setw(ep->dev, jz4740_udc_ep_irq_enable_reg(ep), BIT(ep_index(ep))); -+} -+ -+/** Disable EP interrupt */ -+static void pio_irq_disable(struct jz4740_ep *ep) -+{ -+ DEBUG("%s: EP%d %s\n", __FUNCTION__, ep_index(ep), ep_is_in(ep) ? "IN": "OUT"); -+ -+ usb_clearw(ep->dev, jz4740_udc_ep_irq_enable_reg(ep), BIT(ep_index(ep))); -+} -+ -+/* -+ * nuke - dequeue ALL requests -+ */ -+static void nuke(struct jz4740_ep *ep, int status) -+{ -+ struct jz4740_request *req; -+ -+ DEBUG("%s, %p\n", __FUNCTION__, ep); -+ -+ /* Flush FIFO */ -+ flush(ep); -+ -+ /* called with irqs blocked */ -+ while (!list_empty(&ep->queue)) { -+ req = list_entry(ep->queue.next, struct jz4740_request, queue); -+ done(ep, req, status); -+ } -+ -+ /* Disable IRQ if EP is enabled (has descriptor) */ -+ if (ep->desc) -+ pio_irq_disable(ep); -+} -+ -+/** Flush EP FIFO -+ * NOTE: INDEX register must be set before this call -+ */ -+static void flush(struct jz4740_ep *ep) -+{ -+ DEBUG("%s: %s\n", __FUNCTION__, ep->ep.name); -+ -+ switch (ep->type) { -+ case ep_bulk_in: -+ case ep_interrupt: -+ usb_setb(ep->dev, ep->csr, USB_INCSR_FF); -+ break; -+ case ep_bulk_out: -+ usb_setb(ep->dev, ep->csr, USB_OUTCSR_FF); -+ break; -+ case ep_control: -+ break; -+ } -+} -+ -+/** -+ * jz4740_in_epn - handle IN interrupt -+ */ -+static void jz4740_in_epn(struct jz4740_udc *dev, uint32_t ep_idx, uint32_t intr) -+{ -+ uint32_t csr; -+ struct jz4740_ep *ep = &dev->ep[ep_idx + 1]; -+ struct jz4740_request *req; -+ DEBUG("%s:%s[%d]\n", __FILE__, __func__, __LINE__); -+ -+ jz_udc_select_ep(ep); -+ -+ csr = usb_readb(dev, ep->csr); -+ DEBUG("%s: %d, csr %x\n", __FUNCTION__, ep_idx, csr); -+ -+ if (csr & USB_INCSR_SENTSTALL) { -+ DEBUG("USB_INCSR_SENTSTALL\n"); -+ usb_clearb(dev, ep->csr, USB_INCSR_SENTSTALL); -+ return; -+ } -+ -+ if (!ep->desc) { -+ DEBUG("%s: NO EP DESC\n", __FUNCTION__); -+ return; -+ } -+ -+ if (!list_empty(&ep->queue)) { -+ req = list_first_entry(&ep->queue, struct jz4740_request, queue); -+ write_fifo(ep, req); -+ } -+} -+ -+/* -+ * Bulk OUT (recv) -+ */ -+static void jz4740_out_epn(struct jz4740_udc *dev, uint32_t ep_idx, uint32_t intr) -+{ -+ struct jz4740_ep *ep = &dev->ep[ep_idx]; -+ struct jz4740_request *req; -+ -+ DEBUG("%s: %d\n", __FUNCTION__, ep_idx); -+ -+ jz_udc_select_ep(ep); -+ if (ep->desc) { -+ uint32_t csr; -+ -+ while ((csr = usb_readb(dev, ep->csr)) & -+ (USB_OUTCSR_OUTPKTRDY | USB_OUTCSR_SENTSTALL)) { -+ DEBUG("%s: %x\n", __FUNCTION__, csr); -+ -+ if (csr & USB_OUTCSR_SENTSTALL) { -+ DEBUG("%s: stall sent, flush fifo\n", -+ __FUNCTION__); -+ /* usb_set(USB_OUT_CSR1_FIFO_FLUSH, ep->csr1); */ -+ flush(ep); -+ } else if (csr & USB_OUTCSR_OUTPKTRDY) { -+ if (list_empty(&ep->queue)) -+ req = 0; -+ else -+ req = -+ list_entry(ep->queue.next, -+ struct jz4740_request, -+ queue); -+ -+ if (!req) { -+ DEBUG("%s: NULL REQ %d\n", -+ __FUNCTION__, ep_idx); -+ break; -+ } else { -+ read_fifo(ep, req); -+ } -+ } -+ } -+ } else { -+ /* Throw packet away.. */ -+ DEBUG("%s: ep %p ep_indx %d No descriptor?!?\n", __FUNCTION__, ep, ep_idx); -+ flush(ep); -+ } -+} -+ -+/** Halt specific EP -+ * Return 0 if success -+ * NOTE: Sets INDEX register to EP ! -+ */ -+static int jz4740_set_halt(struct usb_ep *_ep, int value) -+{ -+ struct jz4740_udc *dev; -+ struct jz4740_ep *ep; -+ unsigned long flags; -+ -+ DEBUG("%s:%s[%d]\n", __FILE__, __func__, __LINE__); -+ -+ ep = container_of(_ep, struct jz4740_ep, ep); -+ if (unlikely(!_ep || (!ep->desc && ep->type != ep_control))) { -+ DEBUG("%s, bad ep\n", __FUNCTION__); -+ return -EINVAL; -+ } -+ -+ dev = ep->dev; -+ -+ spin_lock_irqsave(&dev->lock, flags); -+ -+ jz_udc_select_ep(ep); -+ -+ DEBUG("%s, ep %d, val %d\n", __FUNCTION__, ep_index(ep), value); -+ -+ if (ep_index(ep) == 0) { -+ /* EP0 */ -+ usb_setb(dev, JZ_REG_UDC_CSR0, USB_CSR0_SENDSTALL); -+ } else if (ep_is_in(ep)) { -+ uint32_t csr = usb_readb(dev, ep->csr); -+ if (value && ((csr & USB_INCSR_FFNOTEMPT) -+ || !list_empty(&ep->queue))) { -+ /* -+ * Attempts to halt IN endpoints will fail (returning -EAGAIN) -+ * if any transfer requests are still queued, or if the controller -+ * FIFO still holds bytes that the host hasnÂ’t collected. -+ */ -+ spin_unlock_irqrestore(&dev->lock, flags); -+ DEBUG -+ ("Attempt to halt IN endpoint failed (returning -EAGAIN) %d %d\n", -+ (csr & USB_INCSR_FFNOTEMPT), -+ !list_empty(&ep->queue)); -+ return -EAGAIN; -+ } -+ flush(ep); -+ if (value) { -+ usb_setb(dev, ep->csr, USB_INCSR_SENDSTALL); -+ } else { -+ usb_clearb(dev, ep->csr, USB_INCSR_SENDSTALL); -+ usb_setb(dev, ep->csr, USB_INCSR_CDT); -+ } -+ } else { -+ -+ flush(ep); -+ if (value) { -+ usb_setb(dev, ep->csr, USB_OUTCSR_SENDSTALL); -+ } else { -+ usb_clearb(dev, ep->csr, USB_OUTCSR_SENDSTALL); -+ usb_setb(dev, ep->csr, USB_OUTCSR_CDT); -+ } -+ } -+ -+ ep->stopped = value; -+ -+ spin_unlock_irqrestore(&dev->lock, flags); -+ -+ DEBUG("%s %s halted\n", _ep->name, value == 0 ? "NOT" : "IS"); -+ -+ return 0; -+} -+ -+ -+static int jz4740_ep_enable(struct usb_ep *_ep, -+ const struct usb_endpoint_descriptor *desc) -+{ -+ struct jz4740_ep *ep; -+ struct jz4740_udc *dev; -+ unsigned long flags; -+ uint32_t max, csrh = 0; -+ -+ DEBUG("%s: trying to enable %s\n", __FUNCTION__, _ep->name); -+ -+ if (!_ep || !desc) -+ return -EINVAL; -+ -+ ep = container_of(_ep, struct jz4740_ep, ep); -+ if (ep->desc || ep->type == ep_control -+ || desc->bDescriptorType != USB_DT_ENDPOINT -+ || ep->bEndpointAddress != desc->bEndpointAddress) { -+ DEBUG("%s, bad ep or descriptor\n", __FUNCTION__); -+ return -EINVAL; -+ } -+ -+ /* xfer types must match, except that interrupt ~= bulk */ -+ if (ep->bmAttributes != desc->bmAttributes -+ && ep->bmAttributes != USB_ENDPOINT_XFER_BULK -+ && desc->bmAttributes != USB_ENDPOINT_XFER_INT) { -+ DEBUG("%s, %s type mismatch\n", __FUNCTION__, _ep->name); -+ return -EINVAL; -+ } -+ -+ dev = ep->dev; -+ if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) { -+ DEBUG("%s, bogus device state\n", __FUNCTION__); -+ return -ESHUTDOWN; -+ } -+ -+ max = le16_to_cpu(desc->wMaxPacketSize); -+ -+ spin_lock_irqsave(&ep->dev->lock, flags); -+ -+ /* Configure the endpoint */ -+ jz_udc_select_ep(ep); -+ if (ep_is_in(ep)) { -+ usb_writew(dev, JZ_REG_UDC_INMAXP, max); -+ switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { -+ case USB_ENDPOINT_XFER_BULK: -+ case USB_ENDPOINT_XFER_INT: -+ csrh &= ~USB_INCSRH_ISO; -+ break; -+ case USB_ENDPOINT_XFER_ISOC: -+ csrh |= USB_INCSRH_ISO; -+ break; -+ } -+ usb_writeb(dev, JZ_REG_UDC_INCSRH, csrh); -+ } -+ else { -+ usb_writew(dev, JZ_REG_UDC_OUTMAXP, max); -+ switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { -+ case USB_ENDPOINT_XFER_BULK: -+ csrh &= ~USB_OUTCSRH_ISO; -+ break; -+ case USB_ENDPOINT_XFER_INT: -+ csrh &= ~USB_OUTCSRH_ISO; -+ csrh |= USB_OUTCSRH_DNYT; -+ break; -+ case USB_ENDPOINT_XFER_ISOC: -+ csrh |= USB_OUTCSRH_ISO; -+ break; -+ } -+ usb_writeb(dev, JZ_REG_UDC_OUTCSRH, csrh); -+ } -+ -+ -+ ep->stopped = 0; -+ ep->desc = desc; -+ ep->ep.maxpacket = max; -+ -+ spin_unlock_irqrestore(&ep->dev->lock, flags); -+ -+ /* Reset halt state (does flush) */ -+ jz4740_set_halt(_ep, 0); -+ -+ DEBUG("%s: enabled %s\n", __FUNCTION__, _ep->name); -+ -+ return 0; -+} -+ -+/** Disable EP -+ * NOTE: Sets INDEX register -+ */ -+static int jz4740_ep_disable(struct usb_ep *_ep) -+{ -+ struct jz4740_ep *ep; -+ unsigned long flags; -+ -+ DEBUG("%s, %p\n", __FUNCTION__, _ep); -+ -+ ep = container_of(_ep, struct jz4740_ep, ep); -+ if (!_ep || !ep->desc) { -+ DEBUG("%s, %s not enabled\n", __FUNCTION__, -+ _ep ? ep->ep.name : NULL); -+ return -EINVAL; -+ } -+ -+ spin_lock_irqsave(&ep->dev->lock, flags); -+ -+ jz_udc_select_ep(ep); -+ -+ /* Nuke all pending requests (does flush) */ -+ nuke(ep, -ESHUTDOWN); -+ -+ /* Disable ep IRQ */ -+ pio_irq_disable(ep); -+ -+ ep->desc = 0; -+ ep->stopped = 1; -+ -+ spin_unlock_irqrestore(&ep->dev->lock, flags); -+ -+ DEBUG("%s: disabled %s\n", __FUNCTION__, _ep->name); -+ return 0; -+} -+ -+static struct usb_request *jz4740_alloc_request(struct usb_ep *ep, gfp_t gfp_flags) -+{ -+ struct jz4740_request *req; -+ -+ req = kzalloc(sizeof(*req), gfp_flags); -+ if (!req) -+ return NULL; -+ -+ INIT_LIST_HEAD(&req->queue); -+ -+ return &req->req; -+} -+ -+static void jz4740_free_request(struct usb_ep *ep, struct usb_request *_req) -+{ -+ struct jz4740_request *req; -+ -+ req = container_of(_req, struct jz4740_request, req); -+ WARN_ON(!list_empty(&req->queue)); -+ -+ kfree(req); -+} -+ -+/*--------------------------------------------------------------------*/ -+ -+/** Queue one request -+ * Kickstart transfer if needed -+ * NOTE: Sets INDEX register -+ */ -+static int jz4740_queue(struct usb_ep *_ep, struct usb_request *_req, -+ gfp_t gfp_flags) -+{ -+ struct jz4740_request *req; -+ struct jz4740_ep *ep; -+ struct jz4740_udc *dev; -+ -+ DEBUG("%s, %p\n", __FUNCTION__, _ep); -+ -+ req = container_of(_req, struct jz4740_request, req); -+ if (unlikely -+ (!_req || !_req->complete || !_req->buf -+ || !list_empty(&req->queue))) { -+ DEBUG("%s, bad params\n", __FUNCTION__); -+ return -EINVAL; -+ } -+ -+ ep = container_of(_ep, struct jz4740_ep, ep); -+ if (unlikely(!_ep || (!ep->desc && ep->type != ep_control))) { -+ DEBUG("%s, bad ep\n", __FUNCTION__); -+ return -EINVAL; -+ } -+ -+ dev = ep->dev; -+ if (unlikely(!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)) { -+ DEBUG("%s, bogus device state %p\n", __FUNCTION__, dev->driver); -+ return -ESHUTDOWN; -+ } -+ -+ DEBUG("%s queue req %p, len %d buf %p\n", _ep->name, _req, _req->length, -+ _req->buf); -+ -+ spin_lock_irqsave(&dev->lock, dev->lock_flags); -+ -+ _req->status = -EINPROGRESS; -+ _req->actual = 0; -+ -+ /* kickstart this i/o queue? */ -+ DEBUG("Add to %d Q %d %d\n", ep_index(ep), list_empty(&ep->queue), -+ ep->stopped); -+ if (list_empty(&ep->queue) && likely(!ep->stopped)) { -+ uint32_t csr; -+ -+ if (unlikely(ep_index(ep) == 0)) { -+ /* EP0 */ -+ list_add_tail(&req->queue, &ep->queue); -+ jz4740_ep0_kick(dev, ep); -+ req = 0; -+ } -+ else if (ep_is_in(ep)) { -+ /* EP1 & EP2 */ -+ jz_udc_select_ep(ep); -+ csr = usb_readb(dev, ep->csr); -+ pio_irq_enable(ep); -+ if (!(csr & USB_INCSR_FFNOTEMPT)) { -+ if (write_fifo(ep, req) == 1) -+ req = 0; -+ } -+ } else { -+ /* EP1 */ -+ jz_udc_select_ep(ep); -+ csr = usb_readb(dev, ep->csr); -+ pio_irq_enable(ep); -+ if (csr & USB_OUTCSR_OUTPKTRDY) { -+ if (read_fifo(ep, req) == 1) -+ req = 0; -+ } -+ } -+ } -+ -+ /* pio or dma irq handler advances the queue. */ -+ if (likely(req != 0)) -+ list_add_tail(&req->queue, &ep->queue); -+ -+ spin_unlock_irqrestore(&dev->lock, dev->lock_flags); -+ -+ return 0; -+} -+ -+/* dequeue JUST ONE request */ -+static int jz4740_dequeue(struct usb_ep *_ep, struct usb_request *_req) -+{ -+ struct jz4740_ep *ep; -+ struct jz4740_request *req; -+ unsigned long flags; -+ -+ DEBUG("%s, %p\n", __FUNCTION__, _ep); -+ -+ ep = container_of(_ep, struct jz4740_ep, ep); -+ if (!_ep || ep->type == ep_control) -+ return -EINVAL; -+ -+ spin_lock_irqsave(&ep->dev->lock, flags); -+ -+ /* make sure it's actually queued on this endpoint */ -+ list_for_each_entry(req, &ep->queue, queue) { -+ if (&req->req == _req) -+ break; -+ } -+ if (&req->req != _req) { -+ spin_unlock_irqrestore(&ep->dev->lock, flags); -+ return -EINVAL; -+ } -+ done(ep, req, -ECONNRESET); -+ -+ spin_unlock_irqrestore(&ep->dev->lock, flags); -+ return 0; -+} -+ -+/** Return bytes in EP FIFO -+ * NOTE: Sets INDEX register to EP -+ */ -+static int jz4740_fifo_status(struct usb_ep *_ep) -+{ -+ uint32_t csr; -+ int count = 0; -+ struct jz4740_ep *ep; -+ unsigned long flags; -+ -+ ep = container_of(_ep, struct jz4740_ep, ep); -+ if (!_ep) { -+ DEBUG("%s, bad ep\n", __FUNCTION__); -+ return -ENODEV; -+ } -+ -+ DEBUG("%s, %d\n", __FUNCTION__, ep_index(ep)); -+ -+ /* LPD can't report unclaimed bytes from IN fifos */ -+ if (ep_is_in(ep)) -+ return -EOPNOTSUPP; -+ -+ spin_lock_irqsave(&ep->dev->lock, flags); -+ jz_udc_select_ep(ep); -+ -+ csr = usb_readb(ep->dev, ep->csr); -+ if (ep->dev->gadget.speed != USB_SPEED_UNKNOWN || -+ csr & 0x1) { -+ count = usb_readw(ep->dev, JZ_REG_UDC_OUTCOUNT); -+ } -+ -+ spin_unlock_irqrestore(&ep->dev->lock, flags); -+ -+ return count; -+} -+ -+/** Flush EP FIFO -+ * NOTE: Sets INDEX register to EP -+ */ -+static void jz4740_fifo_flush(struct usb_ep *_ep) -+{ -+ struct jz4740_ep *ep; -+ unsigned long flags; -+ -+ DEBUG("%s:%s[%d]\n", __FILE__, __func__, __LINE__); -+ -+ ep = container_of(_ep, struct jz4740_ep, ep); -+ if (unlikely(!_ep || (!ep->desc && ep->type == ep_control))) { -+ DEBUG("%s, bad ep\n", __FUNCTION__); -+ return; -+ } -+ -+ spin_lock_irqsave(&ep->dev->lock, flags); -+ -+ jz_udc_select_ep(ep); -+ flush(ep); -+ -+ spin_unlock_irqrestore(&ep->dev->lock, flags); -+} -+ -+/****************************************************************/ -+/* End Point 0 related functions */ -+/****************************************************************/ -+ -+/* return: 0 = still running, 1 = completed, negative = errno */ -+static int write_fifo_ep0(struct jz4740_ep *ep, struct jz4740_request *req) -+{ -+ uint32_t max; -+ unsigned count; -+ int is_last; -+ -+ DEBUG("%s:%s[%d]\n", __FILE__, __func__, __LINE__); -+ max = ep_maxpacket(ep); -+ -+ count = write_packet(ep, req, max); -+ -+ /* last packet is usually short (or a zlp) */ -+ if (unlikely(count != max)) -+ is_last = 1; -+ else { -+ if (likely(req->req.length != req->req.actual) || req->req.zero) -+ is_last = 0; -+ else -+ is_last = 1; -+ } -+ -+ DEBUG_EP0("%s: wrote %s %d bytes%s %d left %p\n", __FUNCTION__, -+ ep->ep.name, count, -+ is_last ? "/L" : "", req->req.length - req->req.actual, req); -+ -+ /* requests complete when all IN data is in the FIFO */ -+ if (is_last) { -+ done(ep, req, 0); -+ return 1; -+ } -+ -+ return 0; -+} -+ -+static inline int jz4740_fifo_read(struct jz4740_ep *ep, -+ unsigned char *cp, int max) -+{ -+ int bytes; -+ int count = usb_readw(ep->dev, JZ_REG_UDC_OUTCOUNT); -+ -+ if (count > max) -+ count = max; -+ bytes = count; -+ while (count--) -+ *cp++ = usb_readb(ep->dev, ep->fifo); -+ -+ return bytes; -+} -+ -+static inline void jz4740_fifo_write(struct jz4740_ep *ep, -+ unsigned char *cp, int count) -+{ -+ DEBUG("fifo_write: %d %d\n", ep_index(ep), count); -+ while (count--) -+ usb_writeb(ep->dev, ep->fifo, *cp++); -+} -+ -+static int read_fifo_ep0(struct jz4740_ep *ep, struct jz4740_request *req) -+{ -+ struct jz4740_udc *dev = ep->dev; -+ uint32_t csr; -+ uint8_t *buf; -+ unsigned bufferspace, count, is_short; -+ -+ DEBUG_EP0("%s\n", __FUNCTION__); -+ -+ csr = usb_readb(dev, JZ_REG_UDC_CSR0); -+ if (!(csr & USB_CSR0_OUTPKTRDY)) -+ return 0; -+ -+ buf = req->req.buf + req->req.actual; -+ prefetchw(buf); -+ bufferspace = req->req.length - req->req.actual; -+ -+ /* read all bytes from this packet */ -+ if (likely(csr & USB_CSR0_OUTPKTRDY)) { -+ count = usb_readw(dev, JZ_REG_UDC_OUTCOUNT); -+ req->req.actual += min(count, bufferspace); -+ } else /* zlp */ -+ count = 0; -+ -+ is_short = (count < ep->ep.maxpacket); -+ DEBUG_EP0("read %s %02x, %d bytes%s req %p %d/%d\n", -+ ep->ep.name, csr, count, -+ is_short ? "/S" : "", req, req->req.actual, req->req.length); -+ -+ while (likely(count-- != 0)) { -+ uint8_t byte = (uint8_t)usb_readl(dev, ep->fifo); -+ -+ if (unlikely(bufferspace == 0)) { -+ /* this happens when the driver's buffer -+ * is smaller than what the host sent. -+ * discard the extra data. -+ */ -+ if (req->req.status != -EOVERFLOW) -+ DEBUG_EP0("%s overflow %d\n", ep->ep.name, -+ count); -+ req->req.status = -EOVERFLOW; -+ } else { -+ *buf++ = byte; -+ bufferspace--; -+ } -+ } -+ -+ /* completion */ -+ if (is_short || req->req.actual == req->req.length) { -+ done(ep, req, 0); -+ return 1; -+ } -+ -+ /* finished that packet. the next one may be waiting... */ -+ return 0; -+} -+ -+/** -+ * udc_set_address - set the USB address for this device -+ * @address: -+ * -+ * Called from control endpoint function after it decodes a set address setup packet. -+ */ -+static void udc_set_address(struct jz4740_udc *dev, unsigned char address) -+{ -+ DEBUG_EP0("%s: %d\n", __FUNCTION__, address); -+ -+ usb_writeb(dev, JZ_REG_UDC_FADDR, address); -+} -+ -+/* -+ * DATA_STATE_RECV (USB_CSR0_OUTPKTRDY) -+ * - if error -+ * set USB_CSR0_SVDOUTPKTRDY | USB_CSR0_DATAEND | USB_CSR0_SENDSTALL bits -+ * - else -+ * set USB_CSR0_SVDOUTPKTRDY bit -+ if last set USB_CSR0_DATAEND bit -+ */ -+static void jz4740_ep0_out(struct jz4740_udc *dev, uint32_t csr, int kickstart) -+{ -+ struct jz4740_request *req; -+ struct jz4740_ep *ep = &dev->ep[0]; -+ int ret; -+ -+ DEBUG_EP0("%s: %x\n", __FUNCTION__, csr); -+ -+ if (list_empty(&ep->queue)) -+ req = 0; -+ else -+ req = list_entry(ep->queue.next, struct jz4740_request, queue); -+ -+ if (req) { -+ if (req->req.length == 0) { -+ DEBUG_EP0("ZERO LENGTH OUT!\n"); -+ usb_setb(dev, JZ_REG_UDC_CSR0, (USB_CSR0_SVDOUTPKTRDY | USB_CSR0_DATAEND)); -+ dev->ep0state = WAIT_FOR_SETUP; -+ return; -+ } else if (kickstart) { -+ usb_setb(dev, JZ_REG_UDC_CSR0, (USB_CSR0_SVDOUTPKTRDY)); -+ return; -+ } -+ ret = read_fifo_ep0(ep, req); -+ if (ret) { -+ /* Done! */ -+ DEBUG_EP0("%s: finished, waiting for status\n", -+ __FUNCTION__); -+ usb_setb(dev, JZ_REG_UDC_CSR0, (USB_CSR0_SVDOUTPKTRDY | USB_CSR0_DATAEND)); -+ dev->ep0state = WAIT_FOR_SETUP; -+ } else { -+ /* Not done yet.. */ -+ DEBUG_EP0("%s: not finished\n", __FUNCTION__); -+ usb_setb(dev, JZ_REG_UDC_CSR0, USB_CSR0_SVDOUTPKTRDY); -+ } -+ } else { -+ DEBUG_EP0("NO REQ??!\n"); -+ } -+} -+ -+/* -+ * DATA_STATE_XMIT -+ */ -+static int jz4740_ep0_in(struct jz4740_udc *dev, uint32_t csr) -+{ -+ struct jz4740_request *req; -+ struct jz4740_ep *ep = &dev->ep[0]; -+ int ret, need_zlp = 0; -+ -+ DEBUG_EP0("%s: %x\n", __FUNCTION__, csr); -+ -+ if (list_empty(&ep->queue)) -+ req = 0; -+ else -+ req = list_entry(ep->queue.next, struct jz4740_request, queue); -+ -+ if (!req) { -+ DEBUG_EP0("%s: NULL REQ\n", __FUNCTION__); -+ return 0; -+ } -+ -+ if (req->req.length == 0) { -+ usb_setb(dev, JZ_REG_UDC_CSR0, (USB_CSR0_INPKTRDY | USB_CSR0_DATAEND)); -+ dev->ep0state = WAIT_FOR_SETUP; -+ return 1; -+ } -+ -+ if (req->req.length - req->req.actual == EP0_MAXPACKETSIZE) { -+ /* Next write will end with the packet size, */ -+ /* so we need zero-length-packet */ -+ need_zlp = 1; -+ } -+ -+ ret = write_fifo_ep0(ep, req); -+ -+ if (ret == 1 && !need_zlp) { -+ /* Last packet */ -+ DEBUG_EP0("%s: finished, waiting for status\n", __FUNCTION__); -+ -+ usb_setb(dev, JZ_REG_UDC_CSR0, (USB_CSR0_INPKTRDY | USB_CSR0_DATAEND)); -+ dev->ep0state = WAIT_FOR_SETUP; -+ } else { -+ DEBUG_EP0("%s: not finished\n", __FUNCTION__); -+ usb_setb(dev, JZ_REG_UDC_CSR0, USB_CSR0_INPKTRDY); -+ } -+ -+ if (need_zlp) { -+ DEBUG_EP0("%s: Need ZLP!\n", __FUNCTION__); -+ usb_setb(dev, JZ_REG_UDC_CSR0, USB_CSR0_INPKTRDY); -+ dev->ep0state = DATA_STATE_NEED_ZLP; -+ } -+ -+ return 1; -+} -+ -+static int jz4740_handle_get_status(struct jz4740_udc *dev, -+ struct usb_ctrlrequest *ctrl) -+{ -+ struct jz4740_ep *ep0 = &dev->ep[0]; -+ struct jz4740_ep *qep; -+ int reqtype = (ctrl->bRequestType & USB_RECIP_MASK); -+ uint16_t val = 0; -+ -+ DEBUG("%s:%s[%d]\n", __FILE__, __func__, __LINE__); -+ -+ if (reqtype == USB_RECIP_INTERFACE) { -+ /* This is not supported. -+ * And according to the USB spec, this one does nothing.. -+ * Just return 0 -+ */ -+ DEBUG_SETUP("GET_STATUS: USB_RECIP_INTERFACE\n"); -+ } else if (reqtype == USB_RECIP_DEVICE) { -+ DEBUG_SETUP("GET_STATUS: USB_RECIP_DEVICE\n"); -+ val |= (1 << 0); /* Self powered */ -+ /*val |= (1<<1); *//* Remote wakeup */ -+ } else if (reqtype == USB_RECIP_ENDPOINT) { -+ int ep_num = (ctrl->wIndex & ~USB_DIR_IN); -+ -+ DEBUG_SETUP -+ ("GET_STATUS: USB_RECIP_ENDPOINT (%d), ctrl->wLength = %d\n", -+ ep_num, ctrl->wLength); -+ -+ if (ctrl->wLength > 2 || ep_num > 3) -+ return -EOPNOTSUPP; -+ -+ qep = &dev->ep[ep_num]; -+ if (ep_is_in(qep) != ((ctrl->wIndex & USB_DIR_IN) ? 1 : 0) -+ && ep_index(qep) != 0) { -+ return -EOPNOTSUPP; -+ } -+ -+ jz_udc_select_ep(qep); -+ -+ /* Return status on next IN token */ -+ switch (qep->type) { -+ case ep_control: -+ val = -+ (usb_readb(dev, qep->csr) & USB_CSR0_SENDSTALL) == -+ USB_CSR0_SENDSTALL; -+ break; -+ case ep_bulk_in: -+ case ep_interrupt: -+ val = -+ (usb_readb(dev, qep->csr) & USB_INCSR_SENDSTALL) == -+ USB_INCSR_SENDSTALL; -+ break; -+ case ep_bulk_out: -+ val = -+ (usb_readb(dev, qep->csr) & USB_OUTCSR_SENDSTALL) == -+ USB_OUTCSR_SENDSTALL; -+ break; -+ } -+ -+ /* Back to EP0 index */ -+ jz_udc_set_index(dev, 0); -+ -+ DEBUG_SETUP("GET_STATUS, ep: %d (%x), val = %d\n", ep_num, -+ ctrl->wIndex, val); -+ } else { -+ DEBUG_SETUP("Unknown REQ TYPE: %d\n", reqtype); -+ return -EOPNOTSUPP; -+ } -+ -+ /* Clear "out packet ready" */ -+ usb_setb(dev, JZ_REG_UDC_CSR0, USB_CSR0_SVDOUTPKTRDY); -+ /* Put status to FIFO */ -+ jz4740_fifo_write(ep0, (uint8_t *)&val, sizeof(val)); -+ /* Issue "In packet ready" */ -+ usb_setb(dev, JZ_REG_UDC_CSR0, (USB_CSR0_INPKTRDY | USB_CSR0_DATAEND)); -+ -+ return 0; -+} -+ -+/* -+ * WAIT_FOR_SETUP (OUTPKTRDY) -+ * - read data packet from EP0 FIFO -+ * - decode command -+ * - if error -+ * set USB_CSR0_SVDOUTPKTRDY | USB_CSR0_DATAEND | USB_CSR0_SENDSTALL bits -+ * - else -+ * set USB_CSR0_SVDOUTPKTRDY | USB_CSR0_DATAEND bits -+ */ -+static void jz4740_ep0_setup(struct jz4740_udc *dev, uint32_t csr) -+{ -+ struct jz4740_ep *ep = &dev->ep[0]; -+ struct usb_ctrlrequest ctrl; -+ int i; -+ -+ DEBUG_SETUP("%s: %x\n", __FUNCTION__, csr); -+ -+ /* Nuke all previous transfers */ -+ nuke(ep, -EPROTO); -+ -+ /* read control req from fifo (8 bytes) */ -+ jz4740_fifo_read(ep, (unsigned char *)&ctrl, 8); -+ -+ DEBUG_SETUP("SETUP %02x.%02x v%04x i%04x l%04x\n", -+ ctrl.bRequestType, ctrl.bRequest, -+ ctrl.wValue, ctrl.wIndex, ctrl.wLength); -+ -+ /* Set direction of EP0 */ -+ if (likely(ctrl.bRequestType & USB_DIR_IN)) { -+ ep->bEndpointAddress |= USB_DIR_IN; -+ } else { -+ ep->bEndpointAddress &= ~USB_DIR_IN; -+ } -+ -+ /* Handle some SETUP packets ourselves */ -+ switch (ctrl.bRequest) { -+ case USB_REQ_SET_ADDRESS: -+ if (ctrl.bRequestType != (USB_TYPE_STANDARD | USB_RECIP_DEVICE)) -+ break; -+ -+ DEBUG_SETUP("USB_REQ_SET_ADDRESS (%d)\n", ctrl.wValue); -+ udc_set_address(dev, ctrl.wValue); -+ usb_setb(dev, JZ_REG_UDC_CSR0, (USB_CSR0_SVDOUTPKTRDY | USB_CSR0_DATAEND)); -+ return; -+ -+ case USB_REQ_SET_CONFIGURATION: -+ if (ctrl.bRequestType != (USB_TYPE_STANDARD | USB_RECIP_DEVICE)) -+ break; -+ -+ DEBUG_SETUP("USB_REQ_SET_CONFIGURATION (%d)\n", ctrl.wValue); -+/* usb_setb(JZ_REG_UDC_CSR0, (USB_CSR0_SVDOUTPKTRDY | USB_CSR0_DATAEND));*/ -+ -+ /* Enable RESUME and SUSPEND interrupts */ -+ usb_setb(dev, JZ_REG_UDC_INTRUSBE, (USB_INTR_RESUME | USB_INTR_SUSPEND)); -+ break; -+ -+ case USB_REQ_SET_INTERFACE: -+ if (ctrl.bRequestType != (USB_TYPE_STANDARD | USB_RECIP_DEVICE)) -+ break; -+ -+ DEBUG_SETUP("USB_REQ_SET_INTERFACE (%d)\n", ctrl.wValue); -+/* usb_setb(JZ_REG_UDC_CSR0, (USB_CSR0_SVDOUTPKTRDY | USB_CSR0_DATAEND));*/ -+ break; -+ -+ case USB_REQ_GET_STATUS: -+ if (jz4740_handle_get_status(dev, &ctrl) == 0) -+ return; -+ -+ case USB_REQ_CLEAR_FEATURE: -+ case USB_REQ_SET_FEATURE: -+ if (ctrl.bRequestType == USB_RECIP_ENDPOINT) { -+ struct jz4740_ep *qep; -+ int ep_num = (ctrl.wIndex & 0x0f); -+ -+ /* Support only HALT feature */ -+ if (ctrl.wValue != 0 || ctrl.wLength != 0 -+ || ep_num > 3 || ep_num < 1) -+ break; -+ -+ qep = &dev->ep[ep_num]; -+ spin_unlock(&dev->lock); -+ if (ctrl.bRequest == USB_REQ_SET_FEATURE) { -+ DEBUG_SETUP("SET_FEATURE (%d)\n", -+ ep_num); -+ jz4740_set_halt(&qep->ep, 1); -+ } else { -+ DEBUG_SETUP("CLR_FEATURE (%d)\n", -+ ep_num); -+ jz4740_set_halt(&qep->ep, 0); -+ } -+ spin_lock(&dev->lock); -+ -+ jz_udc_set_index(dev, 0); -+ -+ /* Reply with a ZLP on next IN token */ -+ usb_setb(dev, JZ_REG_UDC_CSR0, -+ (USB_CSR0_SVDOUTPKTRDY | USB_CSR0_DATAEND)); -+ return; -+ } -+ break; -+ -+ default: -+ break; -+ } -+ -+ /* gadget drivers see class/vendor specific requests, -+ * {SET,GET}_{INTERFACE,DESCRIPTOR,CONFIGURATION}, -+ * and more. -+ */ -+ if (dev->driver) { -+ /* device-2-host (IN) or no data setup command, process immediately */ -+ spin_unlock(&dev->lock); -+ -+ i = dev->driver->setup(&dev->gadget, &ctrl); -+ spin_lock(&dev->lock); -+ -+ if (unlikely(i < 0)) { -+ /* setup processing failed, force stall */ -+ DEBUG_SETUP -+ (" --> ERROR: gadget setup FAILED (stalling), setup returned %d\n", -+ i); -+ jz_udc_set_index(dev, 0); -+ usb_setb(dev, JZ_REG_UDC_CSR0, (USB_CSR0_SVDOUTPKTRDY | USB_CSR0_DATAEND | USB_CSR0_SENDSTALL)); -+ -+ /* ep->stopped = 1; */ -+ dev->ep0state = WAIT_FOR_SETUP; -+ } -+ else { -+ DEBUG_SETUP("gadget driver setup ok (%d)\n", ctrl.wLength); -+/* if (!ctrl.wLength) { -+ usb_setb(JZ_REG_UDC_CSR0, USB_CSR0_SVDOUTPKTRDY); -+ }*/ -+ } -+ } -+} -+ -+/* -+ * DATA_STATE_NEED_ZLP -+ */ -+static void jz4740_ep0_in_zlp(struct jz4740_udc *dev, uint32_t csr) -+{ -+ DEBUG_EP0("%s: %x\n", __FUNCTION__, csr); -+ -+ usb_setb(dev, JZ_REG_UDC_CSR0, (USB_CSR0_INPKTRDY | USB_CSR0_DATAEND)); -+ dev->ep0state = WAIT_FOR_SETUP; -+} -+ -+/* -+ * handle ep0 interrupt -+ */ -+static void jz4740_handle_ep0(struct jz4740_udc *dev, uint32_t intr) -+{ -+ struct jz4740_ep *ep = &dev->ep[0]; -+ uint32_t csr; -+ -+ DEBUG("%s:%s[%d]\n", __FILE__, __func__, __LINE__); -+ /* Set index 0 */ -+ jz_udc_set_index(dev, 0); -+ csr = usb_readb(dev, JZ_REG_UDC_CSR0); -+ -+ DEBUG_EP0("%s: csr = %x state = \n", __FUNCTION__, csr);//, state_names[dev->ep0state]); -+ -+ /* -+ * if SENT_STALL is set -+ * - clear the SENT_STALL bit -+ */ -+ if (csr & USB_CSR0_SENTSTALL) { -+ DEBUG_EP0("%s: USB_CSR0_SENTSTALL is set: %x\n", __FUNCTION__, csr); -+ usb_clearb(dev, JZ_REG_UDC_CSR0, USB_CSR0_SENDSTALL | USB_CSR0_SENTSTALL); -+ nuke(ep, -ECONNABORTED); -+ dev->ep0state = WAIT_FOR_SETUP; -+ return; -+ } -+ -+ /* -+ * if a transfer is in progress && INPKTRDY and OUTPKTRDY are clear -+ * - fill EP0 FIFO -+ * - if last packet -+ * - set IN_PKT_RDY | DATA_END -+ * - else -+ * set IN_PKT_RDY -+ */ -+ if (!(csr & (USB_CSR0_INPKTRDY | USB_CSR0_OUTPKTRDY))) { -+ DEBUG_EP0("%s: INPKTRDY and OUTPKTRDY are clear\n", -+ __FUNCTION__); -+ -+ switch (dev->ep0state) { -+ case DATA_STATE_XMIT: -+ DEBUG_EP0("continue with DATA_STATE_XMIT\n"); -+ jz4740_ep0_in(dev, csr); -+ return; -+ case DATA_STATE_NEED_ZLP: -+ DEBUG_EP0("continue with DATA_STATE_NEED_ZLP\n"); -+ jz4740_ep0_in_zlp(dev, csr); -+ return; -+ default: -+ /* Stall? */ -+// DEBUG_EP0("Odd state!! state = %s\n", -+// state_names[dev->ep0state]); -+ dev->ep0state = WAIT_FOR_SETUP; -+ /* nuke(ep, 0); */ -+ /* usb_setb(ep->csr, USB_CSR0_SENDSTALL); */ -+// break; -+ return; -+ } -+ } -+ -+ /* -+ * if SETUPEND is set -+ * - abort the last transfer -+ * - set SERVICED_SETUP_END_BIT -+ */ -+ if (csr & USB_CSR0_SETUPEND) { -+ DEBUG_EP0("%s: USB_CSR0_SETUPEND is set: %x\n", __FUNCTION__, csr); -+ -+ usb_setb(dev, JZ_REG_UDC_CSR0, USB_CSR0_SVDSETUPEND); -+ nuke(ep, 0); -+ dev->ep0state = WAIT_FOR_SETUP; -+ } -+ -+ /* -+ * if USB_CSR0_OUTPKTRDY is set -+ * - read data packet from EP0 FIFO -+ * - decode command -+ * - if error -+ * set SVDOUTPKTRDY | DATAEND | SENDSTALL bits -+ * - else -+ * set SVDOUTPKTRDY | DATAEND bits -+ */ -+ if (csr & USB_CSR0_OUTPKTRDY) { -+ -+ DEBUG_EP0("%s: EP0_OUT_PKT_RDY is set: %x\n", __FUNCTION__, -+ csr); -+ -+ switch (dev->ep0state) { -+ case WAIT_FOR_SETUP: -+ DEBUG_EP0("WAIT_FOR_SETUP\n"); -+ jz4740_ep0_setup(dev, csr); -+ break; -+ -+ case DATA_STATE_RECV: -+ DEBUG_EP0("DATA_STATE_RECV\n"); -+ jz4740_ep0_out(dev, csr, 0); -+ break; -+ -+ default: -+ /* send stall? */ -+ DEBUG_EP0("strange state!! 2. send stall? state = %d\n", -+ dev->ep0state); -+ break; -+ } -+ } -+} -+ -+static void jz4740_ep0_kick(struct jz4740_udc *dev, struct jz4740_ep *ep) -+{ -+ uint32_t csr; -+ -+ jz_udc_set_index(dev, 0); -+ -+ DEBUG_EP0("%s: %x\n", __FUNCTION__, csr); -+ -+ /* Clear "out packet ready" */ -+ -+ if (ep_is_in(ep)) { -+ usb_setb(dev, JZ_REG_UDC_CSR0, USB_CSR0_SVDOUTPKTRDY); -+ csr = usb_readb(dev, JZ_REG_UDC_CSR0); -+ dev->ep0state = DATA_STATE_XMIT; -+ jz4740_ep0_in(dev, csr); -+ } else { -+ csr = usb_readb(dev, JZ_REG_UDC_CSR0); -+ dev->ep0state = DATA_STATE_RECV; -+ jz4740_ep0_out(dev, csr, 1); -+ } -+} -+ -+/** Handle USB RESET interrupt -+ */ -+static void jz4740_reset_irq(struct jz4740_udc *dev) -+{ -+ dev->gadget.speed = (usb_readb(dev, JZ_REG_UDC_POWER) & USB_POWER_HSMODE) ? -+ USB_SPEED_HIGH : USB_SPEED_FULL; -+ -+ DEBUG_SETUP("%s: address = %d, speed = %s\n", __FUNCTION__, 0, -+ (dev->gadget.speed == USB_SPEED_HIGH) ? "HIGH":"FULL" ); -+} -+ -+/* -+ * jz4740 usb device interrupt handler. -+ */ -+static irqreturn_t jz4740_udc_irq(int irq, void *devid) -+{ -+ struct jz4740_udc *jz4740_udc = devid; -+ uint8_t index; -+ -+ uint32_t intr_usb = usb_readb(jz4740_udc, JZ_REG_UDC_INTRUSB) & 0x7; /* mask SOF */ -+ uint32_t intr_in = usb_readw(jz4740_udc, JZ_REG_UDC_INTRIN); -+ uint32_t intr_out = usb_readw(jz4740_udc, JZ_REG_UDC_INTROUT); -+ uint32_t intr_dma = usb_readb(jz4740_udc, JZ_REG_UDC_INTR); -+ -+ if (!intr_usb && !intr_in && !intr_out && !intr_dma) -+ return IRQ_HANDLED; -+ -+ -+ DEBUG("intr_out=%x intr_in=%x intr_usb=%x\n", -+ intr_out, intr_in, intr_usb); -+ -+ spin_lock(&jz4740_udc->lock); -+ index = usb_readb(jz4740_udc, JZ_REG_UDC_INDEX); -+ -+ /* Check for resume from suspend mode */ -+ if ((intr_usb & USB_INTR_RESUME) && -+ (usb_readb(jz4740_udc, JZ_REG_UDC_INTRUSBE) & USB_INTR_RESUME)) { -+ DEBUG("USB resume\n"); -+ jz4740_udc->driver->resume(&jz4740_udc->gadget); /* We have suspend(), so we must have resume() too. */ -+ } -+ -+ /* Check for system interrupts */ -+ if (intr_usb & USB_INTR_RESET) { -+ DEBUG("USB reset\n"); -+ jz4740_reset_irq(jz4740_udc); -+ } -+ -+ /* Check for endpoint 0 interrupt */ -+ if (intr_in & USB_INTR_EP0) { -+ DEBUG("USB_INTR_EP0 (control)\n"); -+ jz4740_handle_ep0(jz4740_udc, intr_in); -+ } -+ -+ /* Check for Bulk-IN DMA interrupt */ -+ if (intr_dma & 0x1) { -+ int ep_num; -+ struct jz4740_ep *ep; -+ ep_num = (usb_readl(jz4740_udc, JZ_REG_UDC_CNTL1) >> 4) & 0xf; -+ ep = &jz4740_udc->ep[ep_num + 1]; -+ jz_udc_select_ep(ep); -+ usb_setb(jz4740_udc, ep->csr, USB_INCSR_INPKTRDY); -+/* jz4740_in_epn(jz4740_udc, ep_num, intr_in);*/ -+ } -+ -+ /* Check for Bulk-OUT DMA interrupt */ -+ if (intr_dma & 0x2) { -+ int ep_num; -+ ep_num = (usb_readl(jz4740_udc, JZ_REG_UDC_CNTL2) >> 4) & 0xf; -+ jz4740_out_epn(jz4740_udc, ep_num, intr_out); -+ } -+ -+ /* Check for each configured endpoint interrupt */ -+ if (intr_in & USB_INTR_INEP1) { -+ DEBUG("USB_INTR_INEP1\n"); -+ jz4740_in_epn(jz4740_udc, 1, intr_in); -+ } -+ -+ if (intr_in & USB_INTR_INEP2) { -+ DEBUG("USB_INTR_INEP2\n"); -+ jz4740_in_epn(jz4740_udc, 2, intr_in); -+ } -+ -+ if (intr_out & USB_INTR_OUTEP1) { -+ DEBUG("USB_INTR_OUTEP1\n"); -+ jz4740_out_epn(jz4740_udc, 1, intr_out); -+ } -+ -+ /* Check for suspend mode */ -+ if ((intr_usb & USB_INTR_SUSPEND) && -+ (usb_readb(jz4740_udc, JZ_REG_UDC_INTRUSBE) & USB_INTR_SUSPEND)) { -+ DEBUG("USB suspend\n"); -+ jz4740_udc->driver->suspend(&jz4740_udc->gadget); -+ /* Host unloaded from us, can do something, such as flushing -+ the NAND block cache etc. */ -+ } -+ -+ jz_udc_set_index(jz4740_udc, index); -+ -+ spin_unlock(&jz4740_udc->lock); -+ -+ return IRQ_HANDLED; -+} -+ -+ -+ -+/*-------------------------------------------------------------------------*/ -+ -+ -+static inline struct jz4740_udc *gadget_to_udc(struct usb_gadget *gadget) -+{ -+ return container_of(gadget, struct jz4740_udc, gadget); -+} -+ -+static int jz4740_udc_get_frame(struct usb_gadget *_gadget) -+{ -+ DEBUG("%s, %p\n", __FUNCTION__, _gadget); -+ return usb_readw(gadget_to_udc(_gadget), JZ_REG_UDC_FRAME); -+} -+ -+static int jz4740_udc_wakeup(struct usb_gadget *_gadget) -+{ -+ /* host may not have enabled remote wakeup */ -+ /*if ((UDCCS0 & UDCCS0_DRWF) == 0) -+ return -EHOSTUNREACH; -+ udc_set_mask_UDCCR(UDCCR_RSM); */ -+ return -ENOTSUPP; -+} -+ -+static int jz4740_udc_pullup(struct usb_gadget *_gadget, int on) -+{ -+ struct jz4740_udc *udc = gadget_to_udc(_gadget); -+ unsigned long flags; -+ -+ local_irq_save(flags); -+ -+ if (on) { -+ udc->state = UDC_STATE_ENABLE; -+ udc_enable(udc); -+ } else { -+ udc->state = UDC_STATE_DISABLE; -+ udc_disable(udc); -+ } -+ -+ local_irq_restore(flags); -+ -+ return 0; -+} -+ -+static const struct usb_gadget_ops jz4740_udc_ops = { -+ .get_frame = jz4740_udc_get_frame, -+ .wakeup = jz4740_udc_wakeup, -+ .pullup = jz4740_udc_pullup, -+ .udc_start = jz4740_udc_start, -+ .udc_stop = jz4740_udc_stop, -+}; -+ -+static struct usb_ep_ops jz4740_ep_ops = { -+ .enable = jz4740_ep_enable, -+ .disable = jz4740_ep_disable, -+ -+ .alloc_request = jz4740_alloc_request, -+ .free_request = jz4740_free_request, -+ -+ .queue = jz4740_queue, -+ .dequeue = jz4740_dequeue, -+ -+ .set_halt = jz4740_set_halt, -+ .fifo_status = jz4740_fifo_status, -+ .fifo_flush = jz4740_fifo_flush, -+}; -+ -+ -+/*-------------------------------------------------------------------------*/ -+ -+static struct jz4740_udc jz4740_udc_controller = { -+ .gadget = { -+ .ops = &jz4740_udc_ops, -+ .ep0 = &jz4740_udc_controller.ep[0].ep, -+ .max_speed = USB_SPEED_HIGH, -+ .name = "jz4740-udc", -+ .dev = { -+ .init_name = "gadget", -+ }, -+ }, -+ -+ /* control endpoint */ -+ .ep[0] = { -+ .ep = { -+ .name = "ep0", -+ .ops = &jz4740_ep_ops, -+ .maxpacket = EP0_MAXPACKETSIZE, -+ }, -+ .dev = &jz4740_udc_controller, -+ -+ .bEndpointAddress = 0, -+ .bmAttributes = 0, -+ -+ .type = ep_control, -+ .fifo = JZ_REG_UDC_EP_FIFO(0), -+ .csr = JZ_REG_UDC_CSR0, -+ }, -+ -+ /* bulk out endpoint */ -+ .ep[1] = { -+ .ep = { -+ .name = "ep1out-bulk", -+ .ops = &jz4740_ep_ops, -+ .maxpacket = EPBULK_MAXPACKETSIZE, -+ }, -+ .dev = &jz4740_udc_controller, -+ -+ .bEndpointAddress = 1, -+ .bmAttributes = USB_ENDPOINT_XFER_BULK, -+ -+ .type = ep_bulk_out, -+ .fifo = JZ_REG_UDC_EP_FIFO(1), -+ .csr = JZ_REG_UDC_OUTCSR, -+ }, -+ -+ /* bulk in endpoint */ -+ .ep[2] = { -+ .ep = { -+ .name = "ep1in-bulk", -+ .ops = &jz4740_ep_ops, -+ .maxpacket = EPBULK_MAXPACKETSIZE, -+ }, -+ .dev = &jz4740_udc_controller, -+ -+ .bEndpointAddress = 1 | USB_DIR_IN, -+ .bmAttributes = USB_ENDPOINT_XFER_BULK, -+ -+ .type = ep_bulk_in, -+ .fifo = JZ_REG_UDC_EP_FIFO(1), -+ .csr = JZ_REG_UDC_INCSR, -+ }, -+ -+ /* interrupt in endpoint */ -+ .ep[3] = { -+ .ep = { -+ .name = "ep2in-int", -+ .ops = &jz4740_ep_ops, -+ .maxpacket = EPINTR_MAXPACKETSIZE, -+ }, -+ .dev = &jz4740_udc_controller, -+ -+ .bEndpointAddress = 2 | USB_DIR_IN, -+ .bmAttributes = USB_ENDPOINT_XFER_INT, -+ -+ .type = ep_interrupt, -+ .fifo = JZ_REG_UDC_EP_FIFO(2), -+ .csr = JZ_REG_UDC_INCSR, -+ }, -+}; -+ -+static int jz4740_udc_probe(struct platform_device *pdev) -+{ -+ struct jz4740_udc *jz4740_udc = &jz4740_udc_controller; -+ int ret; -+ -+ spin_lock_init(&jz4740_udc->lock); -+ -+ jz4740_udc->dev = &pdev->dev; -+ -+ jz4740_udc->clk = clk_get(&pdev->dev, "udc"); -+ if (IS_ERR(jz4740_udc->clk)) { -+ ret = PTR_ERR(jz4740_udc->clk); -+ dev_err(&pdev->dev, "Failed to get udc clock: %d\n", ret); -+ return ret; -+ } -+ -+ platform_set_drvdata(pdev, jz4740_udc); -+ -+ jz4740_udc->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ -+ if (!jz4740_udc->mem) { -+ ret = -ENOENT; -+ dev_err(&pdev->dev, "Failed to get mmio memory resource\n"); -+ goto err_clk_put; -+ } -+ -+ jz4740_udc->mem = request_mem_region(jz4740_udc->mem->start, -+ resource_size(jz4740_udc->mem), pdev->name); -+ -+ if (!jz4740_udc->mem) { -+ ret = -EBUSY; -+ dev_err(&pdev->dev, "Failed to request mmio memory region\n"); -+ goto err_clk_put; -+ } -+ -+ jz4740_udc->base = ioremap(jz4740_udc->mem->start, resource_size(jz4740_udc->mem)); -+ -+ if (!jz4740_udc->base) { -+ ret = -EBUSY; -+ dev_err(&pdev->dev, "Failed to ioremap mmio memory\n"); -+ goto err_release_mem_region; -+ } -+ -+ jz4740_udc->irq = platform_get_irq(pdev, 0); -+ ret = request_irq(jz4740_udc->irq, jz4740_udc_irq, 0, pdev->name, -+ jz4740_udc); -+ if (ret) { -+ dev_err(&pdev->dev, "Failed to request irq: %d\n", ret); -+ goto err_iounmap; -+ } -+ -+ ret = usb_add_gadget_udc(&pdev->dev, &jz4740_udc->gadget); -+ if (ret) { -+ dev_err(&pdev->dev, "Failed to add gadget: %d\n", ret); -+ goto err_free_irq; -+ } -+ -+/* udc_disable(jz4740_udc);*/ -+ udc_reinit(jz4740_udc); -+ -+ return 0; -+ -+err_free_irq: -+ free_irq(jz4740_udc->irq, pdev); -+err_iounmap: -+ iounmap(jz4740_udc->base); -+err_release_mem_region: -+ release_mem_region(jz4740_udc->mem->start, resource_size(jz4740_udc->mem)); -+err_clk_put: -+ clk_put(jz4740_udc->clk); -+ -+ return ret; -+} -+ -+static int jz4740_udc_remove(struct platform_device *pdev) -+{ -+ struct jz4740_udc *dev = platform_get_drvdata(pdev); -+ -+ usb_del_gadget_udc(&dev->gadget); -+ if (dev->driver) -+ return -EBUSY; -+ -+ udc_disable(dev); -+ -+ free_irq(dev->irq, dev); -+ iounmap(dev->base); -+ release_mem_region(dev->mem->start, resource_size(dev->mem)); -+ clk_put(dev->clk); -+ -+ return 0; -+} -+ -+#ifdef CONFIG_PM -+ -+static int jz4740_udc_suspend(struct device *dev) -+{ -+ struct jz4740_udc *jz4740_udc = dev_get_drvdata(dev); -+ -+ if (jz4740_udc->state == UDC_STATE_ENABLE) -+ udc_disable(jz4740_udc); -+ -+ return 0; -+} -+ -+static int jz4740_udc_resume(struct device *dev) -+{ -+ struct jz4740_udc *jz4740_udc = dev_get_drvdata(dev); -+ -+ if (jz4740_udc->state == UDC_STATE_ENABLE) -+ udc_enable(jz4740_udc); -+ -+ return 0; -+} -+ -+static SIMPLE_DEV_PM_OPS(jz4740_udc_pm_ops, jz4740_udc_suspend, jz4740_udc_resume); -+#define JZ4740_UDC_PM_OPS (&jz4740_udc_pm_ops) -+ -+#else -+#define JZ4740_UDC_PM_OPS NULL -+#endif -+ -+static struct platform_driver udc_driver = { -+ .probe = jz4740_udc_probe, -+ .remove = jz4740_udc_remove, -+ .driver = { -+ .name = "jz-udc", -+ .owner = THIS_MODULE, -+ .pm = JZ4740_UDC_PM_OPS, -+ }, -+}; -+ -+/*-------------------------------------------------------------------------*/ -+ -+static int __init udc_init (void) -+{ -+ return platform_driver_register(&udc_driver); -+} -+module_init(udc_init); -+ -+static void __exit udc_exit (void) -+{ -+ platform_driver_unregister(&udc_driver); -+} -+module_exit(udc_exit); -+ -+MODULE_DESCRIPTION("JZ4740 USB Device Controller"); -+MODULE_AUTHOR("Wei Jianli <jlwei@ingenic.cn>"); -+MODULE_LICENSE("GPL"); ---- /dev/null -+++ b/drivers/usb/gadget/jz4740_udc.h -@@ -0,0 +1,101 @@ -+/* -+ * linux/drivers/usb/gadget/jz4740_udc.h -+ * -+ * Ingenic JZ4740 on-chip high speed USB device controller -+ * -+ * Copyright (C) 2006 Ingenic Semiconductor Inc. -+ * Author: <jlwei@ingenic.cn> -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ */ -+ -+#ifndef __USB_GADGET_JZ4740_H__ -+#define __USB_GADGET_JZ4740_H__ -+ -+/*-------------------------------------------------------------------------*/ -+ -+// Max packet size -+#define EP0_MAXPACKETSIZE 64 -+#define EPBULK_MAXPACKETSIZE 512 -+#define EPINTR_MAXPACKETSIZE 64 -+ -+#define UDC_MAX_ENDPOINTS 4 -+ -+/*-------------------------------------------------------------------------*/ -+ -+enum ep_type { -+ ep_control, ep_bulk_in, ep_bulk_out, ep_interrupt -+}; -+ -+struct jz4740_ep { -+ struct usb_ep ep; -+ struct jz4740_udc *dev; -+ -+ const struct usb_endpoint_descriptor *desc; -+ -+ uint8_t stopped; -+ uint8_t bEndpointAddress; -+ uint8_t bmAttributes; -+ -+ enum ep_type type; -+ size_t fifo; -+ uint32_t csr; -+ -+ uint32_t reg_addr; -+ struct list_head queue; -+}; -+ -+struct jz4740_request { -+ struct usb_request req; -+ struct list_head queue; -+}; -+ -+enum ep0state { -+ WAIT_FOR_SETUP, /* between STATUS ack and SETUP report */ -+ DATA_STATE_XMIT, /* data tx stage */ -+ DATA_STATE_NEED_ZLP, /* data tx zlp stage */ -+ WAIT_FOR_OUT_STATUS, /* status stages */ -+ DATA_STATE_RECV, /* data rx stage */ -+}; -+ -+/* For function binding with UDC Disable - Added by River */ -+typedef enum { -+ UDC_STATE_ENABLE = 0, -+ UDC_STATE_DISABLE, -+}udc_state_t; -+ -+struct jz4740_udc { -+ struct usb_gadget gadget; -+ struct usb_gadget_driver *driver; -+ struct device *dev; -+ spinlock_t lock; -+ unsigned long lock_flags; -+ -+ enum ep0state ep0state; -+ struct jz4740_ep ep[UDC_MAX_ENDPOINTS]; -+ -+ udc_state_t state; -+ -+ struct resource *mem; -+ void __iomem *base; -+ int irq; -+ -+ struct clk *clk; -+}; -+ -+#define ep_maxpacket(EP) ((EP)->ep.maxpacket) -+ -+static inline bool ep_is_in(const struct jz4740_ep *ep) -+{ -+ return (ep->bEndpointAddress & USB_DIR_IN) == USB_DIR_IN; -+} -+ -+static inline uint8_t ep_index(const struct jz4740_ep *ep) -+{ -+ return ep->bEndpointAddress & 0xf; -+} -+ -+#endif /* __USB_GADGET_JZ4740_H__ */ diff --git a/target/linux/xburst/patches-3.10/009-Add-ili8960-lcd-driver.patch b/target/linux/xburst/patches-3.10/009-Add-ili8960-lcd-driver.patch deleted file mode 100644 index 95545ed43e..0000000000 --- a/target/linux/xburst/patches-3.10/009-Add-ili8960-lcd-driver.patch +++ /dev/null @@ -1,304 +0,0 @@ -From ee3a5c779be4d1d270388203cd1c6a734a0bf4ed Mon Sep 17 00:00:00 2001 -From: Lars-Peter Clausen <lars@metafoo.de> -Date: Sun, 1 Aug 2010 21:19:40 +0200 -Subject: [PATCH 09/16] Add ili8960 lcd driver - -Signed-off-by: Lars-Peter Clausen <lars@metafoo.de> ---- - drivers/video/backlight/Kconfig | 7 + - drivers/video/backlight/Makefile | 1 + - drivers/video/backlight/ili8960.c | 262 +++++++++++++++++++++++++++++++++++++ - 3 files changed, 270 insertions(+) - create mode 100644 drivers/video/backlight/ili8960.c - ---- a/drivers/video/backlight/Kconfig -+++ b/drivers/video/backlight/Kconfig -@@ -59,6 +59,13 @@ config LCD_LTV350QV - - The LTV350QV panel is present on all ATSTK1000 boards. - -+config LCD_ILI8960 -+ tristate "Ilitek ili8960 LCD driver" -+ depends on LCD_CLASS_DEVICE && SPI -+ default n -+ help -+ Driver for the Ilitek ili8960 LCD controller chip. -+ - config LCD_ILI922X - tristate "ILI Technology ILI9221/ILI9222 support" - depends on SPI ---- a/drivers/video/backlight/Makefile -+++ b/drivers/video/backlight/Makefile -@@ -5,6 +5,7 @@ obj-$(CONFIG_LCD_CLASS_DEVICE) += lcd.o - obj-$(CONFIG_LCD_CORGI) += corgi_lcd.o - obj-$(CONFIG_LCD_HP700) += jornada720_lcd.o - obj-$(CONFIG_LCD_HX8357) += hx8357.o -+obj-$(CONFIG_LCD_ILI8960) += ili8960.o - obj-$(CONFIG_LCD_ILI922X) += ili922x.o - obj-$(CONFIG_LCD_ILI9320) += ili9320.o - obj-$(CONFIG_LCD_L4F00242T03) += l4f00242t03.o ---- /dev/null -+++ b/drivers/video/backlight/ili8960.c -@@ -0,0 +1,262 @@ -+/* -+ * Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de> -+ * Driver for Ilitek ili8960 LCD -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License as published by the -+ * Free Software Foundation; either version 2 of the License, or (at your -+ * option) any later version. -+ * -+ * You should have received a copy of the GNU General Public License along -+ * with this program; if not, write to the Free Software Foundation, Inc., -+ * 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ */ -+ -+#include <linux/module.h> -+#include <linux/spi/spi.h> -+#include <linux/lcd.h> -+#include <linux/delay.h> -+ -+struct ili8960 { -+ struct spi_device *spi; -+ struct lcd_device *lcd; -+ bool enabled; -+ unsigned int brightness; -+}; -+ -+#define ILI8960_REG_BRIGHTNESS 0x03 -+#define ILI8960_REG_POWER 0x05 -+#define ILI8960_REG_CONTRAST 0x0d -+ -+static int ili8960_write_reg(struct spi_device *spi, uint8_t reg, -+ uint8_t data) -+{ -+ uint8_t buf[2]; -+ buf[0] = ((reg & 0x40) << 1) | (reg & 0x3f); -+ buf[1] = data; -+ -+ return spi_write(spi, buf, sizeof(buf)); -+} -+ -+static int ili8960_programm_power(struct spi_device *spi, bool enabled) -+{ -+ int ret; -+ -+ if (enabled) -+ mdelay(20); -+ -+ ret = ili8960_write_reg(spi, ILI8960_REG_POWER, enabled ? 0xc7 : 0xc6); -+ -+ if (!enabled) -+ mdelay(20); -+ -+ return ret; -+} -+ -+static int ili8960_set_power(struct lcd_device *lcd, int power) -+{ -+ struct ili8960 *ili8960 = lcd_get_data(lcd); -+ -+ switch (power) { -+ case FB_BLANK_UNBLANK: -+ ili8960->enabled = true; -+ break; -+ default: -+ return 0; -+ } -+ -+ return ili8960_programm_power(ili8960->spi, ili8960->enabled); -+} -+ -+static int ili8960_early_set_power(struct lcd_device *lcd, int power) -+{ -+ struct ili8960 *ili8960 = lcd_get_data(lcd); -+ -+ switch (power) { -+ case FB_BLANK_UNBLANK: -+ return 0; -+ default: -+ ili8960->enabled = false; -+ break; -+ } -+ -+ return ili8960_programm_power(ili8960->spi, ili8960->enabled); -+} -+ -+static int ili8960_get_power(struct lcd_device *lcd) -+{ -+ struct ili8960 *ili8960 = lcd_get_data(lcd); -+ return ili8960->enabled ? FB_BLANK_UNBLANK : FB_BLANK_POWERDOWN; -+} -+ -+static int ili8960_set_contrast(struct lcd_device *lcd, int contrast) -+{ -+ struct ili8960 *ili8960 = lcd_get_data(lcd); -+ -+ return ili8960_write_reg(ili8960->spi, ILI8960_REG_CONTRAST, contrast); -+} -+ -+static int ili8960_set_mode(struct lcd_device *lcd, struct fb_videomode *mode) -+{ -+ if (mode->xres != 320 && mode->yres != 240) -+ return -EINVAL; -+ -+ return 0; -+} -+ -+static int ili8960_set_brightness(struct ili8960 *ili8960, int brightness) -+{ -+ int ret; -+ -+ ret = ili8960_write_reg(ili8960->spi, ILI8960_REG_BRIGHTNESS, brightness); -+ -+ if (ret == 0) -+ ili8960->brightness = brightness; -+ -+ return ret; -+} -+ -+static ssize_t ili8960_show_brightness(struct device *dev, -+ struct device_attribute *attr, char *buf) -+{ -+ struct lcd_device *ld = to_lcd_device(dev); -+ struct ili8960 *ili8960 = lcd_get_data(ld); -+ -+ return sprintf(buf, "%u\n", ili8960->brightness); -+} -+ -+static ssize_t ili8960_store_brightness(struct device *dev, -+ struct device_attribute *attr, const char *buf, size_t count) -+{ -+ struct lcd_device *ld = to_lcd_device(dev); -+ struct ili8960 *ili8960 = lcd_get_data(ld); -+ unsigned long brightness; -+ int ret; -+ -+ ret = kstrtoul(buf, 0, &brightness); -+ if (ret) -+ return ret; -+ -+ if (brightness > 255) -+ return -EINVAL; -+ -+ ili8960_set_brightness(ili8960, brightness); -+ -+ return count; -+} -+ -+ -+static DEVICE_ATTR(brightness, 0644, ili8960_show_brightness, -+ ili8960_store_brightness); -+ -+static struct lcd_ops ili8960_lcd_ops = { -+ .set_power = ili8960_set_power, -+ .early_set_power = ili8960_early_set_power, -+ .get_power = ili8960_get_power, -+ .set_contrast = ili8960_set_contrast, -+ .set_mode = ili8960_set_mode, -+}; -+ -+static int ili8960_probe(struct spi_device *spi) -+{ -+ int ret; -+ struct ili8960 *ili8960; -+ -+ ili8960 = devm_kzalloc(&spi->dev, sizeof(*ili8960), GFP_KERNEL); -+ if (!ili8960) -+ return -ENOMEM; -+ -+ spi->bits_per_word = 8; -+ spi->mode = SPI_MODE_3; -+ -+ ret = spi_setup(spi); -+ if (ret) { -+ dev_err(&spi->dev, "Failed to setup spi\n"); -+ return ret; -+ } -+ -+ ili8960->spi = spi; -+ -+ ili8960->lcd = lcd_device_register("ili8960-lcd", &spi->dev, ili8960, -+ &ili8960_lcd_ops); -+ -+ if (IS_ERR(ili8960->lcd)) { -+ ret = PTR_ERR(ili8960->lcd); -+ dev_err(&spi->dev, "Failed to register lcd device: %d\n", ret); -+ return ret; -+ } -+ -+ ili8960->lcd->props.max_contrast = 255; -+ -+ ret = device_create_file(&ili8960->lcd->dev, &dev_attr_brightness); -+ if (ret) -+ goto err_unregister_lcd; -+ -+ ili8960_programm_power(ili8960->spi, true); -+ ili8960->enabled = true; -+ -+ spi_set_drvdata(spi, ili8960); -+ -+ ili8960_write_reg(spi, 0x13, 0x01); -+ -+ return 0; -+err_unregister_lcd: -+ lcd_device_unregister(ili8960->lcd); -+ return ret; -+} -+ -+static int ili8960_remove(struct spi_device *spi) -+{ -+ struct ili8960 *ili8960 = spi_get_drvdata(spi); -+ -+ device_remove_file(&ili8960->lcd->dev, &dev_attr_brightness); -+ lcd_device_unregister(ili8960->lcd); -+ -+ spi_set_drvdata(spi, NULL); -+ return 0; -+} -+ -+#ifdef CONFIG_PM -+ -+static int ili8960_suspend(struct spi_device *spi, pm_message_t state) -+{ -+ struct ili8960 *ili8960 = spi_get_drvdata(spi); -+ -+ if (ili8960->enabled) -+ ili8960_programm_power(ili8960->spi, false); -+ -+ return 0; -+} -+ -+static int ili8960_resume(struct spi_device *spi) -+{ -+ struct ili8960 *ili8960 = spi_get_drvdata(spi); -+ -+ if (ili8960->enabled) -+ ili8960_programm_power(ili8960->spi, true); -+ -+ return 0; -+} -+ -+#else -+#define ili8960_suspend NULL -+#define ili8960_resume NULL -+#endif -+ -+static struct spi_driver ili8960_driver = { -+ .driver = { -+ .name = "ili8960", -+ .owner = THIS_MODULE, -+ }, -+ .probe = ili8960_probe, -+ .remove = ili8960_remove, -+ .suspend = ili8960_suspend, -+ .resume = ili8960_resume, -+}; -+module_spi_driver(ili8960_driver); -+ -+MODULE_AUTHOR("Lars-Peter Clausen"); -+MODULE_LICENSE("GPL"); -+MODULE_DESCRIPTION("LCD driver for Ilitek ili8960"); -+MODULE_ALIAS("spi:ili8960"); diff --git a/target/linux/xburst/patches-3.10/010-qi_lb60-Don-t-use-3-wire-spi-mode-for-the-display-fo.patch b/target/linux/xburst/patches-3.10/010-qi_lb60-Don-t-use-3-wire-spi-mode-for-the-display-fo.patch deleted file mode 100644 index c45964f673..0000000000 --- a/target/linux/xburst/patches-3.10/010-qi_lb60-Don-t-use-3-wire-spi-mode-for-the-display-fo.patch +++ /dev/null @@ -1,23 +0,0 @@ -From 590ceec7028084ebd9d643b4929ceae9fd806fbe Mon Sep 17 00:00:00 2001 -From: Lars-Peter Clausen <lars@metafoo.de> -Date: Wed, 13 Oct 2010 01:17:24 +0200 -Subject: [PATCH 10/16] qi_lb60: Don't use 3-wire spi mode for the display for - now - -The spi_gpio driver does not support 3-wire mode. - -Signed-off-by: Lars-Peter Clausen <lars@metafoo.de> ---- - arch/mips/jz4740/board-qi_lb60.c | 1 - - 1 file changed, 1 deletion(-) - ---- a/arch/mips/jz4740/board-qi_lb60.c -+++ b/arch/mips/jz4740/board-qi_lb60.c -@@ -311,7 +311,6 @@ static struct spi_board_info qi_lb60_spi - .chip_select = 0, - .bus_num = 1, - .max_speed_hz = 30 * 1000, -- .mode = SPI_3WIRE, - }, - }; - diff --git a/target/linux/xburst/patches-3.10/011-dma-Add-a-jz4740-dmaengine-driver.patch b/target/linux/xburst/patches-3.10/011-dma-Add-a-jz4740-dmaengine-driver.patch deleted file mode 100644 index e53896bba9..0000000000 --- a/target/linux/xburst/patches-3.10/011-dma-Add-a-jz4740-dmaengine-driver.patch +++ /dev/null @@ -1,478 +0,0 @@ -From 8c53b6491806a37d6999886d22c34bfed310034c Mon Sep 17 00:00:00 2001 -From: Lars-Peter Clausen <lars@metafoo.de> -Date: Thu, 30 May 2013 18:25:02 +0200 -Subject: [PATCH 11/16] dma: Add a jz4740 dmaengine driver - -This patch adds dmaengine support for the JZ4740 DMA controller. For now the -driver will be a wrapper around the custom JZ4740 DMA API. Once all users of the -custom JZ4740 DMA API have been converted to the dmaengine API the custom API -will be removed and direct hardware access will be added to the dmaengine -driver. - -Signed-off-by: Lars-Peter Clausen <lars@metafoo.de> -Signed-off-by: Vinod Koul <vinod.koul@intel.com> ---- - drivers/dma/Kconfig | 6 + - drivers/dma/Makefile | 1 + - drivers/dma/dma-jz4740.c | 433 ++++++++++++++++++++++++++++++++++++++++++++++ - 3 files changed, 440 insertions(+) - create mode 100644 drivers/dma/dma-jz4740.c - ---- a/drivers/dma/Kconfig -+++ b/drivers/dma/Kconfig -@@ -312,6 +312,12 @@ config MMP_PDMA - help - Support the MMP PDMA engine for PXA and MMP platfrom. - -+config DMA_JZ4740 -+ tristate "JZ4740 DMA support" -+ depends on MACH_JZ4740 -+ select DMA_ENGINE -+ select DMA_VIRTUAL_CHANNELS -+ - config DMA_ENGINE - bool - ---- a/drivers/dma/Makefile -+++ b/drivers/dma/Makefile -@@ -38,3 +38,4 @@ obj-$(CONFIG_DMA_SA11X0) += sa11x0-dma.o - obj-$(CONFIG_MMP_TDMA) += mmp_tdma.o - obj-$(CONFIG_DMA_OMAP) += omap-dma.o - obj-$(CONFIG_MMP_PDMA) += mmp_pdma.o -+obj-$(CONFIG_DMA_JZ4740) += dma-jz4740.o ---- /dev/null -+++ b/drivers/dma/dma-jz4740.c -@@ -0,0 +1,433 @@ -+/* -+ * Copyright (C) 2013, Lars-Peter Clausen <lars@metafoo.de> -+ * JZ4740 DMAC support -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License as published by the -+ * Free Software Foundation; either version 2 of the License, or (at your -+ * option) any later version. -+ * -+ * You should have received a copy of the GNU General Public License along -+ * with this program; if not, write to the Free Software Foundation, Inc., -+ * 675 Mass Ave, Cambridge, MA 02139, USA. -+ * -+ */ -+ -+#include <linux/dmaengine.h> -+#include <linux/dma-mapping.h> -+#include <linux/err.h> -+#include <linux/init.h> -+#include <linux/list.h> -+#include <linux/module.h> -+#include <linux/platform_device.h> -+#include <linux/slab.h> -+#include <linux/spinlock.h> -+ -+#include <asm/mach-jz4740/dma.h> -+ -+#include "virt-dma.h" -+ -+#define JZ_DMA_NR_CHANS 6 -+ -+struct jz4740_dma_sg { -+ dma_addr_t addr; -+ unsigned int len; -+}; -+ -+struct jz4740_dma_desc { -+ struct virt_dma_desc vdesc; -+ -+ enum dma_transfer_direction direction; -+ bool cyclic; -+ -+ unsigned int num_sgs; -+ struct jz4740_dma_sg sg[]; -+}; -+ -+struct jz4740_dmaengine_chan { -+ struct virt_dma_chan vchan; -+ struct jz4740_dma_chan *jz_chan; -+ -+ dma_addr_t fifo_addr; -+ -+ struct jz4740_dma_desc *desc; -+ unsigned int next_sg; -+}; -+ -+struct jz4740_dma_dev { -+ struct dma_device ddev; -+ -+ struct jz4740_dmaengine_chan chan[JZ_DMA_NR_CHANS]; -+}; -+ -+static struct jz4740_dmaengine_chan *to_jz4740_dma_chan(struct dma_chan *c) -+{ -+ return container_of(c, struct jz4740_dmaengine_chan, vchan.chan); -+} -+ -+static struct jz4740_dma_desc *to_jz4740_dma_desc(struct virt_dma_desc *vdesc) -+{ -+ return container_of(vdesc, struct jz4740_dma_desc, vdesc); -+} -+ -+static struct jz4740_dma_desc *jz4740_dma_alloc_desc(unsigned int num_sgs) -+{ -+ return kzalloc(sizeof(struct jz4740_dma_desc) + -+ sizeof(struct jz4740_dma_sg) * num_sgs, GFP_ATOMIC); -+} -+ -+static enum jz4740_dma_width jz4740_dma_width(enum dma_slave_buswidth width) -+{ -+ switch (width) { -+ case DMA_SLAVE_BUSWIDTH_1_BYTE: -+ return JZ4740_DMA_WIDTH_8BIT; -+ case DMA_SLAVE_BUSWIDTH_2_BYTES: -+ return JZ4740_DMA_WIDTH_16BIT; -+ case DMA_SLAVE_BUSWIDTH_4_BYTES: -+ return JZ4740_DMA_WIDTH_32BIT; -+ default: -+ return JZ4740_DMA_WIDTH_32BIT; -+ } -+} -+ -+static enum jz4740_dma_transfer_size jz4740_dma_maxburst(u32 maxburst) -+{ -+ if (maxburst <= 1) -+ return JZ4740_DMA_TRANSFER_SIZE_1BYTE; -+ else if (maxburst <= 3) -+ return JZ4740_DMA_TRANSFER_SIZE_2BYTE; -+ else if (maxburst <= 15) -+ return JZ4740_DMA_TRANSFER_SIZE_4BYTE; -+ else if (maxburst <= 31) -+ return JZ4740_DMA_TRANSFER_SIZE_16BYTE; -+ -+ return JZ4740_DMA_TRANSFER_SIZE_32BYTE; -+} -+ -+static int jz4740_dma_slave_config(struct dma_chan *c, -+ const struct dma_slave_config *config) -+{ -+ struct jz4740_dmaengine_chan *chan = to_jz4740_dma_chan(c); -+ struct jz4740_dma_config jzcfg; -+ -+ switch (config->direction) { -+ case DMA_MEM_TO_DEV: -+ jzcfg.flags = JZ4740_DMA_SRC_AUTOINC; -+ jzcfg.transfer_size = jz4740_dma_maxburst(config->dst_maxburst); -+ chan->fifo_addr = config->dst_addr; -+ break; -+ case DMA_DEV_TO_MEM: -+ jzcfg.flags = JZ4740_DMA_DST_AUTOINC; -+ jzcfg.transfer_size = jz4740_dma_maxburst(config->src_maxburst); -+ chan->fifo_addr = config->src_addr; -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ -+ jzcfg.src_width = jz4740_dma_width(config->src_addr_width); -+ jzcfg.dst_width = jz4740_dma_width(config->dst_addr_width); -+ jzcfg.mode = JZ4740_DMA_MODE_SINGLE; -+ jzcfg.request_type = config->slave_id; -+ -+ jz4740_dma_configure(chan->jz_chan, &jzcfg); -+ -+ return 0; -+} -+ -+static int jz4740_dma_terminate_all(struct dma_chan *c) -+{ -+ struct jz4740_dmaengine_chan *chan = to_jz4740_dma_chan(c); -+ unsigned long flags; -+ LIST_HEAD(head); -+ -+ spin_lock_irqsave(&chan->vchan.lock, flags); -+ jz4740_dma_disable(chan->jz_chan); -+ chan->desc = NULL; -+ vchan_get_all_descriptors(&chan->vchan, &head); -+ spin_unlock_irqrestore(&chan->vchan.lock, flags); -+ -+ vchan_dma_desc_free_list(&chan->vchan, &head); -+ -+ return 0; -+} -+ -+static int jz4740_dma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, -+ unsigned long arg) -+{ -+ struct dma_slave_config *config = (struct dma_slave_config *)arg; -+ -+ switch (cmd) { -+ case DMA_SLAVE_CONFIG: -+ return jz4740_dma_slave_config(chan, config); -+ case DMA_TERMINATE_ALL: -+ return jz4740_dma_terminate_all(chan); -+ default: -+ return -ENOSYS; -+ } -+} -+ -+static int jz4740_dma_start_transfer(struct jz4740_dmaengine_chan *chan) -+{ -+ dma_addr_t src_addr, dst_addr; -+ struct virt_dma_desc *vdesc; -+ struct jz4740_dma_sg *sg; -+ -+ jz4740_dma_disable(chan->jz_chan); -+ -+ if (!chan->desc) { -+ vdesc = vchan_next_desc(&chan->vchan); -+ if (!vdesc) -+ return 0; -+ chan->desc = to_jz4740_dma_desc(vdesc); -+ chan->next_sg = 0; -+ } -+ -+ if (chan->next_sg == chan->desc->num_sgs) -+ chan->next_sg = 0; -+ -+ sg = &chan->desc->sg[chan->next_sg]; -+ -+ if (chan->desc->direction == DMA_MEM_TO_DEV) { -+ src_addr = sg->addr; -+ dst_addr = chan->fifo_addr; -+ } else { -+ src_addr = chan->fifo_addr; -+ dst_addr = sg->addr; -+ } -+ jz4740_dma_set_src_addr(chan->jz_chan, src_addr); -+ jz4740_dma_set_dst_addr(chan->jz_chan, dst_addr); -+ jz4740_dma_set_transfer_count(chan->jz_chan, sg->len); -+ -+ chan->next_sg++; -+ -+ jz4740_dma_enable(chan->jz_chan); -+ -+ return 0; -+} -+ -+static void jz4740_dma_complete_cb(struct jz4740_dma_chan *jz_chan, int error, -+ void *devid) -+{ -+ struct jz4740_dmaengine_chan *chan = devid; -+ -+ spin_lock(&chan->vchan.lock); -+ if (chan->desc) { -+ if (chan->desc && chan->desc->cyclic) { -+ vchan_cyclic_callback(&chan->desc->vdesc); -+ } else { -+ if (chan->next_sg == chan->desc->num_sgs) { -+ chan->desc = NULL; -+ vchan_cookie_complete(&chan->desc->vdesc); -+ } -+ } -+ } -+ jz4740_dma_start_transfer(chan); -+ spin_unlock(&chan->vchan.lock); -+} -+ -+static void jz4740_dma_issue_pending(struct dma_chan *c) -+{ -+ struct jz4740_dmaengine_chan *chan = to_jz4740_dma_chan(c); -+ unsigned long flags; -+ -+ spin_lock_irqsave(&chan->vchan.lock, flags); -+ if (vchan_issue_pending(&chan->vchan) && !chan->desc) -+ jz4740_dma_start_transfer(chan); -+ spin_unlock_irqrestore(&chan->vchan.lock, flags); -+} -+ -+static struct dma_async_tx_descriptor *jz4740_dma_prep_slave_sg( -+ struct dma_chan *c, struct scatterlist *sgl, -+ unsigned int sg_len, enum dma_transfer_direction direction, -+ unsigned long flags, void *context) -+{ -+ struct jz4740_dmaengine_chan *chan = to_jz4740_dma_chan(c); -+ struct jz4740_dma_desc *desc; -+ struct scatterlist *sg; -+ unsigned int i; -+ -+ desc = jz4740_dma_alloc_desc(sg_len); -+ if (!desc) -+ return NULL; -+ -+ for_each_sg(sgl, sg, sg_len, i) { -+ desc->sg[i].addr = sg_dma_address(sg); -+ desc->sg[i].len = sg_dma_len(sg); -+ } -+ -+ desc->num_sgs = sg_len; -+ desc->direction = direction; -+ desc->cyclic = false; -+ -+ return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags); -+} -+ -+static struct dma_async_tx_descriptor *jz4740_dma_prep_dma_cyclic( -+ struct dma_chan *c, dma_addr_t buf_addr, size_t buf_len, -+ size_t period_len, enum dma_transfer_direction direction, -+ unsigned long flags, void *context) -+{ -+ struct jz4740_dmaengine_chan *chan = to_jz4740_dma_chan(c); -+ struct jz4740_dma_desc *desc; -+ unsigned int num_periods, i; -+ -+ if (buf_len % period_len) -+ return NULL; -+ -+ num_periods = buf_len / period_len; -+ -+ desc = jz4740_dma_alloc_desc(num_periods); -+ if (!desc) -+ return NULL; -+ -+ for (i = 0; i < num_periods; i++) { -+ desc->sg[i].addr = buf_addr; -+ desc->sg[i].len = period_len; -+ buf_addr += period_len; -+ } -+ -+ desc->num_sgs = num_periods; -+ desc->direction = direction; -+ desc->cyclic = true; -+ -+ return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags); -+} -+ -+static size_t jz4740_dma_desc_residue(struct jz4740_dmaengine_chan *chan, -+ struct jz4740_dma_desc *desc, unsigned int next_sg) -+{ -+ size_t residue = 0; -+ unsigned int i; -+ -+ residue = 0; -+ -+ for (i = next_sg; i < desc->num_sgs; i++) -+ residue += desc->sg[i].len; -+ -+ if (next_sg != 0) -+ residue += jz4740_dma_get_residue(chan->jz_chan); -+ -+ return residue; -+} -+ -+static enum dma_status jz4740_dma_tx_status(struct dma_chan *c, -+ dma_cookie_t cookie, struct dma_tx_state *state) -+{ -+ struct jz4740_dmaengine_chan *chan = to_jz4740_dma_chan(c); -+ struct virt_dma_desc *vdesc; -+ enum dma_status status; -+ unsigned long flags; -+ -+ status = dma_cookie_status(c, cookie, state); -+ if (status == DMA_SUCCESS || !state) -+ return status; -+ -+ spin_lock_irqsave(&chan->vchan.lock, flags); -+ vdesc = vchan_find_desc(&chan->vchan, cookie); -+ if (cookie == chan->desc->vdesc.tx.cookie) { -+ state->residue = jz4740_dma_desc_residue(chan, chan->desc, -+ chan->next_sg); -+ } else if (vdesc) { -+ state->residue = jz4740_dma_desc_residue(chan, -+ to_jz4740_dma_desc(vdesc), 0); -+ } else { -+ state->residue = 0; -+ } -+ spin_unlock_irqrestore(&chan->vchan.lock, flags); -+ -+ return status; -+} -+ -+static int jz4740_dma_alloc_chan_resources(struct dma_chan *c) -+{ -+ struct jz4740_dmaengine_chan *chan = to_jz4740_dma_chan(c); -+ -+ chan->jz_chan = jz4740_dma_request(chan, NULL); -+ if (!chan->jz_chan) -+ return -EBUSY; -+ -+ jz4740_dma_set_complete_cb(chan->jz_chan, jz4740_dma_complete_cb); -+ -+ return 0; -+} -+ -+static void jz4740_dma_free_chan_resources(struct dma_chan *c) -+{ -+ struct jz4740_dmaengine_chan *chan = to_jz4740_dma_chan(c); -+ -+ vchan_free_chan_resources(&chan->vchan); -+ jz4740_dma_free(chan->jz_chan); -+ chan->jz_chan = NULL; -+} -+ -+static void jz4740_dma_desc_free(struct virt_dma_desc *vdesc) -+{ -+ kfree(container_of(vdesc, struct jz4740_dma_desc, vdesc)); -+} -+ -+static int jz4740_dma_probe(struct platform_device *pdev) -+{ -+ struct jz4740_dmaengine_chan *chan; -+ struct jz4740_dma_dev *dmadev; -+ struct dma_device *dd; -+ unsigned int i; -+ int ret; -+ -+ dmadev = devm_kzalloc(&pdev->dev, sizeof(*dmadev), GFP_KERNEL); -+ if (!dmadev) -+ return -EINVAL; -+ -+ dd = &dmadev->ddev; -+ -+ dma_cap_set(DMA_SLAVE, dd->cap_mask); -+ dma_cap_set(DMA_CYCLIC, dd->cap_mask); -+ dd->device_alloc_chan_resources = jz4740_dma_alloc_chan_resources; -+ dd->device_free_chan_resources = jz4740_dma_free_chan_resources; -+ dd->device_tx_status = jz4740_dma_tx_status; -+ dd->device_issue_pending = jz4740_dma_issue_pending; -+ dd->device_prep_slave_sg = jz4740_dma_prep_slave_sg; -+ dd->device_prep_dma_cyclic = jz4740_dma_prep_dma_cyclic; -+ dd->device_control = jz4740_dma_control; -+ dd->dev = &pdev->dev; -+ dd->chancnt = JZ_DMA_NR_CHANS; -+ INIT_LIST_HEAD(&dd->channels); -+ -+ for (i = 0; i < dd->chancnt; i++) { -+ chan = &dmadev->chan[i]; -+ chan->vchan.desc_free = jz4740_dma_desc_free; -+ vchan_init(&chan->vchan, dd); -+ } -+ -+ ret = dma_async_device_register(dd); -+ if (ret) -+ return ret; -+ -+ platform_set_drvdata(pdev, dmadev); -+ -+ return 0; -+} -+ -+static int jz4740_dma_remove(struct platform_device *pdev) -+{ -+ struct jz4740_dma_dev *dmadev = platform_get_drvdata(pdev); -+ -+ dma_async_device_unregister(&dmadev->ddev); -+ -+ return 0; -+} -+ -+static struct platform_driver jz4740_dma_driver = { -+ .probe = jz4740_dma_probe, -+ .remove = jz4740_dma_remove, -+ .driver = { -+ .name = "jz4740-dma", -+ .owner = THIS_MODULE, -+ }, -+}; -+module_platform_driver(jz4740_dma_driver); -+ -+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); -+MODULE_DESCRIPTION("JZ4740 DMA driver"); -+MODULE_LICENSE("GPLv2"); diff --git a/target/linux/xburst/patches-3.10/012-MIPS-JZ4740-Correct-clock-gate-bit-for-DMA-controlle.patch b/target/linux/xburst/patches-3.10/012-MIPS-JZ4740-Correct-clock-gate-bit-for-DMA-controlle.patch deleted file mode 100644 index f440a9daa3..0000000000 --- a/target/linux/xburst/patches-3.10/012-MIPS-JZ4740-Correct-clock-gate-bit-for-DMA-controlle.patch +++ /dev/null @@ -1,22 +0,0 @@ -From 1a0086ae912b81a1e6c7213e97059c50a7bfe636 Mon Sep 17 00:00:00 2001 -From: Maarten ter Huurne <maarten@treewalker.org> -Date: Sun, 6 May 2012 01:51:09 +0200 -Subject: [PATCH 12/16] MIPS: JZ4740: Correct clock gate bit for DMA - controller - -Signed-off-by: Lars-Peter Clausen <lars@metafoo.de> ---- - arch/mips/jz4740/clock.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/arch/mips/jz4740/clock.c -+++ b/arch/mips/jz4740/clock.c -@@ -687,7 +687,7 @@ static struct clk jz4740_clock_simple_cl - [3] = { - .name = "dma", - .parent = &jz_clk_high_speed_peripheral.clk, -- .gate_bit = JZ_CLOCK_GATE_UART0, -+ .gate_bit = JZ_CLOCK_GATE_DMAC, - .ops = &jz_clk_simple_ops, - }, - [4] = { diff --git a/target/linux/xburst/patches-3.10/013-MIPS-JZ4740-Acquire-and-enable-DMA-controller-clock.patch b/target/linux/xburst/patches-3.10/013-MIPS-JZ4740-Acquire-and-enable-DMA-controller-clock.patch deleted file mode 100644 index 027e3ad365..0000000000 --- a/target/linux/xburst/patches-3.10/013-MIPS-JZ4740-Acquire-and-enable-DMA-controller-clock.patch +++ /dev/null @@ -1,73 +0,0 @@ -From b1ab71156cd49b2389397d3be54b93fe394a1cb2 Mon Sep 17 00:00:00 2001 -From: Maarten ter Huurne <maarten@treewalker.org> -Date: Tue, 9 Oct 2012 13:09:57 +0200 -Subject: [PATCH 13/16] MIPS: JZ4740: Acquire and enable DMA controller clock - -Previously, it was assumed that the DMA controller clock is not gated -when the kernel starts running. While that is the power-on state, it is -safer to not rely on that. - -Signed-off-by: Lars-Peter Clausen <lars@metafoo.de> ---- - arch/mips/jz4740/clock.c | 2 +- - arch/mips/jz4740/dma.c | 24 ++++++++++++++++++++++-- - 2 files changed, 23 insertions(+), 3 deletions(-) - ---- a/arch/mips/jz4740/clock.c -+++ b/arch/mips/jz4740/clock.c -@@ -921,4 +921,4 @@ static int jz4740_clock_init(void) - - return 0; - } --arch_initcall(jz4740_clock_init); -+postcore_initcall(jz4740_clock_init); ---- a/arch/mips/jz4740/dma.c -+++ b/arch/mips/jz4740/dma.c -@@ -16,6 +16,7 @@ - #include <linux/kernel.h> - #include <linux/module.h> - #include <linux/spinlock.h> -+#include <linux/clk.h> - #include <linux/interrupt.h> - - #include <linux/dma-mapping.h> -@@ -268,6 +269,7 @@ static irqreturn_t jz4740_dma_irq(int ir - - static int jz4740_dma_init(void) - { -+ struct clk *clk; - unsigned int ret; - - jz4740_dma_base = ioremap(JZ4740_DMAC_BASE_ADDR, 0x400); -@@ -277,11 +279,29 @@ static int jz4740_dma_init(void) - - spin_lock_init(&jz4740_dma_lock); - -- ret = request_irq(JZ4740_IRQ_DMAC, jz4740_dma_irq, 0, "DMA", NULL); -+ clk = clk_get(NULL, "dma"); -+ if (IS_ERR(clk)) { -+ ret = PTR_ERR(clk); -+ printk(KERN_ERR "JZ4740 DMA: Failed to request clock: %d\n", -+ ret); -+ goto err_iounmap; -+ } - -- if (ret) -+ ret = request_irq(JZ4740_IRQ_DMAC, jz4740_dma_irq, 0, "DMA", NULL); -+ if (ret) { - printk(KERN_ERR "JZ4740 DMA: Failed to request irq: %d\n", ret); -+ goto err_clkput; -+ } -+ -+ clk_enable(clk); -+ -+ return 0; -+ -+err_clkput: -+ clk_put(clk); - -+err_iounmap: -+ iounmap(jz4740_dma_base); - return ret; - } - arch_initcall(jz4740_dma_init); diff --git a/target/linux/xburst/patches-3.10/014-MIPS-jz4740-Register-jz4740-DMA-device.patch b/target/linux/xburst/patches-3.10/014-MIPS-jz4740-Register-jz4740-DMA-device.patch deleted file mode 100644 index f10666dfad..0000000000 --- a/target/linux/xburst/patches-3.10/014-MIPS-jz4740-Register-jz4740-DMA-device.patch +++ /dev/null @@ -1,64 +0,0 @@ -From 734bdfd446b1eba0c54ad07703a192e6093417fd Mon Sep 17 00:00:00 2001 -From: Lars-Peter Clausen <lars@metafoo.de> -Date: Thu, 30 May 2013 18:25:03 +0200 -Subject: [PATCH 14/16] MIPS: jz4740: Register jz4740 DMA device - -Register a device for the newly added jz4740 dmaengine driver. - -Signed-off-by: Lars-Peter Clausen <lars@metafoo.de> -Acked-by: Ralf Baechle <ralf@linux-mips.org> -[manually edited to align struct assignment] -Signed-off-by: Vinod Koul <vinod.koul@intel.com> ---- - arch/mips/include/asm/mach-jz4740/platform.h | 1 + - arch/mips/jz4740/board-qi_lb60.c | 1 + - arch/mips/jz4740/platform.c | 21 +++++++++++++++++++++ - 3 files changed, 23 insertions(+) - ---- a/arch/mips/include/asm/mach-jz4740/platform.h -+++ b/arch/mips/include/asm/mach-jz4740/platform.h -@@ -32,6 +32,7 @@ extern struct platform_device jz4740_cod - extern struct platform_device jz4740_adc_device; - extern struct platform_device jz4740_wdt_device; - extern struct platform_device jz4740_pwm_device; -+extern struct platform_device jz4740_dma_device; - - void jz4740_serial_device_register(void); - ---- a/arch/mips/jz4740/board-qi_lb60.c -+++ b/arch/mips/jz4740/board-qi_lb60.c -@@ -437,6 +437,7 @@ static struct platform_device *jz_platfo - &jz4740_rtc_device, - &jz4740_adc_device, - &jz4740_pwm_device, -+ &jz4740_dma_device, - &qi_lb60_gpio_keys, - &qi_lb60_pwm_beeper, - &qi_lb60_charger_device, ---- a/arch/mips/jz4740/platform.c -+++ b/arch/mips/jz4740/platform.c -@@ -329,3 +329,24 @@ struct platform_device jz4740_pwm_device - .name = "jz4740-pwm", - .id = -1, - }; -+ -+/* DMA */ -+static struct resource jz4740_dma_resources[] = { -+ { -+ .start = JZ4740_DMAC_BASE_ADDR, -+ .end = JZ4740_DMAC_BASE_ADDR + 0x400 - 1, -+ .flags = IORESOURCE_MEM, -+ }, -+ { -+ .start = JZ4740_IRQ_DMAC, -+ .end = JZ4740_IRQ_DMAC, -+ .flags = IORESOURCE_IRQ, -+ }, -+}; -+ -+struct platform_device jz4740_dma_device = { -+ .name = "jz4740-dma", -+ .id = -1, -+ .num_resources = ARRAY_SIZE(jz4740_dma_resources), -+ .resource = jz4740_dma_resources, -+}; diff --git a/target/linux/xburst/patches-3.10/015-MIPS-jz4740-Remove-custom-DMA-API.patch b/target/linux/xburst/patches-3.10/015-MIPS-jz4740-Remove-custom-DMA-API.patch deleted file mode 100644 index 0bce0ac8fa..0000000000 --- a/target/linux/xburst/patches-3.10/015-MIPS-jz4740-Remove-custom-DMA-API.patch +++ /dev/null @@ -1,842 +0,0 @@ -From 7b91fca454e66ac1bc1fe5b68de0bf55f799bd41 Mon Sep 17 00:00:00 2001 -From: Lars-Peter Clausen <lars@metafoo.de> -Date: Thu, 30 May 2013 18:25:05 +0200 -Subject: [PATCH 15/16] MIPS: jz4740: Remove custom DMA API - -Now that all users of the custom jz4740 DMA API have been converted to use -the dmaengine API instead we can remove the custom API and move all the code -talking to the hardware to the dmaengine driver. - -Signed-off-by: Lars-Peter Clausen <lars@metafoo.de> -Acked-by: Ralf Baechle <ralf@linux-mips.org> -Signed-off-by: Vinod Koul <vinod.koul@intel.com> ---- - arch/mips/include/asm/mach-jz4740/dma.h | 56 ------ - arch/mips/jz4740/Makefile | 2 +- - arch/mips/jz4740/dma.c | 307 ------------------------------- - drivers/dma/dma-jz4740.c | 258 ++++++++++++++++++++++---- - 4 files changed, 222 insertions(+), 401 deletions(-) - delete mode 100644 arch/mips/jz4740/dma.c - ---- a/arch/mips/include/asm/mach-jz4740/dma.h -+++ b/arch/mips/include/asm/mach-jz4740/dma.h -@@ -16,8 +16,6 @@ - #ifndef __ASM_MACH_JZ4740_DMA_H__ - #define __ASM_MACH_JZ4740_DMA_H__ - --struct jz4740_dma_chan; -- - enum jz4740_dma_request_type { - JZ4740_DMA_TYPE_AUTO_REQUEST = 8, - JZ4740_DMA_TYPE_UART_TRANSMIT = 20, -@@ -33,58 +31,4 @@ enum jz4740_dma_request_type { - JZ4740_DMA_TYPE_SLCD = 30, - }; - --enum jz4740_dma_width { -- JZ4740_DMA_WIDTH_32BIT = 0, -- JZ4740_DMA_WIDTH_8BIT = 1, -- JZ4740_DMA_WIDTH_16BIT = 2, --}; -- --enum jz4740_dma_transfer_size { -- JZ4740_DMA_TRANSFER_SIZE_4BYTE = 0, -- JZ4740_DMA_TRANSFER_SIZE_1BYTE = 1, -- JZ4740_DMA_TRANSFER_SIZE_2BYTE = 2, -- JZ4740_DMA_TRANSFER_SIZE_16BYTE = 3, -- JZ4740_DMA_TRANSFER_SIZE_32BYTE = 4, --}; -- --enum jz4740_dma_flags { -- JZ4740_DMA_SRC_AUTOINC = 0x2, -- JZ4740_DMA_DST_AUTOINC = 0x1, --}; -- --enum jz4740_dma_mode { -- JZ4740_DMA_MODE_SINGLE = 0, -- JZ4740_DMA_MODE_BLOCK = 1, --}; -- --struct jz4740_dma_config { -- enum jz4740_dma_width src_width; -- enum jz4740_dma_width dst_width; -- enum jz4740_dma_transfer_size transfer_size; -- enum jz4740_dma_request_type request_type; -- enum jz4740_dma_flags flags; -- enum jz4740_dma_mode mode; --}; -- --typedef void (*jz4740_dma_complete_callback_t)(struct jz4740_dma_chan *, int, void *); -- --struct jz4740_dma_chan *jz4740_dma_request(void *dev, const char *name); --void jz4740_dma_free(struct jz4740_dma_chan *dma); -- --void jz4740_dma_configure(struct jz4740_dma_chan *dma, -- const struct jz4740_dma_config *config); -- -- --void jz4740_dma_enable(struct jz4740_dma_chan *dma); --void jz4740_dma_disable(struct jz4740_dma_chan *dma); -- --void jz4740_dma_set_src_addr(struct jz4740_dma_chan *dma, dma_addr_t src); --void jz4740_dma_set_dst_addr(struct jz4740_dma_chan *dma, dma_addr_t dst); --void jz4740_dma_set_transfer_count(struct jz4740_dma_chan *dma, uint32_t count); -- --uint32_t jz4740_dma_get_residue(const struct jz4740_dma_chan *dma); -- --void jz4740_dma_set_complete_cb(struct jz4740_dma_chan *dma, -- jz4740_dma_complete_callback_t cb); -- - #endif /* __ASM_JZ4740_DMA_H__ */ ---- a/arch/mips/jz4740/Makefile -+++ b/arch/mips/jz4740/Makefile -@@ -4,7 +4,7 @@ - - # Object file lists. - --obj-y += prom.o irq.o time.o reset.o setup.o dma.o \ -+obj-y += prom.o irq.o time.o reset.o setup.o \ - gpio.o clock.o platform.o timer.o serial.o - - obj-$(CONFIG_DEBUG_FS) += clock-debugfs.o ---- a/arch/mips/jz4740/dma.c -+++ /dev/null -@@ -1,307 +0,0 @@ --/* -- * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de> -- * JZ4740 SoC DMA support -- * -- * This program is free software; you can redistribute it and/or modify it -- * under the terms of the GNU General Public License as published by the -- * Free Software Foundation; either version 2 of the License, or (at your -- * option) any later version. -- * -- * You should have received a copy of the GNU General Public License along -- * with this program; if not, write to the Free Software Foundation, Inc., -- * 675 Mass Ave, Cambridge, MA 02139, USA. -- * -- */ -- --#include <linux/kernel.h> --#include <linux/module.h> --#include <linux/spinlock.h> --#include <linux/clk.h> --#include <linux/interrupt.h> -- --#include <linux/dma-mapping.h> --#include <asm/mach-jz4740/dma.h> --#include <asm/mach-jz4740/base.h> -- --#define JZ_REG_DMA_SRC_ADDR(x) (0x00 + (x) * 0x20) --#define JZ_REG_DMA_DST_ADDR(x) (0x04 + (x) * 0x20) --#define JZ_REG_DMA_TRANSFER_COUNT(x) (0x08 + (x) * 0x20) --#define JZ_REG_DMA_REQ_TYPE(x) (0x0C + (x) * 0x20) --#define JZ_REG_DMA_STATUS_CTRL(x) (0x10 + (x) * 0x20) --#define JZ_REG_DMA_CMD(x) (0x14 + (x) * 0x20) --#define JZ_REG_DMA_DESC_ADDR(x) (0x18 + (x) * 0x20) -- --#define JZ_REG_DMA_CTRL 0x300 --#define JZ_REG_DMA_IRQ 0x304 --#define JZ_REG_DMA_DOORBELL 0x308 --#define JZ_REG_DMA_DOORBELL_SET 0x30C -- --#define JZ_DMA_STATUS_CTRL_NO_DESC BIT(31) --#define JZ_DMA_STATUS_CTRL_DESC_INV BIT(6) --#define JZ_DMA_STATUS_CTRL_ADDR_ERR BIT(4) --#define JZ_DMA_STATUS_CTRL_TRANSFER_DONE BIT(3) --#define JZ_DMA_STATUS_CTRL_HALT BIT(2) --#define JZ_DMA_STATUS_CTRL_COUNT_TERMINATE BIT(1) --#define JZ_DMA_STATUS_CTRL_ENABLE BIT(0) -- --#define JZ_DMA_CMD_SRC_INC BIT(23) --#define JZ_DMA_CMD_DST_INC BIT(22) --#define JZ_DMA_CMD_RDIL_MASK (0xf << 16) --#define JZ_DMA_CMD_SRC_WIDTH_MASK (0x3 << 14) --#define JZ_DMA_CMD_DST_WIDTH_MASK (0x3 << 12) --#define JZ_DMA_CMD_INTERVAL_LENGTH_MASK (0x7 << 8) --#define JZ_DMA_CMD_BLOCK_MODE BIT(7) --#define JZ_DMA_CMD_DESC_VALID BIT(4) --#define JZ_DMA_CMD_DESC_VALID_MODE BIT(3) --#define JZ_DMA_CMD_VALID_IRQ_ENABLE BIT(2) --#define JZ_DMA_CMD_TRANSFER_IRQ_ENABLE BIT(1) --#define JZ_DMA_CMD_LINK_ENABLE BIT(0) -- --#define JZ_DMA_CMD_FLAGS_OFFSET 22 --#define JZ_DMA_CMD_RDIL_OFFSET 16 --#define JZ_DMA_CMD_SRC_WIDTH_OFFSET 14 --#define JZ_DMA_CMD_DST_WIDTH_OFFSET 12 --#define JZ_DMA_CMD_TRANSFER_SIZE_OFFSET 8 --#define JZ_DMA_CMD_MODE_OFFSET 7 -- --#define JZ_DMA_CTRL_PRIORITY_MASK (0x3 << 8) --#define JZ_DMA_CTRL_HALT BIT(3) --#define JZ_DMA_CTRL_ADDRESS_ERROR BIT(2) --#define JZ_DMA_CTRL_ENABLE BIT(0) -- -- --static void __iomem *jz4740_dma_base; --static spinlock_t jz4740_dma_lock; -- --static inline uint32_t jz4740_dma_read(size_t reg) --{ -- return readl(jz4740_dma_base + reg); --} -- --static inline void jz4740_dma_write(size_t reg, uint32_t val) --{ -- writel(val, jz4740_dma_base + reg); --} -- --static inline void jz4740_dma_write_mask(size_t reg, uint32_t val, uint32_t mask) --{ -- uint32_t val2; -- val2 = jz4740_dma_read(reg); -- val2 &= ~mask; -- val2 |= val; -- jz4740_dma_write(reg, val2); --} -- --struct jz4740_dma_chan { -- unsigned int id; -- void *dev; -- const char *name; -- -- enum jz4740_dma_flags flags; -- uint32_t transfer_shift; -- -- jz4740_dma_complete_callback_t complete_cb; -- -- unsigned used:1; --}; -- --#define JZ4740_DMA_CHANNEL(_id) { .id = _id } -- --struct jz4740_dma_chan jz4740_dma_channels[] = { -- JZ4740_DMA_CHANNEL(0), -- JZ4740_DMA_CHANNEL(1), -- JZ4740_DMA_CHANNEL(2), -- JZ4740_DMA_CHANNEL(3), -- JZ4740_DMA_CHANNEL(4), -- JZ4740_DMA_CHANNEL(5), --}; -- --struct jz4740_dma_chan *jz4740_dma_request(void *dev, const char *name) --{ -- unsigned int i; -- struct jz4740_dma_chan *dma = NULL; -- -- spin_lock(&jz4740_dma_lock); -- -- for (i = 0; i < ARRAY_SIZE(jz4740_dma_channels); ++i) { -- if (!jz4740_dma_channels[i].used) { -- dma = &jz4740_dma_channels[i]; -- dma->used = 1; -- break; -- } -- } -- -- spin_unlock(&jz4740_dma_lock); -- -- if (!dma) -- return NULL; -- -- dma->dev = dev; -- dma->name = name; -- -- return dma; --} --EXPORT_SYMBOL_GPL(jz4740_dma_request); -- --void jz4740_dma_configure(struct jz4740_dma_chan *dma, -- const struct jz4740_dma_config *config) --{ -- uint32_t cmd; -- -- switch (config->transfer_size) { -- case JZ4740_DMA_TRANSFER_SIZE_2BYTE: -- dma->transfer_shift = 1; -- break; -- case JZ4740_DMA_TRANSFER_SIZE_4BYTE: -- dma->transfer_shift = 2; -- break; -- case JZ4740_DMA_TRANSFER_SIZE_16BYTE: -- dma->transfer_shift = 4; -- break; -- case JZ4740_DMA_TRANSFER_SIZE_32BYTE: -- dma->transfer_shift = 5; -- break; -- default: -- dma->transfer_shift = 0; -- break; -- } -- -- cmd = config->flags << JZ_DMA_CMD_FLAGS_OFFSET; -- cmd |= config->src_width << JZ_DMA_CMD_SRC_WIDTH_OFFSET; -- cmd |= config->dst_width << JZ_DMA_CMD_DST_WIDTH_OFFSET; -- cmd |= config->transfer_size << JZ_DMA_CMD_TRANSFER_SIZE_OFFSET; -- cmd |= config->mode << JZ_DMA_CMD_MODE_OFFSET; -- cmd |= JZ_DMA_CMD_TRANSFER_IRQ_ENABLE; -- -- jz4740_dma_write(JZ_REG_DMA_CMD(dma->id), cmd); -- jz4740_dma_write(JZ_REG_DMA_STATUS_CTRL(dma->id), 0); -- jz4740_dma_write(JZ_REG_DMA_REQ_TYPE(dma->id), config->request_type); --} --EXPORT_SYMBOL_GPL(jz4740_dma_configure); -- --void jz4740_dma_set_src_addr(struct jz4740_dma_chan *dma, dma_addr_t src) --{ -- jz4740_dma_write(JZ_REG_DMA_SRC_ADDR(dma->id), src); --} --EXPORT_SYMBOL_GPL(jz4740_dma_set_src_addr); -- --void jz4740_dma_set_dst_addr(struct jz4740_dma_chan *dma, dma_addr_t dst) --{ -- jz4740_dma_write(JZ_REG_DMA_DST_ADDR(dma->id), dst); --} --EXPORT_SYMBOL_GPL(jz4740_dma_set_dst_addr); -- --void jz4740_dma_set_transfer_count(struct jz4740_dma_chan *dma, uint32_t count) --{ -- count >>= dma->transfer_shift; -- jz4740_dma_write(JZ_REG_DMA_TRANSFER_COUNT(dma->id), count); --} --EXPORT_SYMBOL_GPL(jz4740_dma_set_transfer_count); -- --void jz4740_dma_set_complete_cb(struct jz4740_dma_chan *dma, -- jz4740_dma_complete_callback_t cb) --{ -- dma->complete_cb = cb; --} --EXPORT_SYMBOL_GPL(jz4740_dma_set_complete_cb); -- --void jz4740_dma_free(struct jz4740_dma_chan *dma) --{ -- dma->dev = NULL; -- dma->complete_cb = NULL; -- dma->used = 0; --} --EXPORT_SYMBOL_GPL(jz4740_dma_free); -- --void jz4740_dma_enable(struct jz4740_dma_chan *dma) --{ -- jz4740_dma_write_mask(JZ_REG_DMA_STATUS_CTRL(dma->id), -- JZ_DMA_STATUS_CTRL_NO_DESC | JZ_DMA_STATUS_CTRL_ENABLE, -- JZ_DMA_STATUS_CTRL_HALT | JZ_DMA_STATUS_CTRL_NO_DESC | -- JZ_DMA_STATUS_CTRL_ENABLE); -- -- jz4740_dma_write_mask(JZ_REG_DMA_CTRL, -- JZ_DMA_CTRL_ENABLE, -- JZ_DMA_CTRL_HALT | JZ_DMA_CTRL_ENABLE); --} --EXPORT_SYMBOL_GPL(jz4740_dma_enable); -- --void jz4740_dma_disable(struct jz4740_dma_chan *dma) --{ -- jz4740_dma_write_mask(JZ_REG_DMA_STATUS_CTRL(dma->id), 0, -- JZ_DMA_STATUS_CTRL_ENABLE); --} --EXPORT_SYMBOL_GPL(jz4740_dma_disable); -- --uint32_t jz4740_dma_get_residue(const struct jz4740_dma_chan *dma) --{ -- uint32_t residue; -- residue = jz4740_dma_read(JZ_REG_DMA_TRANSFER_COUNT(dma->id)); -- return residue << dma->transfer_shift; --} --EXPORT_SYMBOL_GPL(jz4740_dma_get_residue); -- --static void jz4740_dma_chan_irq(struct jz4740_dma_chan *dma) --{ -- (void) jz4740_dma_read(JZ_REG_DMA_STATUS_CTRL(dma->id)); -- -- jz4740_dma_write_mask(JZ_REG_DMA_STATUS_CTRL(dma->id), 0, -- JZ_DMA_STATUS_CTRL_ENABLE | JZ_DMA_STATUS_CTRL_TRANSFER_DONE); -- -- if (dma->complete_cb) -- dma->complete_cb(dma, 0, dma->dev); --} -- --static irqreturn_t jz4740_dma_irq(int irq, void *dev_id) --{ -- uint32_t irq_status; -- unsigned int i; -- -- irq_status = readl(jz4740_dma_base + JZ_REG_DMA_IRQ); -- -- for (i = 0; i < 6; ++i) { -- if (irq_status & (1 << i)) -- jz4740_dma_chan_irq(&jz4740_dma_channels[i]); -- } -- -- return IRQ_HANDLED; --} -- --static int jz4740_dma_init(void) --{ -- struct clk *clk; -- unsigned int ret; -- -- jz4740_dma_base = ioremap(JZ4740_DMAC_BASE_ADDR, 0x400); -- -- if (!jz4740_dma_base) -- return -EBUSY; -- -- spin_lock_init(&jz4740_dma_lock); -- -- clk = clk_get(NULL, "dma"); -- if (IS_ERR(clk)) { -- ret = PTR_ERR(clk); -- printk(KERN_ERR "JZ4740 DMA: Failed to request clock: %d\n", -- ret); -- goto err_iounmap; -- } -- -- ret = request_irq(JZ4740_IRQ_DMAC, jz4740_dma_irq, 0, "DMA", NULL); -- if (ret) { -- printk(KERN_ERR "JZ4740 DMA: Failed to request irq: %d\n", ret); -- goto err_clkput; -- } -- -- clk_enable(clk); -- -- return 0; -- --err_clkput: -- clk_put(clk); -- --err_iounmap: -- iounmap(jz4740_dma_base); -- return ret; --} --arch_initcall(jz4740_dma_init); ---- a/drivers/dma/dma-jz4740.c -+++ b/drivers/dma/dma-jz4740.c -@@ -22,6 +22,8 @@ - #include <linux/platform_device.h> - #include <linux/slab.h> - #include <linux/spinlock.h> -+#include <linux/irq.h> -+#include <linux/clk.h> - - #include <asm/mach-jz4740/dma.h> - -@@ -29,6 +31,76 @@ - - #define JZ_DMA_NR_CHANS 6 - -+#define JZ_REG_DMA_SRC_ADDR(x) (0x00 + (x) * 0x20) -+#define JZ_REG_DMA_DST_ADDR(x) (0x04 + (x) * 0x20) -+#define JZ_REG_DMA_TRANSFER_COUNT(x) (0x08 + (x) * 0x20) -+#define JZ_REG_DMA_REQ_TYPE(x) (0x0C + (x) * 0x20) -+#define JZ_REG_DMA_STATUS_CTRL(x) (0x10 + (x) * 0x20) -+#define JZ_REG_DMA_CMD(x) (0x14 + (x) * 0x20) -+#define JZ_REG_DMA_DESC_ADDR(x) (0x18 + (x) * 0x20) -+ -+#define JZ_REG_DMA_CTRL 0x300 -+#define JZ_REG_DMA_IRQ 0x304 -+#define JZ_REG_DMA_DOORBELL 0x308 -+#define JZ_REG_DMA_DOORBELL_SET 0x30C -+ -+#define JZ_DMA_STATUS_CTRL_NO_DESC BIT(31) -+#define JZ_DMA_STATUS_CTRL_DESC_INV BIT(6) -+#define JZ_DMA_STATUS_CTRL_ADDR_ERR BIT(4) -+#define JZ_DMA_STATUS_CTRL_TRANSFER_DONE BIT(3) -+#define JZ_DMA_STATUS_CTRL_HALT BIT(2) -+#define JZ_DMA_STATUS_CTRL_COUNT_TERMINATE BIT(1) -+#define JZ_DMA_STATUS_CTRL_ENABLE BIT(0) -+ -+#define JZ_DMA_CMD_SRC_INC BIT(23) -+#define JZ_DMA_CMD_DST_INC BIT(22) -+#define JZ_DMA_CMD_RDIL_MASK (0xf << 16) -+#define JZ_DMA_CMD_SRC_WIDTH_MASK (0x3 << 14) -+#define JZ_DMA_CMD_DST_WIDTH_MASK (0x3 << 12) -+#define JZ_DMA_CMD_INTERVAL_LENGTH_MASK (0x7 << 8) -+#define JZ_DMA_CMD_BLOCK_MODE BIT(7) -+#define JZ_DMA_CMD_DESC_VALID BIT(4) -+#define JZ_DMA_CMD_DESC_VALID_MODE BIT(3) -+#define JZ_DMA_CMD_VALID_IRQ_ENABLE BIT(2) -+#define JZ_DMA_CMD_TRANSFER_IRQ_ENABLE BIT(1) -+#define JZ_DMA_CMD_LINK_ENABLE BIT(0) -+ -+#define JZ_DMA_CMD_FLAGS_OFFSET 22 -+#define JZ_DMA_CMD_RDIL_OFFSET 16 -+#define JZ_DMA_CMD_SRC_WIDTH_OFFSET 14 -+#define JZ_DMA_CMD_DST_WIDTH_OFFSET 12 -+#define JZ_DMA_CMD_TRANSFER_SIZE_OFFSET 8 -+#define JZ_DMA_CMD_MODE_OFFSET 7 -+ -+#define JZ_DMA_CTRL_PRIORITY_MASK (0x3 << 8) -+#define JZ_DMA_CTRL_HALT BIT(3) -+#define JZ_DMA_CTRL_ADDRESS_ERROR BIT(2) -+#define JZ_DMA_CTRL_ENABLE BIT(0) -+ -+enum jz4740_dma_width { -+ JZ4740_DMA_WIDTH_32BIT = 0, -+ JZ4740_DMA_WIDTH_8BIT = 1, -+ JZ4740_DMA_WIDTH_16BIT = 2, -+}; -+ -+enum jz4740_dma_transfer_size { -+ JZ4740_DMA_TRANSFER_SIZE_4BYTE = 0, -+ JZ4740_DMA_TRANSFER_SIZE_1BYTE = 1, -+ JZ4740_DMA_TRANSFER_SIZE_2BYTE = 2, -+ JZ4740_DMA_TRANSFER_SIZE_16BYTE = 3, -+ JZ4740_DMA_TRANSFER_SIZE_32BYTE = 4, -+}; -+ -+enum jz4740_dma_flags { -+ JZ4740_DMA_SRC_AUTOINC = 0x2, -+ JZ4740_DMA_DST_AUTOINC = 0x1, -+}; -+ -+enum jz4740_dma_mode { -+ JZ4740_DMA_MODE_SINGLE = 0, -+ JZ4740_DMA_MODE_BLOCK = 1, -+}; -+ - struct jz4740_dma_sg { - dma_addr_t addr; - unsigned int len; -@@ -46,9 +118,10 @@ struct jz4740_dma_desc { - - struct jz4740_dmaengine_chan { - struct virt_dma_chan vchan; -- struct jz4740_dma_chan *jz_chan; -+ unsigned int id; - - dma_addr_t fifo_addr; -+ unsigned int transfer_shift; - - struct jz4740_dma_desc *desc; - unsigned int next_sg; -@@ -56,10 +129,19 @@ struct jz4740_dmaengine_chan { - - struct jz4740_dma_dev { - struct dma_device ddev; -+ void __iomem *base; -+ struct clk *clk; - - struct jz4740_dmaengine_chan chan[JZ_DMA_NR_CHANS]; - }; - -+static struct jz4740_dma_dev *jz4740_dma_chan_get_dev( -+ struct jz4740_dmaengine_chan *chan) -+{ -+ return container_of(chan->vchan.chan.device, struct jz4740_dma_dev, -+ ddev); -+} -+ - static struct jz4740_dmaengine_chan *to_jz4740_dma_chan(struct dma_chan *c) - { - return container_of(c, struct jz4740_dmaengine_chan, vchan.chan); -@@ -70,6 +152,29 @@ static struct jz4740_dma_desc *to_jz4740 - return container_of(vdesc, struct jz4740_dma_desc, vdesc); - } - -+static inline uint32_t jz4740_dma_read(struct jz4740_dma_dev *dmadev, -+ unsigned int reg) -+{ -+ return readl(dmadev->base + reg); -+} -+ -+static inline void jz4740_dma_write(struct jz4740_dma_dev *dmadev, -+ unsigned reg, uint32_t val) -+{ -+ writel(val, dmadev->base + reg); -+} -+ -+static inline void jz4740_dma_write_mask(struct jz4740_dma_dev *dmadev, -+ unsigned int reg, uint32_t val, uint32_t mask) -+{ -+ uint32_t tmp; -+ -+ tmp = jz4740_dma_read(dmadev, reg); -+ tmp &= ~mask; -+ tmp |= val; -+ jz4740_dma_write(dmadev, reg, tmp); -+} -+ - static struct jz4740_dma_desc *jz4740_dma_alloc_desc(unsigned int num_sgs) - { - return kzalloc(sizeof(struct jz4740_dma_desc) + -@@ -108,30 +213,60 @@ static int jz4740_dma_slave_config(struc - const struct dma_slave_config *config) - { - struct jz4740_dmaengine_chan *chan = to_jz4740_dma_chan(c); -- struct jz4740_dma_config jzcfg; -+ struct jz4740_dma_dev *dmadev = jz4740_dma_chan_get_dev(chan); -+ enum jz4740_dma_width src_width; -+ enum jz4740_dma_width dst_width; -+ enum jz4740_dma_transfer_size transfer_size; -+ enum jz4740_dma_flags flags; -+ uint32_t cmd; - - switch (config->direction) { - case DMA_MEM_TO_DEV: -- jzcfg.flags = JZ4740_DMA_SRC_AUTOINC; -- jzcfg.transfer_size = jz4740_dma_maxburst(config->dst_maxburst); -+ flags = JZ4740_DMA_SRC_AUTOINC; -+ transfer_size = jz4740_dma_maxburst(config->dst_maxburst); - chan->fifo_addr = config->dst_addr; - break; - case DMA_DEV_TO_MEM: -- jzcfg.flags = JZ4740_DMA_DST_AUTOINC; -- jzcfg.transfer_size = jz4740_dma_maxburst(config->src_maxburst); -+ flags = JZ4740_DMA_DST_AUTOINC; -+ transfer_size = jz4740_dma_maxburst(config->src_maxburst); - chan->fifo_addr = config->src_addr; - break; - default: - return -EINVAL; - } - -+ src_width = jz4740_dma_width(config->src_addr_width); -+ dst_width = jz4740_dma_width(config->dst_addr_width); - -- jzcfg.src_width = jz4740_dma_width(config->src_addr_width); -- jzcfg.dst_width = jz4740_dma_width(config->dst_addr_width); -- jzcfg.mode = JZ4740_DMA_MODE_SINGLE; -- jzcfg.request_type = config->slave_id; -+ switch (transfer_size) { -+ case JZ4740_DMA_TRANSFER_SIZE_2BYTE: -+ chan->transfer_shift = 1; -+ break; -+ case JZ4740_DMA_TRANSFER_SIZE_4BYTE: -+ chan->transfer_shift = 2; -+ break; -+ case JZ4740_DMA_TRANSFER_SIZE_16BYTE: -+ chan->transfer_shift = 4; -+ break; -+ case JZ4740_DMA_TRANSFER_SIZE_32BYTE: -+ chan->transfer_shift = 5; -+ break; -+ default: -+ chan->transfer_shift = 0; -+ break; -+ } - -- jz4740_dma_configure(chan->jz_chan, &jzcfg); -+ cmd = flags << JZ_DMA_CMD_FLAGS_OFFSET; -+ cmd |= src_width << JZ_DMA_CMD_SRC_WIDTH_OFFSET; -+ cmd |= dst_width << JZ_DMA_CMD_DST_WIDTH_OFFSET; -+ cmd |= transfer_size << JZ_DMA_CMD_TRANSFER_SIZE_OFFSET; -+ cmd |= JZ4740_DMA_MODE_SINGLE << JZ_DMA_CMD_MODE_OFFSET; -+ cmd |= JZ_DMA_CMD_TRANSFER_IRQ_ENABLE; -+ -+ jz4740_dma_write(dmadev, JZ_REG_DMA_CMD(chan->id), cmd); -+ jz4740_dma_write(dmadev, JZ_REG_DMA_STATUS_CTRL(chan->id), 0); -+ jz4740_dma_write(dmadev, JZ_REG_DMA_REQ_TYPE(chan->id), -+ config->slave_id); - - return 0; - } -@@ -139,11 +274,13 @@ static int jz4740_dma_slave_config(struc - static int jz4740_dma_terminate_all(struct dma_chan *c) - { - struct jz4740_dmaengine_chan *chan = to_jz4740_dma_chan(c); -+ struct jz4740_dma_dev *dmadev = jz4740_dma_chan_get_dev(chan); - unsigned long flags; - LIST_HEAD(head); - - spin_lock_irqsave(&chan->vchan.lock, flags); -- jz4740_dma_disable(chan->jz_chan); -+ jz4740_dma_write_mask(dmadev, JZ_REG_DMA_STATUS_CTRL(chan->id), 0, -+ JZ_DMA_STATUS_CTRL_ENABLE); - chan->desc = NULL; - vchan_get_all_descriptors(&chan->vchan, &head); - spin_unlock_irqrestore(&chan->vchan.lock, flags); -@@ -170,11 +307,13 @@ static int jz4740_dma_control(struct dma - - static int jz4740_dma_start_transfer(struct jz4740_dmaengine_chan *chan) - { -+ struct jz4740_dma_dev *dmadev = jz4740_dma_chan_get_dev(chan); - dma_addr_t src_addr, dst_addr; - struct virt_dma_desc *vdesc; - struct jz4740_dma_sg *sg; - -- jz4740_dma_disable(chan->jz_chan); -+ jz4740_dma_write_mask(dmadev, JZ_REG_DMA_STATUS_CTRL(chan->id), 0, -+ JZ_DMA_STATUS_CTRL_ENABLE); - - if (!chan->desc) { - vdesc = vchan_next_desc(&chan->vchan); -@@ -196,22 +335,27 @@ static int jz4740_dma_start_transfer(str - src_addr = chan->fifo_addr; - dst_addr = sg->addr; - } -- jz4740_dma_set_src_addr(chan->jz_chan, src_addr); -- jz4740_dma_set_dst_addr(chan->jz_chan, dst_addr); -- jz4740_dma_set_transfer_count(chan->jz_chan, sg->len); -+ jz4740_dma_write(dmadev, JZ_REG_DMA_SRC_ADDR(chan->id), src_addr); -+ jz4740_dma_write(dmadev, JZ_REG_DMA_DST_ADDR(chan->id), dst_addr); -+ jz4740_dma_write(dmadev, JZ_REG_DMA_TRANSFER_COUNT(chan->id), -+ sg->len >> chan->transfer_shift); - - chan->next_sg++; - -- jz4740_dma_enable(chan->jz_chan); -+ jz4740_dma_write_mask(dmadev, JZ_REG_DMA_STATUS_CTRL(chan->id), -+ JZ_DMA_STATUS_CTRL_NO_DESC | JZ_DMA_STATUS_CTRL_ENABLE, -+ JZ_DMA_STATUS_CTRL_HALT | JZ_DMA_STATUS_CTRL_NO_DESC | -+ JZ_DMA_STATUS_CTRL_ENABLE); -+ -+ jz4740_dma_write_mask(dmadev, JZ_REG_DMA_CTRL, -+ JZ_DMA_CTRL_ENABLE, -+ JZ_DMA_CTRL_HALT | JZ_DMA_CTRL_ENABLE); - - return 0; - } - --static void jz4740_dma_complete_cb(struct jz4740_dma_chan *jz_chan, int error, -- void *devid) -+static void jz4740_dma_chan_irq(struct jz4740_dmaengine_chan *chan) - { -- struct jz4740_dmaengine_chan *chan = devid; -- - spin_lock(&chan->vchan.lock); - if (chan->desc) { - if (chan->desc && chan->desc->cyclic) { -@@ -227,6 +371,28 @@ static void jz4740_dma_complete_cb(struc - spin_unlock(&chan->vchan.lock); - } - -+static irqreturn_t jz4740_dma_irq(int irq, void *devid) -+{ -+ struct jz4740_dma_dev *dmadev = devid; -+ uint32_t irq_status; -+ unsigned int i; -+ -+ irq_status = readl(dmadev->base + JZ_REG_DMA_IRQ); -+ -+ for (i = 0; i < 6; ++i) { -+ if (irq_status & (1 << i)) { -+ jz4740_dma_write_mask(dmadev, -+ JZ_REG_DMA_STATUS_CTRL(i), 0, -+ JZ_DMA_STATUS_CTRL_ENABLE | -+ JZ_DMA_STATUS_CTRL_TRANSFER_DONE); -+ -+ jz4740_dma_chan_irq(&dmadev->chan[i]); -+ } -+ } -+ -+ return IRQ_HANDLED; -+} -+ - static void jz4740_dma_issue_pending(struct dma_chan *c) - { - struct jz4740_dmaengine_chan *chan = to_jz4740_dma_chan(c); -@@ -298,7 +464,8 @@ static struct dma_async_tx_descriptor *j - static size_t jz4740_dma_desc_residue(struct jz4740_dmaengine_chan *chan, - struct jz4740_dma_desc *desc, unsigned int next_sg) - { -- size_t residue = 0; -+ struct jz4740_dma_dev *dmadev = jz4740_dma_chan_get_dev(chan); -+ unsigned int residue, count; - unsigned int i; - - residue = 0; -@@ -306,8 +473,11 @@ static size_t jz4740_dma_desc_residue(st - for (i = next_sg; i < desc->num_sgs; i++) - residue += desc->sg[i].len; - -- if (next_sg != 0) -- residue += jz4740_dma_get_residue(chan->jz_chan); -+ if (next_sg != 0) { -+ count = jz4740_dma_read(dmadev, -+ JZ_REG_DMA_TRANSFER_COUNT(chan->id)); -+ residue += count << chan->transfer_shift; -+ } - - return residue; - } -@@ -342,24 +512,12 @@ static enum dma_status jz4740_dma_tx_sta - - static int jz4740_dma_alloc_chan_resources(struct dma_chan *c) - { -- struct jz4740_dmaengine_chan *chan = to_jz4740_dma_chan(c); -- -- chan->jz_chan = jz4740_dma_request(chan, NULL); -- if (!chan->jz_chan) -- return -EBUSY; -- -- jz4740_dma_set_complete_cb(chan->jz_chan, jz4740_dma_complete_cb); -- - return 0; - } - - static void jz4740_dma_free_chan_resources(struct dma_chan *c) - { -- struct jz4740_dmaengine_chan *chan = to_jz4740_dma_chan(c); -- -- vchan_free_chan_resources(&chan->vchan); -- jz4740_dma_free(chan->jz_chan); -- chan->jz_chan = NULL; -+ vchan_free_chan_resources(to_virt_chan(c)); - } - - static void jz4740_dma_desc_free(struct virt_dma_desc *vdesc) -@@ -373,7 +531,9 @@ static int jz4740_dma_probe(struct platf - struct jz4740_dma_dev *dmadev; - struct dma_device *dd; - unsigned int i; -+ struct resource *res; - int ret; -+ int irq; - - dmadev = devm_kzalloc(&pdev->dev, sizeof(*dmadev), GFP_KERNEL); - if (!dmadev) -@@ -381,6 +541,17 @@ static int jz4740_dma_probe(struct platf - - dd = &dmadev->ddev; - -+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ dmadev->base = devm_ioremap_resource(&pdev->dev, res); -+ if (IS_ERR(dmadev->base)) -+ return PTR_ERR(dmadev->base); -+ -+ dmadev->clk = clk_get(&pdev->dev, "dma"); -+ if (IS_ERR(dmadev->clk)) -+ return PTR_ERR(dmadev->clk); -+ -+ clk_prepare_enable(dmadev->clk); -+ - dma_cap_set(DMA_SLAVE, dd->cap_mask); - dma_cap_set(DMA_CYCLIC, dd->cap_mask); - dd->device_alloc_chan_resources = jz4740_dma_alloc_chan_resources; -@@ -396,6 +567,7 @@ static int jz4740_dma_probe(struct platf - - for (i = 0; i < dd->chancnt; i++) { - chan = &dmadev->chan[i]; -+ chan->id = i; - chan->vchan.desc_free = jz4740_dma_desc_free; - vchan_init(&chan->vchan, dd); - } -@@ -404,16 +576,28 @@ static int jz4740_dma_probe(struct platf - if (ret) - return ret; - -+ irq = platform_get_irq(pdev, 0); -+ ret = request_irq(irq, jz4740_dma_irq, 0, dev_name(&pdev->dev), dmadev); -+ if (ret) -+ goto err_unregister; -+ - platform_set_drvdata(pdev, dmadev); - - return 0; -+ -+err_unregister: -+ dma_async_device_unregister(dd); -+ return ret; - } - - static int jz4740_dma_remove(struct platform_device *pdev) - { - struct jz4740_dma_dev *dmadev = platform_get_drvdata(pdev); -+ int irq = platform_get_irq(pdev, 0); - -+ free_irq(irq, dmadev); - dma_async_device_unregister(&dmadev->ddev); -+ clk_disable_unprepare(dmadev->clk); - - return 0; - } diff --git a/target/linux/xburst/patches-3.10/016-ASoC-jz4740-Use-the-generic-dmaengine-PCM-driver.patch b/target/linux/xburst/patches-3.10/016-ASoC-jz4740-Use-the-generic-dmaengine-PCM-driver.patch deleted file mode 100644 index 1fb3731083..0000000000 --- a/target/linux/xburst/patches-3.10/016-ASoC-jz4740-Use-the-generic-dmaengine-PCM-driver.patch +++ /dev/null @@ -1,507 +0,0 @@ -From a20f54fdd500e5bccc9bd1ca4ac9f150addf2e64 Mon Sep 17 00:00:00 2001 -From: Lars-Peter Clausen <lars@metafoo.de> -Date: Sat, 27 Apr 2013 21:26:30 +0200 -Subject: [PATCH 16/16] ASoC: jz4740: Use the generic dmaengine PCM driver - -Since there is a dmaengine driver for the jz4740 DMA controller now we can use -the generic dmaengine PCM driver instead of a custom one. - -Signed-off-by: Lars-Peter Clausen <lars@metafoo.de> -Acked-by: Mark Brown <broonie@opensource.wolfsonmicro.com> ---- - sound/soc/jz4740/Kconfig | 1 + - sound/soc/jz4740/jz4740-i2s.c | 48 +++---- - sound/soc/jz4740/jz4740-pcm.c | 310 ++--------------------------------------- - sound/soc/jz4740/jz4740-pcm.h | 20 --- - 4 files changed, 27 insertions(+), 352 deletions(-) - delete mode 100644 sound/soc/jz4740/jz4740-pcm.h - ---- a/sound/soc/jz4740/Kconfig -+++ b/sound/soc/jz4740/Kconfig -@@ -1,6 +1,7 @@ - config SND_JZ4740_SOC - tristate "SoC Audio for Ingenic JZ4740 SoC" - depends on MACH_JZ4740 && SND_SOC -+ select SND_SOC_GENERIC_DMAENGINE_PCM - help - Say Y or M if you want to add support for codecs attached to - the JZ4740 I2S interface. You will also need to select the audio ---- a/sound/soc/jz4740/jz4740-i2s.c -+++ b/sound/soc/jz4740/jz4740-i2s.c -@@ -29,9 +29,12 @@ - #include <sound/pcm_params.h> - #include <sound/soc.h> - #include <sound/initval.h> -+#include <sound/dmaengine_pcm.h> -+ -+#include <asm/mach-jz4740/dma.h> - - #include "jz4740-i2s.h" --#include "jz4740-pcm.h" -+ - - #define JZ_REG_AIC_CONF 0x00 - #define JZ_REG_AIC_CTRL 0x04 -@@ -89,8 +92,8 @@ struct jz4740_i2s { - struct clk *clk_aic; - struct clk *clk_i2s; - -- struct jz4740_pcm_config pcm_config_playback; -- struct jz4740_pcm_config pcm_config_capture; -+ struct snd_dmaengine_dai_dma_data playback_dma_data; -+ struct snd_dmaengine_dai_dma_data capture_dma_data; - }; - - static inline uint32_t jz4740_i2s_read(const struct jz4740_i2s *i2s, -@@ -233,8 +236,6 @@ static int jz4740_i2s_hw_params(struct s - struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) - { - struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai); -- enum jz4740_dma_width dma_width; -- struct jz4740_pcm_config *pcm_config; - unsigned int sample_size; - uint32_t ctrl; - -@@ -243,11 +244,9 @@ static int jz4740_i2s_hw_params(struct s - switch (params_format(params)) { - case SNDRV_PCM_FORMAT_S8: - sample_size = 0; -- dma_width = JZ4740_DMA_WIDTH_8BIT; - break; - case SNDRV_PCM_FORMAT_S16: - sample_size = 1; -- dma_width = JZ4740_DMA_WIDTH_16BIT; - break; - default: - return -EINVAL; -@@ -260,22 +259,13 @@ static int jz4740_i2s_hw_params(struct s - ctrl |= JZ_AIC_CTRL_MONO_TO_STEREO; - else - ctrl &= ~JZ_AIC_CTRL_MONO_TO_STEREO; -- -- pcm_config = &i2s->pcm_config_playback; -- pcm_config->dma_config.dst_width = dma_width; -- - } else { - ctrl &= ~JZ_AIC_CTRL_INPUT_SAMPLE_SIZE_MASK; - ctrl |= sample_size << JZ_AIC_CTRL_INPUT_SAMPLE_SIZE_OFFSET; -- -- pcm_config = &i2s->pcm_config_capture; -- pcm_config->dma_config.src_width = dma_width; - } - - jz4740_i2s_write(i2s, JZ_REG_AIC_CTRL, ctrl); - -- snd_soc_dai_set_dma_data(dai, substream, pcm_config); -- - return 0; - } - -@@ -342,25 +332,19 @@ static int jz4740_i2s_resume(struct snd_ - - static void jz4740_i2c_init_pcm_config(struct jz4740_i2s *i2s) - { -- struct jz4740_dma_config *dma_config; -+ struct snd_dmaengine_dai_dma_data *dma_data; - - /* Playback */ -- dma_config = &i2s->pcm_config_playback.dma_config; -- dma_config->src_width = JZ4740_DMA_WIDTH_32BIT; -- dma_config->transfer_size = JZ4740_DMA_TRANSFER_SIZE_16BYTE; -- dma_config->request_type = JZ4740_DMA_TYPE_AIC_TRANSMIT; -- dma_config->flags = JZ4740_DMA_SRC_AUTOINC; -- dma_config->mode = JZ4740_DMA_MODE_SINGLE; -- i2s->pcm_config_playback.fifo_addr = i2s->phys_base + JZ_REG_AIC_FIFO; -+ dma_data = &i2s->playback_dma_data; -+ dma_data->maxburst = 16; -+ dma_data->slave_id = JZ4740_DMA_TYPE_AIC_TRANSMIT; -+ dma_data->addr = i2s->phys_base + JZ_REG_AIC_FIFO; - - /* Capture */ -- dma_config = &i2s->pcm_config_capture.dma_config; -- dma_config->dst_width = JZ4740_DMA_WIDTH_32BIT; -- dma_config->transfer_size = JZ4740_DMA_TRANSFER_SIZE_16BYTE; -- dma_config->request_type = JZ4740_DMA_TYPE_AIC_RECEIVE; -- dma_config->flags = JZ4740_DMA_DST_AUTOINC; -- dma_config->mode = JZ4740_DMA_MODE_SINGLE; -- i2s->pcm_config_capture.fifo_addr = i2s->phys_base + JZ_REG_AIC_FIFO; -+ dma_data = &i2s->capture_dma_data; -+ dma_data->maxburst = 16; -+ dma_data->slave_id = JZ4740_DMA_TYPE_AIC_RECEIVE; -+ dma_data->addr = i2s->phys_base + JZ_REG_AIC_FIFO; - } - - static int jz4740_i2s_dai_probe(struct snd_soc_dai *dai) -@@ -371,6 +355,8 @@ static int jz4740_i2s_dai_probe(struct s - clk_enable(i2s->clk_aic); - - jz4740_i2c_init_pcm_config(i2s); -+ dai->playback_dma_data = &i2s->playback_dma_data; -+ dai->capture_dma_data = &i2s->capture_dma_data; - - conf = (7 << JZ_AIC_CONF_FIFO_RX_THRESHOLD_OFFSET) | - (8 << JZ_AIC_CONF_FIFO_TX_THRESHOLD_OFFSET) | ---- a/sound/soc/jz4740/jz4740-pcm.c -+++ b/sound/soc/jz4740/jz4740-pcm.c -@@ -19,38 +19,14 @@ - #include <linux/platform_device.h> - #include <linux/slab.h> - --#include <linux/dma-mapping.h> -+#include <sound/dmaengine_pcm.h> - --#include <sound/core.h> --#include <sound/pcm.h> --#include <sound/pcm_params.h> --#include <sound/soc.h> -- --#include <asm/mach-jz4740/dma.h> --#include "jz4740-pcm.h" -- --struct jz4740_runtime_data { -- unsigned long dma_period; -- dma_addr_t dma_start; -- dma_addr_t dma_pos; -- dma_addr_t dma_end; -- -- struct jz4740_dma_chan *dma; -- -- dma_addr_t fifo_addr; --}; -- --/* identify hardware playback capabilities */ - static const struct snd_pcm_hardware jz4740_pcm_hardware = { - .info = SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_BLOCK_TRANSFER, - .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8, -- -- .rates = SNDRV_PCM_RATE_8000_48000, -- .channels_min = 1, -- .channels_max = 2, - .period_bytes_min = 16, - .period_bytes_max = 2 * PAGE_SIZE, - .periods_min = 2, -@@ -59,290 +35,22 @@ static const struct snd_pcm_hardware jz4 - .fifo_size = 32, - }; - --static void jz4740_pcm_start_transfer(struct jz4740_runtime_data *prtd, -- struct snd_pcm_substream *substream) --{ -- unsigned long count; -- -- if (prtd->dma_pos == prtd->dma_end) -- prtd->dma_pos = prtd->dma_start; -- -- if (prtd->dma_pos + prtd->dma_period > prtd->dma_end) -- count = prtd->dma_end - prtd->dma_pos; -- else -- count = prtd->dma_period; -- -- jz4740_dma_disable(prtd->dma); -- -- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { -- jz4740_dma_set_src_addr(prtd->dma, prtd->dma_pos); -- jz4740_dma_set_dst_addr(prtd->dma, prtd->fifo_addr); -- } else { -- jz4740_dma_set_src_addr(prtd->dma, prtd->fifo_addr); -- jz4740_dma_set_dst_addr(prtd->dma, prtd->dma_pos); -- } -- -- jz4740_dma_set_transfer_count(prtd->dma, count); -- -- prtd->dma_pos += count; -- -- jz4740_dma_enable(prtd->dma); --} -- --static void jz4740_pcm_dma_transfer_done(struct jz4740_dma_chan *dma, int err, -- void *dev_id) --{ -- struct snd_pcm_substream *substream = dev_id; -- struct snd_pcm_runtime *runtime = substream->runtime; -- struct jz4740_runtime_data *prtd = runtime->private_data; -- -- snd_pcm_period_elapsed(substream); -- -- jz4740_pcm_start_transfer(prtd, substream); --} -- --static int jz4740_pcm_hw_params(struct snd_pcm_substream *substream, -- struct snd_pcm_hw_params *params) --{ -- struct snd_pcm_runtime *runtime = substream->runtime; -- struct jz4740_runtime_data *prtd = runtime->private_data; -- struct snd_soc_pcm_runtime *rtd = substream->private_data; -- struct jz4740_pcm_config *config; -- -- config = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); -- -- if (!config) -- return 0; -- -- if (!prtd->dma) { -- if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) -- prtd->dma = jz4740_dma_request(substream, "PCM Capture"); -- else -- prtd->dma = jz4740_dma_request(substream, "PCM Playback"); -- } -- -- if (!prtd->dma) -- return -EBUSY; -- -- jz4740_dma_configure(prtd->dma, &config->dma_config); -- prtd->fifo_addr = config->fifo_addr; -- -- jz4740_dma_set_complete_cb(prtd->dma, jz4740_pcm_dma_transfer_done); -- -- snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); -- runtime->dma_bytes = params_buffer_bytes(params); -- -- prtd->dma_period = params_period_bytes(params); -- prtd->dma_start = runtime->dma_addr; -- prtd->dma_pos = prtd->dma_start; -- prtd->dma_end = prtd->dma_start + runtime->dma_bytes; -- -- return 0; --} -- --static int jz4740_pcm_hw_free(struct snd_pcm_substream *substream) --{ -- struct jz4740_runtime_data *prtd = substream->runtime->private_data; -- -- snd_pcm_set_runtime_buffer(substream, NULL); -- if (prtd->dma) { -- jz4740_dma_free(prtd->dma); -- prtd->dma = NULL; -- } -- -- return 0; --} -- --static int jz4740_pcm_prepare(struct snd_pcm_substream *substream) --{ -- struct jz4740_runtime_data *prtd = substream->runtime->private_data; -- -- if (!prtd->dma) -- return -EBUSY; -- -- prtd->dma_pos = prtd->dma_start; -- -- return 0; --} -- --static int jz4740_pcm_trigger(struct snd_pcm_substream *substream, int cmd) --{ -- struct snd_pcm_runtime *runtime = substream->runtime; -- struct jz4740_runtime_data *prtd = runtime->private_data; -- -- switch (cmd) { -- case SNDRV_PCM_TRIGGER_START: -- case SNDRV_PCM_TRIGGER_RESUME: -- case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: -- jz4740_pcm_start_transfer(prtd, substream); -- break; -- case SNDRV_PCM_TRIGGER_STOP: -- case SNDRV_PCM_TRIGGER_SUSPEND: -- case SNDRV_PCM_TRIGGER_PAUSE_PUSH: -- jz4740_dma_disable(prtd->dma); -- break; -- default: -- break; -- } -- -- return 0; --} -- --static snd_pcm_uframes_t jz4740_pcm_pointer(struct snd_pcm_substream *substream) --{ -- struct snd_pcm_runtime *runtime = substream->runtime; -- struct jz4740_runtime_data *prtd = runtime->private_data; -- unsigned long byte_offset; -- snd_pcm_uframes_t offset; -- struct jz4740_dma_chan *dma = prtd->dma; -- -- /* prtd->dma_pos points to the end of the current transfer. So by -- * subtracting prdt->dma_start we get the offset to the end of the -- * current period in bytes. By subtracting the residue of the transfer -- * we get the current offset in bytes. */ -- byte_offset = prtd->dma_pos - prtd->dma_start; -- byte_offset -= jz4740_dma_get_residue(dma); -- -- offset = bytes_to_frames(runtime, byte_offset); -- if (offset >= runtime->buffer_size) -- offset = 0; -- -- return offset; --} -- --static int jz4740_pcm_open(struct snd_pcm_substream *substream) --{ -- struct snd_pcm_runtime *runtime = substream->runtime; -- struct jz4740_runtime_data *prtd; -- -- prtd = kzalloc(sizeof(*prtd), GFP_KERNEL); -- if (prtd == NULL) -- return -ENOMEM; -- -- snd_soc_set_runtime_hwparams(substream, &jz4740_pcm_hardware); -- -- runtime->private_data = prtd; -- -- return 0; --} -- --static int jz4740_pcm_close(struct snd_pcm_substream *substream) --{ -- struct snd_pcm_runtime *runtime = substream->runtime; -- struct jz4740_runtime_data *prtd = runtime->private_data; -- -- kfree(prtd); -- -- return 0; --} -- --static int jz4740_pcm_mmap(struct snd_pcm_substream *substream, -- struct vm_area_struct *vma) --{ -- return remap_pfn_range(vma, vma->vm_start, -- substream->dma_buffer.addr >> PAGE_SHIFT, -- vma->vm_end - vma->vm_start, vma->vm_page_prot); --} -- --static struct snd_pcm_ops jz4740_pcm_ops = { -- .open = jz4740_pcm_open, -- .close = jz4740_pcm_close, -- .ioctl = snd_pcm_lib_ioctl, -- .hw_params = jz4740_pcm_hw_params, -- .hw_free = jz4740_pcm_hw_free, -- .prepare = jz4740_pcm_prepare, -- .trigger = jz4740_pcm_trigger, -- .pointer = jz4740_pcm_pointer, -- .mmap = jz4740_pcm_mmap, --}; -- --static int jz4740_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) --{ -- struct snd_pcm_substream *substream = pcm->streams[stream].substream; -- struct snd_dma_buffer *buf = &substream->dma_buffer; -- size_t size = jz4740_pcm_hardware.buffer_bytes_max; -- -- buf->dev.type = SNDRV_DMA_TYPE_DEV; -- buf->dev.dev = pcm->card->dev; -- buf->private_data = NULL; -- -- buf->area = dma_alloc_noncoherent(pcm->card->dev, size, -- &buf->addr, GFP_KERNEL); -- if (!buf->area) -- return -ENOMEM; -- -- buf->bytes = size; -- -- return 0; --} -- --static void jz4740_pcm_free(struct snd_pcm *pcm) --{ -- struct snd_pcm_substream *substream; -- struct snd_dma_buffer *buf; -- int stream; -- -- for (stream = 0; stream < SNDRV_PCM_STREAM_LAST; ++stream) { -- substream = pcm->streams[stream].substream; -- if (!substream) -- continue; -- -- buf = &substream->dma_buffer; -- if (!buf->area) -- continue; -- -- dma_free_noncoherent(pcm->card->dev, buf->bytes, buf->area, -- buf->addr); -- buf->area = NULL; -- } --} -- --static u64 jz4740_pcm_dmamask = DMA_BIT_MASK(32); -- --static int jz4740_pcm_new(struct snd_soc_pcm_runtime *rtd) --{ -- struct snd_card *card = rtd->card->snd_card; -- struct snd_pcm *pcm = rtd->pcm; -- int ret = 0; -- -- if (!card->dev->dma_mask) -- card->dev->dma_mask = &jz4740_pcm_dmamask; -- -- if (!card->dev->coherent_dma_mask) -- card->dev->coherent_dma_mask = DMA_BIT_MASK(32); -- -- if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) { -- ret = jz4740_pcm_preallocate_dma_buffer(pcm, -- SNDRV_PCM_STREAM_PLAYBACK); -- if (ret) -- goto err; -- } -- -- if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) { -- ret = jz4740_pcm_preallocate_dma_buffer(pcm, -- SNDRV_PCM_STREAM_CAPTURE); -- if (ret) -- goto err; -- } -- --err: -- return ret; --} -- --static struct snd_soc_platform_driver jz4740_soc_platform = { -- .ops = &jz4740_pcm_ops, -- .pcm_new = jz4740_pcm_new, -- .pcm_free = jz4740_pcm_free, -+static const struct snd_dmaengine_pcm_config jz4740_dmaengine_pcm_config = { -+ .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config, -+ .pcm_hardware = &jz4740_pcm_hardware, -+ .prealloc_buffer_size = 256 * PAGE_SIZE, - }; - - static int jz4740_pcm_probe(struct platform_device *pdev) - { -- return snd_soc_register_platform(&pdev->dev, &jz4740_soc_platform); -+ return snd_dmaengine_pcm_register(&pdev->dev, -+ &jz4740_dmaengine_pcm_config, -+ SND_DMAENGINE_PCM_FLAG_COMPAT); - } - - static int jz4740_pcm_remove(struct platform_device *pdev) - { -- snd_soc_unregister_platform(&pdev->dev); -+ snd_dmaengine_pcm_unregister(&pdev->dev); - return 0; - } - ---- a/sound/soc/jz4740/jz4740-pcm.h -+++ /dev/null -@@ -1,20 +0,0 @@ --/* -- * -- * 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. -- */ -- --#ifndef _JZ4740_PCM_H --#define _JZ4740_PCM_H -- --#include <linux/dma-mapping.h> --#include <asm/mach-jz4740/dma.h> -- -- --struct jz4740_pcm_config { -- struct jz4740_dma_config dma_config; -- phys_addr_t fifo_addr; --}; -- --#endif |