Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/patches/808780/?format=api
{ "id": 808780, "url": "http://patchwork.ozlabs.org/api/patches/808780/?format=api", "web_url": "http://patchwork.ozlabs.org/project/openbmc/patch/1504281966-6199-3-git-send-email-oleksandrs@mellanox.com/", "project": { "id": 56, "url": "http://patchwork.ozlabs.org/api/projects/56/?format=api", "name": "OpenBMC development", "link_name": "openbmc", "list_id": "openbmc.lists.ozlabs.org", "list_email": "openbmc@lists.ozlabs.org", "web_url": "http://github.com/openbmc/", "scm_url": "", "webscm_url": "", "list_archive_url": "", "list_archive_url_format": "", "commit_url_format": "" }, "msgid": "<1504281966-6199-3-git-send-email-oleksandrs@mellanox.com>", "list_archive_url": null, "date": "2017-09-01T16:06:04", "name": "[v7,2/4] drivers: jtag: Add Aspeed SoC 24xx and 25xx families JTAG master driver", "commit_ref": null, "pull_url": null, "state": "not-applicable", "archived": true, "hash": "068f79e1cba4b371cdc9159b269db98778c5c5ec", "submitter": { "id": 72099, "url": "http://patchwork.ozlabs.org/api/people/72099/?format=api", "name": "Oleksandr Shamray", "email": "oleksandrs@mellanox.com" }, "delegate": null, "mbox": "http://patchwork.ozlabs.org/project/openbmc/patch/1504281966-6199-3-git-send-email-oleksandrs@mellanox.com/mbox/", "series": [ { "id": 1060, "url": "http://patchwork.ozlabs.org/api/series/1060/?format=api", "web_url": "http://patchwork.ozlabs.org/project/openbmc/list/?series=1060", "date": "2017-09-01T16:06:02", "name": "JTAG driver introduction", "version": 7, "mbox": "http://patchwork.ozlabs.org/series/1060/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/808780/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/808780/checks/", "tags": {}, "related": [], "headers": { "Return-Path": "<openbmc-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org>", "X-Original-To": [ "incoming@patchwork.ozlabs.org", "openbmc@lists.ozlabs.org" ], "Delivered-To": [ "patchwork-incoming@bilbo.ozlabs.org", "openbmc@lists.ozlabs.org" ], "Received": [ "from lists.ozlabs.org (lists.ozlabs.org [103.22.144.68])\n\t(using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits))\n\t(No client certificate requested)\n\tby ozlabs.org (Postfix) with ESMTPS id 3xkPK33Zg3z9t3P\n\tfor <incoming@patchwork.ozlabs.org>;\n\tSat, 2 Sep 2017 02:07:35 +1000 (AEST)", "from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3])\n\tby lists.ozlabs.org (Postfix) with ESMTP id 3xkPK30pwwzDqjk\n\tfor <incoming@patchwork.ozlabs.org>;\n\tSat, 2 Sep 2017 02:07:35 +1000 (AEST)", "from mellanox.co.il (mail-il-dmz.mellanox.com [193.47.165.129])\n\tby lists.ozlabs.org (Postfix) with ESMTP id 3xkPHv4FsmzDqfx\n\tfor <openbmc@lists.ozlabs.org>; Sat, 2 Sep 2017 02:06:34 +1000 (AEST)", "from Internal Mail-Server by MTLPINE1 (envelope-from\n\toleksandrs@mellanox.com)\n\twith ESMTPS (AES256-SHA encrypted); 1 Sep 2017 19:06:26 +0300", "from r-vnc16.mtr.labs.mlnx (r-vnc16.mtr.labs.mlnx [10.208.0.16])\n\tby labmailer.mlnx (8.13.8/8.13.8) with ESMTP id v81G6P6Q002351;\n\tFri, 1 Sep 2017 19:06:26 +0300" ], "From": "Oleksandr Shamray <oleksandrs@mellanox.com>", "To": "gregkh@linuxfoundation.org, arnd@arndb.de", "Subject": "[patch v7 2/4] drivers: jtag: Add Aspeed SoC 24xx and 25xx families\n\tJTAG master driver", "Date": "Fri, 1 Sep 2017 19:06:04 +0300", "Message-Id": "<1504281966-6199-3-git-send-email-oleksandrs@mellanox.com>", "X-Mailer": "git-send-email 1.7.1", "In-Reply-To": "<1504281966-6199-1-git-send-email-oleksandrs@mellanox.com>", "References": "<1504281966-6199-1-git-send-email-oleksandrs@mellanox.com>", "X-BeenThere": "openbmc@lists.ozlabs.org", "X-Mailman-Version": "2.1.23", "Precedence": "list", "List-Id": "Development list for OpenBMC <openbmc.lists.ozlabs.org>", "List-Unsubscribe": "<https://lists.ozlabs.org/options/openbmc>,\n\t<mailto:openbmc-request@lists.ozlabs.org?subject=unsubscribe>", "List-Archive": "<http://lists.ozlabs.org/pipermail/openbmc/>", "List-Post": "<mailto:openbmc@lists.ozlabs.org>", "List-Help": "<mailto:openbmc-request@lists.ozlabs.org?subject=help>", "List-Subscribe": "<https://lists.ozlabs.org/listinfo/openbmc>,\n\t<mailto:openbmc-request@lists.ozlabs.org?subject=subscribe>", "Cc": "devicetree@vger.kernel.org, jiri@resnulli.us,\n\tsystem-sw-low-level@mellanox.com, linux-api@vger.kernel.org,\n\topenbmc@lists.ozlabs.org, linux-kernel@vger.kernel.org,\n\topenocd-devel-owner@lists.sourceforge.net, mec@shout.net,\n\tJiri Pirko <jiri@mellanox.com>, robh+dt@kernel.org,\n\tlinux-serial@vger.kernel.org, vadimp@maellanox.com,\n\tOleksandr Shamray <oleksandrs@mellanox.com>, tklauser@distanz.ch,\n\tmchehab@kernel.org, davem@davemloft.net,\n\tlinux-arm-kernel@lists.infradead.org", "Errors-To": "openbmc-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org", "Sender": "\"openbmc\"\n\t<openbmc-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org>" }, "content": "Driver adds support of Aspeed 2500/2400 series SOC JTAG master controller.\n\nDriver implements the following jtag ops:\n- freq_get;\n- freq_set;\n- status_get;\n- idle;\n- xfer;\n\nIt has been tested on Mellanox system with BMC equipped with\nAspeed 2520 SoC for programming CPLD devices.\n\nSigned-off-by: Oleksandr Shamray <oleksandrs@mellanox.com>\nSigned-off-by: Jiri Pirko <jiri@mellanox.com>\n---\nv6->v7\nNotifications from kbuild test robot <lkp@intel.com>\n- Add include <linux/types.h> to jtag-asapeed.c\n\nv5->v6\nv4->v5\nComments pointed by Arnd Bergmann <arnd@arndb.de>\n- Added HAS_IOMEM dependence in Kconfig to avoid\n \"undefined reference to `devm_ioremap_resource'\" error,\n because in some arch this not supported\n\nv3->v4\nComments pointed by Arnd Bergmann <arnd@arndb.de>\n- change transaction pointer tdio type to __u64\n- change internal status type from enum to __u32\n\nv2->v3\n\nv1->v2\nComments pointed by Greg KH <gregkh@linuxfoundation.org>\n- change license type from GPLv2/BSD to GPLv2\n\nComments pointed by Neil Armstrong <narmstrong@baylibre.com>\n- Add clk_prepare_enable/clk_disable_unprepare in clock init/deinit\n- Change .compatible to soc-specific compatible names\n aspeed,aspeed4000-jtag/aspeed5000-jtag\n- Added dt-bindings\n\nComments pointed by Arnd Bergmann <arnd@arndb.de>\n- Reorder functions and removed the forward declarations\n- Add static const qualifier to state machine states transitions\n- Change .compatible to soc-specific compatible names\n aspeed,aspeed4000-jtag/aspeed5000-jtag\n- Add dt-bindings\n\nComments pointed by Randy Dunlap <rdunlap@infradead.org>\n- Change module name jtag-aspeed in description in Kconfig\n\nComments pointed by kbuild test robot <lkp@intel.com>\n- Remove invalid include <asm/mach-types.h>\n- add resource_size instead of calculation\n---\n drivers/jtag/Kconfig | 13 +\n drivers/jtag/Makefile | 1 +\n drivers/jtag/jtag-aspeed.c | 773 ++++++++++++++++++++++++++++++++++++++++++++\n 3 files changed, 787 insertions(+), 0 deletions(-)\n create mode 100644 drivers/jtag/jtag-aspeed.c", "diff": "diff --git a/drivers/jtag/Kconfig b/drivers/jtag/Kconfig\nindex 0fad1a3..098beb0 100644\n--- a/drivers/jtag/Kconfig\n+++ b/drivers/jtag/Kconfig\n@@ -14,3 +14,16 @@ menuconfig JTAG\n \n \t To compile this driver as a module, choose M here: the module will\n \t be called jtag.\n+\n+menuconfig JTAG_ASPEED\n+\ttristate \"Aspeed SoC JTAG controller support\"\n+\tdepends on JTAG && HAS_IOMEM\n+\t---help---\n+\t This provides a support for Aspeed JTAG device, equipped on\n+\t Aspeed SoC 24xx and 25xx families. Drivers allows programming\n+\t of hardware devices, connected to SoC through the JTAG interface.\n+\n+\t If you want this support, you should say Y here.\n+\n+\t To compile this driver as a module, choose M here: the module will\n+\t be called jtag-aspeed.\ndiff --git a/drivers/jtag/Makefile b/drivers/jtag/Makefile\nindex af37493..04a855e 100644\n--- a/drivers/jtag/Makefile\n+++ b/drivers/jtag/Makefile\n@@ -1 +1,2 @@\n obj-$(CONFIG_JTAG)\t\t+= jtag.o\n+obj-$(CONFIG_JTAG_ASPEED)\t+= jtag-aspeed.o\ndiff --git a/drivers/jtag/jtag-aspeed.c b/drivers/jtag/jtag-aspeed.c\nnew file mode 100644\nindex 0000000..017d96e\n--- /dev/null\n+++ b/drivers/jtag/jtag-aspeed.c\n@@ -0,0 +1,773 @@\n+/*\n+ * drivers/jtag/jtag.c\n+ *\n+ * Copyright (c) 2017 Mellanox Technologies. All rights reserved.\n+ * Copyright (c) 2017 Oleksandr Shamray <oleksandrs@mellanox.com>\n+ *\n+ * Released under the GPLv2 only.\n+ * SPDX-License-Identifier: GPL-2.0\n+ */\n+\n+#include <linux/clk.h>\n+#include <linux/device.h>\n+#include <linux/interrupt.h>\n+#include <linux/jtag.h>\n+#include <linux/kernel.h>\n+#include <linux/module.h>\n+#include <linux/of_address.h>\n+#include <linux/platform_device.h>\n+#include <linux/slab.h>\n+#include <linux/types.h>\n+#include <uapi/linux/jtag.h>\n+\n+#define ASPEED_JTAG_DATA\t\t0x00\n+#define ASPEED_JTAG_INST\t\t0x04\n+#define ASPEED_JTAG_CTRL\t\t0x08\n+#define ASPEED_JTAG_ISR\t\t\t0x0C\n+#define ASPEED_JTAG_SW\t\t\t0x10\n+#define ASPEED_JTAG_TCK\t\t\t0x14\n+#define ASPEED_JTAG_EC\t\t\t0x18\n+\n+#define ASPEED_JTAG_DATA_MSB\t\t0x01\n+#define ASPEED_JTAG_DATA_CHUNK_SIZE\t0x20\n+\n+/* ASPEED_JTAG_CTRL: Engine Control */\n+#define ASPEED_JTAG_CTL_ENG_EN\t\tBIT(31)\n+#define ASPEED_JTAG_CTL_ENG_OUT_EN\tBIT(30)\n+#define ASPEED_JTAG_CTL_FORCE_TMS\tBIT(29)\n+#define ASPEED_JTAG_CTL_INST_LEN(x)\t((x) << 20)\n+#define ASPEED_JTAG_CTL_LASPEED_INST\tBIT(17)\n+#define ASPEED_JTAG_CTL_INST_EN\t\tBIT(16)\n+#define ASPEED_JTAG_CTL_DR_UPDATE\tBIT(10)\n+#define ASPEED_JTAG_CTL_DATA_LEN(x)\t((x) << 4)\n+#define ASPEED_JTAG_CTL_LASPEED_DATA\tBIT(1)\n+#define ASPEED_JTAG_CTL_DATA_EN\t\tBIT(0)\n+\n+/* ASPEED_JTAG_ISR : Interrupt status and enable */\n+#define ASPEED_JTAG_ISR_INST_PAUSE\tBIT(19)\n+#define ASPEED_JTAG_ISR_INST_COMPLETE\tBIT(18)\n+#define ASPEED_JTAG_ISR_DATA_PAUSE\tBIT(17)\n+#define ASPEED_JTAG_ISR_DATA_COMPLETE\tBIT(16)\n+#define ASPEED_JTAG_ISR_INST_PAUSE_EN\tBIT(3)\n+#define ASPEED_JTAG_ISR_INST_COMPLETE_EN BIT(2)\n+#define ASPEED_JTAG_ISR_DATA_PAUSE_EN\tBIT(1)\n+#define ASPEED_JTAG_ISR_DATA_COMPLETE_EN BIT(0)\n+#define ASPEED_JTAG_ISR_INT_EN_MASK\tGENMASK(3, 0)\n+#define ASPEED_JTAG_ISR_INT_MASK\tGENMASK(19, 16)\n+\n+/* ASPEED_JTAG_SW : Software Mode and Status */\n+#define ASPEED_JTAG_SW_MODE_EN\t\tBIT(19)\n+#define ASPEED_JTAG_SW_MODE_TCK\t\tBIT(18)\n+#define ASPEED_JTAG_SW_MODE_TMS\t\tBIT(17)\n+#define ASPEED_JTAG_SW_MODE_TDIO\tBIT(16)\n+\n+/* ASPEED_JTAG_TCK : TCK Control */\n+#define ASPEED_JTAG_TCK_DIVISOR_MASK\tGENMASK(10, 0)\n+#define ASPEED_JTAG_TCK_GET_DIV(x)\t((x) & ASPEED_JTAG_TCK_DIVISOR_MASK)\n+\n+/* ASPEED_JTAG_EC : Controller set for go to IDLE */\n+#define ASPEED_JTAG_EC_GO_IDLE\t\tBIT(0)\n+\n+#define ASPEED_JTAG_IOUT_LEN(len)\t(ASPEED_JTAG_CTL_ENG_EN |\\\n+\t\t\t\t\t ASPEED_JTAG_CTL_ENG_OUT_EN |\\\n+\t\t\t\t\t ASPEED_JTAG_CTL_INST_LEN(len))\n+\n+#define ASPEED_JTAG_DOUT_LEN(len)\t(ASPEED_JTAG_CTL_ENG_EN |\\\n+\t\t\t\t\t ASPEED_JTAG_CTL_ENG_OUT_EN |\\\n+\t\t\t\t\t ASPEED_JTAG_CTL_DATA_LEN(len))\n+\n+#define ASPEED_JTAG_TCK_WAIT\t\t10\n+#define ASPEED_JTAG_RESET_CNTR\t\t10\n+\n+#define ASPEED_JTAG_NAME\t\t\"jtag-aspeed\"\n+\n+struct aspeed_jtag {\n+\tvoid __iomem\t\t\t*reg_base;\n+\tstruct device\t\t\t*dev;\n+\tstruct clk\t\t\t*pclk;\n+\tenum jtag_endstate\t\tstatus;\n+\tint\t\t\t\tirq;\n+\tu32\t\t\t\tflag;\n+\twait_queue_head_t\t\tjtag_wq;\n+\tbool\t\t\t\tis_open;\n+};\n+\n+static char *end_status_str[] = {\"idle\", \"ir pause\", \"drpause\"};\n+\n+static u32 aspeed_jtag_read(struct aspeed_jtag *aspeed_jtag, u32 reg)\n+{\n+\treturn readl(aspeed_jtag->reg_base + reg);\n+}\n+\n+static void\n+aspeed_jtag_write(struct aspeed_jtag *aspeed_jtag, u32 val, u32 reg)\n+{\n+\twritel(val, aspeed_jtag->reg_base + reg);\n+}\n+\n+static int aspeed_jtag_freq_set(struct jtag *jtag, __u32 freq)\n+{\n+\tstruct aspeed_jtag *aspeed_jtag = jtag_priv(jtag);\n+\tunsigned long apb_frq;\n+\tu32 tck_val;\n+\tu16 div;\n+\n+\tapb_frq = clk_get_rate(aspeed_jtag->pclk);\n+\tdiv = (apb_frq % freq == 0) ? (apb_frq / freq) - 1 : (apb_frq / freq);\n+\ttck_val = aspeed_jtag_read(aspeed_jtag, ASPEED_JTAG_TCK);\n+\taspeed_jtag_write(aspeed_jtag,\n+\t\t\t (tck_val & ASPEED_JTAG_TCK_DIVISOR_MASK) | div,\n+\t\t\t ASPEED_JTAG_TCK);\n+\treturn 0;\n+}\n+\n+static int aspeed_jtag_freq_get(struct jtag *jtag, __u32 *frq)\n+{\n+\tstruct aspeed_jtag *aspeed_jtag = jtag_priv(jtag);\n+\tu32 pclk;\n+\tu32 tck;\n+\n+\tpclk = clk_get_rate(aspeed_jtag->pclk);\n+\ttck = aspeed_jtag_read(aspeed_jtag, ASPEED_JTAG_TCK);\n+\t*frq = pclk / (ASPEED_JTAG_TCK_GET_DIV(tck) + 1);\n+\n+\treturn 0;\n+}\n+\n+static void aspeed_jtag_sw_delay(struct aspeed_jtag *aspeed_jtag, int cnt)\n+{\n+\tint i;\n+\n+\tfor (i = 0; i < cnt; i++)\n+\t\taspeed_jtag_read(aspeed_jtag, ASPEED_JTAG_SW);\n+}\n+\n+static char aspeed_jtag_tck_cycle(struct aspeed_jtag *aspeed_jtag,\n+\t\t\t\t u8 tms, u8 tdi)\n+{\n+\tchar tdo = 0;\n+\n+\t/* TCK = 0 */\n+\taspeed_jtag_write(aspeed_jtag, ASPEED_JTAG_SW_MODE_EN |\n+\t\t\t (tms * ASPEED_JTAG_SW_MODE_TMS) |\n+\t\t\t (tdi * ASPEED_JTAG_SW_MODE_TDIO), ASPEED_JTAG_SW);\n+\n+\taspeed_jtag_sw_delay(aspeed_jtag, ASPEED_JTAG_TCK_WAIT);\n+\n+\t/* TCK = 1 */\n+\taspeed_jtag_write(aspeed_jtag, ASPEED_JTAG_SW_MODE_EN |\n+\t\t\t ASPEED_JTAG_SW_MODE_TCK |\n+\t\t\t (tms * ASPEED_JTAG_SW_MODE_TMS) |\n+\t\t\t (tdi * ASPEED_JTAG_SW_MODE_TDIO), ASPEED_JTAG_SW);\n+\n+\tif (aspeed_jtag_read(aspeed_jtag, ASPEED_JTAG_SW) &\n+\t ASPEED_JTAG_SW_MODE_TDIO)\n+\t\ttdo = 1;\n+\n+\taspeed_jtag_sw_delay(aspeed_jtag, ASPEED_JTAG_TCK_WAIT);\n+\n+\t/* TCK = 0 */\n+\taspeed_jtag_write(aspeed_jtag, ASPEED_JTAG_SW_MODE_EN |\n+\t\t\t (tms * ASPEED_JTAG_SW_MODE_TMS) |\n+\t\t\t (tdi * ASPEED_JTAG_SW_MODE_TDIO), ASPEED_JTAG_SW);\n+\treturn tdo;\n+}\n+\n+static void aspeed_jtag_wait_instruction_pause(struct aspeed_jtag *aspeed_jtag)\n+{\n+\twait_event_interruptible(aspeed_jtag->jtag_wq, aspeed_jtag->flag &\n+\t\t\t\t ASPEED_JTAG_ISR_INST_PAUSE);\n+\taspeed_jtag->flag &= ~ASPEED_JTAG_ISR_INST_PAUSE;\n+}\n+\n+static void\n+aspeed_jtag_wait_instruction_complete(struct aspeed_jtag *aspeed_jtag)\n+{\n+\twait_event_interruptible(aspeed_jtag->jtag_wq, aspeed_jtag->flag &\n+\t\t\t\t ASPEED_JTAG_ISR_INST_COMPLETE);\n+\taspeed_jtag->flag &= ~ASPEED_JTAG_ISR_INST_COMPLETE;\n+}\n+\n+static void\n+aspeed_jtag_wait_data_pause_complete(struct aspeed_jtag *aspeed_jtag)\n+{\n+\twait_event_interruptible(aspeed_jtag->jtag_wq, aspeed_jtag->flag &\n+\t\t\t\t ASPEED_JTAG_ISR_DATA_PAUSE);\n+\taspeed_jtag->flag &= ~ASPEED_JTAG_ISR_DATA_PAUSE;\n+}\n+\n+static void aspeed_jtag_wait_data_complete(struct aspeed_jtag *aspeed_jtag)\n+{\n+\twait_event_interruptible(aspeed_jtag->jtag_wq, aspeed_jtag->flag &\n+\t\t\t\t ASPEED_JTAG_ISR_DATA_COMPLETE);\n+\taspeed_jtag->flag &= ~ASPEED_JTAG_ISR_DATA_COMPLETE;\n+}\n+\n+static void aspeed_jtag_sm_cycle(struct aspeed_jtag *aspeed_jtag, const u8 *tms,\n+\t\t\t\t int len)\n+{\n+\tint i;\n+\n+\tfor (i = 0; i < len; i++)\n+\t\taspeed_jtag_tck_cycle(aspeed_jtag, tms[i], 0);\n+}\n+\n+static void aspeed_jtag_run_test_idle_sw(struct aspeed_jtag *aspeed_jtag,\n+\t\t\t\t\t struct jtag_run_test_idle *runtest)\n+{\n+\tstatic const char sm_pause_irpause[] = {1, 1, 1, 1, 0, 1, 0};\n+\tstatic const char sm_pause_drpause[] = {1, 1, 1, 0, 1, 0};\n+\tstatic const char sm_idle_irpause[] = {1, 1, 0, 1, 0};\n+\tstatic const char sm_idle_drpause[] = {1, 0, 1, 0};\n+\tstatic const char sm_pause_idle[] = {1, 1, 0};\n+\tint i;\n+\n+\t/* SW mode from idle/pause-> to pause/idle */\n+\tif (runtest->reset) {\n+\t\tfor (i = 0; i < ASPEED_JTAG_RESET_CNTR; i++)\n+\t\t\taspeed_jtag_tck_cycle(aspeed_jtag, 1, 0);\n+\t}\n+\n+\tswitch (aspeed_jtag->status) {\n+\tcase JTAG_STATE_IDLE:\n+\t\tswitch (runtest->endstate) {\n+\t\tcase JTAG_STATE_PAUSEIR:\n+\t\t\t/* ->DRSCan->IRSCan->IRCap->IRExit1->PauseIR */\n+\t\t\taspeed_jtag_sm_cycle(aspeed_jtag, sm_idle_irpause,\n+\t\t\t\t\t sizeof(sm_idle_irpause));\n+\n+\t\t\taspeed_jtag->status = JTAG_STATE_PAUSEIR;\n+\t\t\tbreak;\n+\t\tcase JTAG_STATE_PAUSEDR:\n+\t\t\t/* ->DRSCan->DRCap->DRExit1->PauseDR */\n+\t\t\taspeed_jtag_sm_cycle(aspeed_jtag, sm_idle_drpause,\n+\t\t\t\t\t sizeof(sm_idle_drpause));\n+\n+\t\t\taspeed_jtag->status = JTAG_STATE_PAUSEDR;\n+\t\t\tbreak;\n+\t\tcase JTAG_STATE_IDLE:\n+\t\t\t/* IDLE */\n+\t\t\taspeed_jtag_tck_cycle(aspeed_jtag, 0, 0);\n+\t\t\taspeed_jtag->status = JTAG_STATE_IDLE;\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\tbreak;\n+\t\t}\n+\t\tbreak;\n+\n+\tcase JTAG_STATE_PAUSEIR:\n+\t/* Fall-through */\n+\tcase JTAG_STATE_PAUSEDR:\n+\t\t/* From IR/DR Pause */\n+\t\tswitch (runtest->endstate) {\n+\t\tcase JTAG_STATE_PAUSEIR:\n+\t\t\t/*\n+\t\t\t * to Exit2 IR/DR->Updt IR/DR->DRSCan->IRSCan->IRCap->\n+\t\t\t * IRExit1->PauseIR\n+\t\t\t */\n+\t\t\taspeed_jtag_sm_cycle(aspeed_jtag, sm_pause_irpause,\n+\t\t\t\t\t sizeof(sm_pause_irpause));\n+\n+\t\t\taspeed_jtag->status = JTAG_STATE_PAUSEIR;\n+\t\t\tbreak;\n+\t\tcase JTAG_STATE_PAUSEDR:\n+\t\t\t/*\n+\t\t\t * to Exit2 IR/DR->Updt IR/DR->DRSCan->DRCap->\n+\t\t\t * DRExit1->PauseDR\n+\t\t\t */\n+\t\t\taspeed_jtag_sm_cycle(aspeed_jtag, sm_pause_drpause,\n+\t\t\t\t\t sizeof(sm_pause_drpause));\n+\t\t\taspeed_jtag->status = JTAG_STATE_PAUSEDR;\n+\t\t\tbreak;\n+\t\tcase JTAG_STATE_IDLE:\n+\t\t\t/* to Exit2 IR/DR->Updt IR/DR->IDLE */\n+\t\t\taspeed_jtag_sm_cycle(aspeed_jtag, sm_pause_idle,\n+\t\t\t\t\t sizeof(sm_pause_idle));\n+\t\t\taspeed_jtag->status = JTAG_STATE_IDLE;\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\tbreak;\n+\t\t}\n+\t\tbreak;\n+\n+\tdefault:\n+\t\tdev_err(aspeed_jtag->dev, \"aspeed_jtag_run_test_idle error\\n\");\n+\t\tbreak;\n+\t}\n+\n+\t/* Stay on IDLE for at least TCK cycle */\n+\tfor (i = 0; i < runtest->tck; i++)\n+\t\taspeed_jtag_tck_cycle(aspeed_jtag, 0, 0);\n+}\n+\n+/**\n+ * aspeed_jtag_run_test_idle:\n+ * JTAG reset: generates at least 9 TMS high and 1 TMS low to force\n+ * devices into Run-Test/Idle State.\n+ */\n+static int aspeed_jtag_idle(struct jtag *jtag,\n+\t\t\t struct jtag_run_test_idle *runtest)\n+{\n+\tstruct aspeed_jtag *aspeed_jtag = jtag_priv(jtag);\n+\n+\tdev_dbg(aspeed_jtag->dev, \"aspeed_jtag runtest, status:%d, mode:%s, state:%s, reset:%d, tck:%d\\n\",\n+\t\taspeed_jtag->status, runtest->mode ? \"SW\" : \"HW\",\n+\t\tend_status_str[runtest->endstate], runtest->reset,\n+\t\truntest->tck);\n+\n+\tif (runtest->mode) {\n+\t\taspeed_jtag_run_test_idle_sw(aspeed_jtag, runtest);\n+\t\treturn 0;\n+\t}\n+\n+\t/* Disable sw mode */\n+\taspeed_jtag_write(aspeed_jtag, 0, ASPEED_JTAG_SW);\n+\t/* x TMS high + 1 TMS low */\n+\tif (runtest->reset)\n+\t\taspeed_jtag_write(aspeed_jtag, ASPEED_JTAG_CTL_ENG_EN |\n+\t\t\t\t ASPEED_JTAG_CTL_ENG_OUT_EN |\n+\t\t\t\t ASPEED_JTAG_CTL_FORCE_TMS, ASPEED_JTAG_CTRL);\n+\telse\n+\t\taspeed_jtag_write(aspeed_jtag, ASPEED_JTAG_EC_GO_IDLE,\n+\t\t\t\t ASPEED_JTAG_EC);\n+\n+\taspeed_jtag_write(aspeed_jtag, ASPEED_JTAG_SW_MODE_EN |\n+\t\t\t ASPEED_JTAG_SW_MODE_TDIO, ASPEED_JTAG_SW);\n+\n+\taspeed_jtag->status = JTAG_STATE_IDLE;\n+\treturn 0;\n+}\n+\n+static void aspeed_jtag_xfer_sw(struct aspeed_jtag *aspeed_jtag,\n+\t\t\t\tstruct jtag_xfer *xfer, unsigned long *data)\n+{\n+\tunsigned long remain_xfer = xfer->length;\n+\tunsigned long shift_bits = 0;\n+\tunsigned long index = 0;\n+\tunsigned long tdi;\n+\tchar tdo;\n+\n+\tif (xfer->direction == JTAG_READ_XFER)\n+\t\ttdi = UINT_MAX;\n+\telse\n+\t\ttdi = data[index];\n+\n+\twhile (remain_xfer > 1) {\n+\t\ttdo = aspeed_jtag_tck_cycle(aspeed_jtag, 0,\n+\t\t\t\t\t tdi & ASPEED_JTAG_DATA_MSB);\n+\t\tdata[index] |= tdo << (shift_bits %\n+\t\t\t\t\t ASPEED_JTAG_DATA_CHUNK_SIZE);\n+\n+\t\ttdi >>= 1;\n+\t\tshift_bits++;\n+\t\tremain_xfer--;\n+\n+\t\tif (shift_bits % ASPEED_JTAG_DATA_CHUNK_SIZE == 0) {\n+\t\t\tdev_dbg(aspeed_jtag->dev, \"R/W data[%lu]:%lx\\n\",\n+\t\t\t\tindex, data[index]);\n+\n+\t\t\ttdo = 0;\n+\t\t\tindex++;\n+\n+\t\t\tif (xfer->direction == JTAG_READ_XFER)\n+\t\t\t\ttdi = UINT_MAX;\n+\t\t\telse\n+\t\t\t\ttdi = data[index];\n+\t\t}\n+\t}\n+\n+\ttdo = aspeed_jtag_tck_cycle(aspeed_jtag, 1, tdi & ASPEED_JTAG_DATA_MSB);\n+\tdata[index] |= tdo << (shift_bits % ASPEED_JTAG_DATA_CHUNK_SIZE);\n+}\n+\n+static void aspeed_jtag_xfer_push_data(struct aspeed_jtag *aspeed_jtag,\n+\t\t\t\t enum jtag_xfer_type type, u32 bits_len)\n+{\n+\tdev_dbg(aspeed_jtag->dev, \"shift bits %d\\n\", bits_len);\n+\n+\tif (type == JTAG_SIR_XFER) {\n+\t\taspeed_jtag_write(aspeed_jtag, ASPEED_JTAG_IOUT_LEN(bits_len),\n+\t\t\t\t ASPEED_JTAG_CTRL);\n+\t\taspeed_jtag_write(aspeed_jtag, ASPEED_JTAG_DOUT_LEN(bits_len) |\n+\t\t\t\t ASPEED_JTAG_CTL_INST_EN, ASPEED_JTAG_CTRL);\n+\t} else {\n+\t\taspeed_jtag_write(aspeed_jtag, ASPEED_JTAG_DOUT_LEN(bits_len),\n+\t\t\t\t ASPEED_JTAG_CTRL);\n+\t\taspeed_jtag_write(aspeed_jtag, ASPEED_JTAG_DOUT_LEN(bits_len) |\n+\t\t\t\t ASPEED_JTAG_CTL_DATA_EN, ASPEED_JTAG_CTRL);\n+\t}\n+}\n+\n+static void aspeed_jtag_xfer_push_data_last(struct aspeed_jtag *aspeed_jtag,\n+\t\t\t\t\t enum jtag_xfer_type type,\n+\t\t\t\t\t u32 shift_bits,\n+\t\t\t\t\t enum jtag_endstate endstate)\n+{\n+\tif (endstate != JTAG_STATE_IDLE) {\n+\t\tif (type == JTAG_SIR_XFER) {\n+\t\t\tdev_dbg(aspeed_jtag->dev, \"IR Keep Pause\\n\");\n+\n+\t\t\taspeed_jtag_write(aspeed_jtag,\n+\t\t\t\t\t ASPEED_JTAG_IOUT_LEN(shift_bits),\n+\t\t\t\t\t ASPEED_JTAG_CTRL);\n+\t\t\taspeed_jtag_write(aspeed_jtag,\n+\t\t\t\t\t ASPEED_JTAG_IOUT_LEN(shift_bits) |\n+\t\t\t\t\t ASPEED_JTAG_CTL_INST_EN,\n+\t\t\t\t\t ASPEED_JTAG_CTRL);\n+\t\t\taspeed_jtag_wait_instruction_pause(aspeed_jtag);\n+\t\t} else {\n+\t\t\tdev_dbg(aspeed_jtag->dev, \"DR Keep Pause\\n\");\n+\t\t\taspeed_jtag_write(aspeed_jtag,\n+\t\t\t\t\t ASPEED_JTAG_DOUT_LEN(shift_bits) |\n+\t\t\t\t\t ASPEED_JTAG_CTL_DR_UPDATE,\n+\t\t\t\t\t ASPEED_JTAG_CTRL);\n+\t\t\taspeed_jtag_write(aspeed_jtag,\n+\t\t\t\t\t ASPEED_JTAG_DOUT_LEN(shift_bits) |\n+\t\t\t\t\t ASPEED_JTAG_CTL_DR_UPDATE |\n+\t\t\t\t\t ASPEED_JTAG_CTL_DATA_EN,\n+\t\t\t\t\t ASPEED_JTAG_CTRL);\n+\t\t\taspeed_jtag_wait_data_pause_complete(aspeed_jtag);\n+\t\t}\n+\t} else {\n+\t\tif (type == JTAG_SIR_XFER) {\n+\t\t\tdev_dbg(aspeed_jtag->dev, \"IR go IDLE\\n\");\n+\n+\t\t\taspeed_jtag_write(aspeed_jtag,\n+\t\t\t\t\t ASPEED_JTAG_IOUT_LEN(shift_bits) |\n+\t\t\t\t\t ASPEED_JTAG_CTL_LASPEED_INST,\n+\t\t\t\t\t ASPEED_JTAG_CTRL);\n+\t\t\taspeed_jtag_write(aspeed_jtag,\n+\t\t\t\t\t ASPEED_JTAG_IOUT_LEN(shift_bits) |\n+\t\t\t\t\t ASPEED_JTAG_CTL_LASPEED_INST |\n+\t\t\t\t\t ASPEED_JTAG_CTL_INST_EN,\n+\t\t\t\t\t ASPEED_JTAG_CTRL);\n+\t\t\taspeed_jtag_wait_instruction_complete(aspeed_jtag);\n+\t\t} else {\n+\t\t\tdev_dbg(aspeed_jtag->dev, \"DR go IDLE\\n\");\n+\n+\t\t\taspeed_jtag_write(aspeed_jtag,\n+\t\t\t\t\t ASPEED_JTAG_DOUT_LEN(shift_bits) |\n+\t\t\t\t\t ASPEED_JTAG_CTL_LASPEED_DATA,\n+\t\t\t\t\t ASPEED_JTAG_CTRL);\n+\t\t\taspeed_jtag_write(aspeed_jtag,\n+\t\t\t\t\t ASPEED_JTAG_DOUT_LEN(shift_bits) |\n+\t\t\t\t\t ASPEED_JTAG_CTL_LASPEED_DATA |\n+\t\t\t\t\t ASPEED_JTAG_CTL_DATA_EN,\n+\t\t\t\t\t ASPEED_JTAG_CTRL);\n+\t\t\taspeed_jtag_wait_data_complete(aspeed_jtag);\n+\t\t}\n+\t}\n+}\n+\n+static void aspeed_jtag_xfer_hw(struct aspeed_jtag *aspeed_jtag,\n+\t\t\t\tstruct jtag_xfer *xfer, unsigned long *data)\n+{\n+\tunsigned long remain_xfer = xfer->length;\n+\tunsigned long index = 0;\n+\tchar shift_bits;\n+\tu32 data_reg;\n+\n+\tdata_reg = xfer->type == JTAG_SIR_XFER ?\n+\t\t ASPEED_JTAG_INST : ASPEED_JTAG_DATA;\n+\twhile (remain_xfer) {\n+\t\tif (xfer->direction == JTAG_WRITE_XFER) {\n+\t\t\tdev_dbg(aspeed_jtag->dev, \"W dr->dr_data[%lu]:%lx\\n\",\n+\t\t\t\tindex, data[index]);\n+\n+\t\t\taspeed_jtag_write(aspeed_jtag, data[index], data_reg);\n+\t\t} else {\n+\t\t\taspeed_jtag_write(aspeed_jtag, 0, data_reg);\n+\t\t}\n+\n+\t\tif (remain_xfer > ASPEED_JTAG_DATA_CHUNK_SIZE) {\n+\t\t\tshift_bits = ASPEED_JTAG_DATA_CHUNK_SIZE;\n+\n+\t\t\t/*\n+\t\t\t * Read bytes were not equals to column length\n+\t\t\t * and go to Pause-DR\n+\t\t\t */\n+\t\t\taspeed_jtag_xfer_push_data(aspeed_jtag, xfer->type,\n+\t\t\t\t\t\t shift_bits);\n+\t\t} else {\n+\t\t\t/*\n+\t\t\t * Read bytes equals to column length =>\n+\t\t\t * Update-DR\n+\t\t\t */\n+\t\t\tshift_bits = remain_xfer;\n+\t\t\taspeed_jtag_xfer_push_data_last(aspeed_jtag, xfer->type,\n+\t\t\t\t\t\t\tshift_bits,\n+\t\t\t\t\t\t\txfer->endstate);\n+\t\t}\n+\n+\t\tif (xfer->direction == JTAG_READ_XFER) {\n+\t\t\tif (shift_bits < ASPEED_JTAG_DATA_CHUNK_SIZE) {\n+\t\t\t\tdata[index] = aspeed_jtag_read(aspeed_jtag,\n+\t\t\t\t\t\t\t data_reg);\n+\n+\t\t\t\tdata[index] >>= ASPEED_JTAG_DATA_CHUNK_SIZE -\n+\t\t\t\t\t\t\t\tshift_bits;\n+\t\t\t} else {\n+\t\t\t\tdata[index] = aspeed_jtag_read(aspeed_jtag,\n+\t\t\t\t\t\t\t data_reg);\n+\t\t\t}\n+\t\t\tdev_dbg(aspeed_jtag->dev, \"R dr->dr_data[%lu]:%lx\\n\",\n+\t\t\t\tindex, data[index]);\n+\t\t}\n+\n+\t\tremain_xfer = remain_xfer - shift_bits;\n+\t\tindex++;\n+\t\tdev_dbg(aspeed_jtag->dev, \"remain_xfer %lu\\n\", remain_xfer);\n+\t}\n+}\n+\n+static int aspeed_jtag_xfer(struct jtag *jtag, struct jtag_xfer *xfer)\n+{\n+\tstatic const char sm_update_shiftir[] = {1, 1, 0, 0};\n+\tstatic const char sm_update_shiftdr[] = {1, 0, 0};\n+\tstatic const char sm_pause_idle[] = {1, 1, 0};\n+\tstatic const char sm_pause_update[] = {1, 1};\n+\tunsigned long *data = jtag_u64_to_ptr(xfer->tdio);\n+\tstruct aspeed_jtag *aspeed_jtag = jtag_priv(jtag);\n+\tunsigned long remain_xfer = xfer->length;\n+\tunsigned long offset;\n+\tchar dbg_str[256];\n+\tint pos = 0;\n+\tint i;\n+\n+\tfor (offset = 0, i = 0; offset < xfer->length;\n+\t\t\toffset += ASPEED_JTAG_DATA_CHUNK_SIZE, i++) {\n+\t\tpos += snprintf(&dbg_str[pos], sizeof(dbg_str) - pos,\n+\t\t\t\t\"0x%08lx \", data[i]);\n+\t}\n+\n+\tdev_dbg(aspeed_jtag->dev, \"aspeed_jtag %s %s xfer, mode:%s, END:%d, len:%lu, TDI[%s]\\n\",\n+\t\txfer->type == JTAG_SIR_XFER ? \"SIR\" : \"SDR\",\n+\t\txfer->direction == JTAG_READ_XFER ? \"READ\" : \"WRITE\",\n+\t\txfer->mode ? \"SW\" : \"HW\",\n+\t\txfer->endstate, remain_xfer, dbg_str);\n+\n+\tif (xfer->mode == JTAG_XFER_SW_MODE) {\n+\t\t/* SW mode */\n+\t\taspeed_jtag_write(aspeed_jtag, ASPEED_JTAG_SW_MODE_EN |\n+\t\t\t\t ASPEED_JTAG_SW_MODE_TDIO, ASPEED_JTAG_SW);\n+\n+\t\tif (aspeed_jtag->status != JTAG_STATE_IDLE) {\n+\t\t\t/*IR/DR Pause->Exit2 IR / DR->Update IR /DR */\n+\t\t\taspeed_jtag_sm_cycle(aspeed_jtag, sm_pause_update,\n+\t\t\t\t\t sizeof(sm_pause_update));\n+\t\t}\n+\n+\t\tif (xfer->type == JTAG_SIR_XFER)\n+\t\t\t/* ->IRSCan->CapIR->ShiftIR */\n+\t\t\taspeed_jtag_sm_cycle(aspeed_jtag, sm_update_shiftir,\n+\t\t\t\t\t sizeof(sm_update_shiftir));\n+\t\telse\n+\t\t\t/* ->DRScan->DRCap->DRShift */\n+\t\t\taspeed_jtag_sm_cycle(aspeed_jtag, sm_update_shiftdr,\n+\t\t\t\t\t sizeof(sm_update_shiftdr));\n+\n+\t\taspeed_jtag_xfer_sw(aspeed_jtag, xfer, data);\n+\n+\t\t/* DIPause/DRPause */\n+\t\taspeed_jtag_tck_cycle(aspeed_jtag, 0, 0);\n+\n+\t\tif (xfer->endstate == JTAG_STATE_IDLE) {\n+\t\t\t/* ->DRExit2->DRUpdate->IDLE */\n+\t\t\taspeed_jtag_sm_cycle(aspeed_jtag, sm_pause_idle,\n+\t\t\t\t\t sizeof(sm_pause_idle));\n+\t\t}\n+\t} else {\n+\t\t/* hw mode */\n+\t\taspeed_jtag_write(aspeed_jtag, 0, ASPEED_JTAG_SW);\n+\t\taspeed_jtag_xfer_hw(aspeed_jtag, xfer, data);\n+\t}\n+\n+\taspeed_jtag_write(aspeed_jtag, ASPEED_JTAG_SW_MODE_EN |\n+\t\t\t ASPEED_JTAG_SW_MODE_TDIO, ASPEED_JTAG_SW);\n+\taspeed_jtag->status = xfer->endstate;\n+\treturn 0;\n+}\n+\n+static int aspeed_jtag_status_get(struct jtag *jtag, __u32 *status)\n+{\n+\tstruct aspeed_jtag *aspeed_jtag = jtag_priv(jtag);\n+\n+\t*status = aspeed_jtag->status;\n+\treturn 0;\n+}\n+\n+static irqreturn_t aspeed_jtag_interrupt(s32 this_irq, void *dev_id)\n+{\n+\tstruct aspeed_jtag *aspeed_jtag = dev_id;\n+\tirqreturn_t ret;\n+\tu32 status;\n+\n+\tstatus = aspeed_jtag_read(aspeed_jtag, ASPEED_JTAG_ISR);\n+\tdev_dbg(aspeed_jtag->dev, \"status %x\\n\", status);\n+\n+\tif (status & ASPEED_JTAG_ISR_INT_MASK) {\n+\t\taspeed_jtag_write(aspeed_jtag,\n+\t\t\t\t (status & ASPEED_JTAG_ISR_INT_MASK)\n+\t\t\t\t | (status & ASPEED_JTAG_ISR_INT_EN_MASK),\n+\t\t\t\t ASPEED_JTAG_ISR);\n+\t\taspeed_jtag->flag |= status & ASPEED_JTAG_ISR_INT_MASK;\n+\t}\n+\n+\tif (aspeed_jtag->flag) {\n+\t\twake_up_interruptible(&aspeed_jtag->jtag_wq);\n+\t\tret = IRQ_HANDLED;\n+\t} else {\n+\t\tdev_err(aspeed_jtag->dev, \"aspeed_jtag irq status:%x\\n\",\n+\t\t\tstatus);\n+\t\tret = IRQ_NONE;\n+\t}\n+\treturn ret;\n+}\n+\n+int aspeed_jtag_init(struct platform_device *pdev,\n+\t\t struct aspeed_jtag *aspeed_jtag)\n+{\n+\tstruct resource *res;\n+\tint err;\n+\n+\tres = platform_get_resource(pdev, IORESOURCE_MEM, 0);\n+\taspeed_jtag->reg_base = devm_ioremap_resource(aspeed_jtag->dev, res);\n+\tif (IS_ERR(aspeed_jtag->reg_base)) {\n+\t\terr = -ENOMEM;\n+\t\tgoto out_region;\n+\t}\n+\n+\taspeed_jtag->pclk = devm_clk_get(aspeed_jtag->dev, NULL);\n+\tif (IS_ERR(aspeed_jtag->pclk)) {\n+\t\tdev_err(aspeed_jtag->dev, \"devm_clk_get failed\\n\");\n+\t\treturn PTR_ERR(aspeed_jtag->pclk);\n+\t}\n+\n+\tclk_prepare_enable(aspeed_jtag->pclk);\n+\n+\taspeed_jtag->irq = platform_get_irq(pdev, 0);\n+\tif (aspeed_jtag->irq < 0) {\n+\t\tdev_err(aspeed_jtag->dev, \"no irq specified\\n\");\n+\t\terr = -ENOENT;\n+\t\tgoto out_region;\n+\t}\n+\n+\t/* Enable clock */\n+\taspeed_jtag_write(aspeed_jtag, ASPEED_JTAG_CTL_ENG_EN |\n+\t\t\t ASPEED_JTAG_CTL_ENG_OUT_EN, ASPEED_JTAG_CTRL);\n+\taspeed_jtag_write(aspeed_jtag, ASPEED_JTAG_SW_MODE_EN |\n+\t\t\t ASPEED_JTAG_SW_MODE_TDIO, ASPEED_JTAG_SW);\n+\n+\terr = devm_request_irq(aspeed_jtag->dev, aspeed_jtag->irq,\n+\t\t\t aspeed_jtag_interrupt, 0,\n+\t\t\t \"aspeed-jtag\", aspeed_jtag);\n+\tif (err) {\n+\t\tdev_err(aspeed_jtag->dev, \"aspeed_jtag unable to get IRQ\");\n+\t\tgoto out_region;\n+\t}\n+\tdev_dbg(&pdev->dev, \"aspeed_jtag:IRQ %d.\\n\", aspeed_jtag->irq);\n+\n+\taspeed_jtag_write(aspeed_jtag, ASPEED_JTAG_ISR_INST_PAUSE |\n+\t\t\t ASPEED_JTAG_ISR_INST_COMPLETE |\n+\t\t\t ASPEED_JTAG_ISR_DATA_PAUSE |\n+\t\t\t ASPEED_JTAG_ISR_DATA_COMPLETE |\n+\t\t\t ASPEED_JTAG_ISR_INST_PAUSE_EN |\n+\t\t\t ASPEED_JTAG_ISR_INST_COMPLETE_EN |\n+\t\t\t ASPEED_JTAG_ISR_DATA_PAUSE_EN |\n+\t\t\t ASPEED_JTAG_ISR_DATA_COMPLETE_EN,\n+\t\t\t ASPEED_JTAG_ISR);\n+\n+\taspeed_jtag->flag = 0;\n+\tinit_waitqueue_head(&aspeed_jtag->jtag_wq);\n+\treturn 0;\n+\n+out_region:\n+\trelease_mem_region(res->start, resource_size(res));\n+\treturn err;\n+}\n+\n+int aspeed_jtag_deinit(struct platform_device *pdev,\n+\t\t struct aspeed_jtag *aspeed_jtag)\n+{\n+\taspeed_jtag_write(aspeed_jtag, 0, ASPEED_JTAG_ISR);\n+\tdevm_free_irq(aspeed_jtag->dev, aspeed_jtag->irq, aspeed_jtag);\n+\t/* Disabe clock */\n+\taspeed_jtag_write(aspeed_jtag, 0, ASPEED_JTAG_CTRL);\n+\tclk_disable_unprepare(aspeed_jtag->pclk);\n+\treturn 0;\n+}\n+\n+static const struct jtag_ops aspeed_jtag_ops = {\n+\t.freq_get = aspeed_jtag_freq_get,\n+\t.freq_set = aspeed_jtag_freq_set,\n+\t.status_get = aspeed_jtag_status_get,\n+\t.idle = aspeed_jtag_idle,\n+\t.xfer = aspeed_jtag_xfer\n+};\n+\n+static int aspeed_jtag_probe(struct platform_device *pdev)\n+{\n+\tstruct aspeed_jtag *aspeed_jtag;\n+\tstruct jtag *jtag;\n+\tint err;\n+\n+\tif (!of_device_is_compatible(pdev->dev.of_node, \"aspeed,aspeed-jtag\"))\n+\t\treturn -ENOMEM;\n+\n+\tjtag = jtag_alloc(sizeof(*aspeed_jtag), &aspeed_jtag_ops);\n+\tif (!jtag)\n+\t\treturn -ENODEV;\n+\n+\tplatform_set_drvdata(pdev, jtag);\n+\taspeed_jtag = jtag_priv(jtag);\n+\taspeed_jtag->dev = &pdev->dev;\n+\n+\t/* Initialize device*/\n+\terr = aspeed_jtag_init(pdev, aspeed_jtag);\n+\tif (err)\n+\t\tgoto err_jtag_init;\n+\n+\t/* Initialize JTAG core structure*/\n+\terr = jtag_register(jtag);\n+\tif (err)\n+\t\tgoto err_jtag_register;\n+\n+\treturn 0;\n+\n+err_jtag_register:\n+\taspeed_jtag_deinit(pdev, aspeed_jtag);\n+err_jtag_init:\n+\tjtag_free(jtag);\n+\treturn err;\n+}\n+\n+static int aspeed_jtag_remove(struct platform_device *pdev)\n+{\n+\tstruct jtag *jtag;\n+\n+\tjtag = platform_get_drvdata(pdev);\n+\taspeed_jtag_deinit(pdev, jtag_priv(jtag));\n+\tjtag_unregister(jtag);\n+\tjtag_free(jtag);\n+\treturn 0;\n+}\n+\n+static const struct of_device_id aspeed_jtag_of_match[] = {\n+\t{ .compatible = \"aspeed,aspeed2400-jtag\", },\n+\t{ .compatible = \"aspeed,aspeed2500-jtag\", },\n+\t{}\n+};\n+\n+static struct platform_driver aspeed_jtag_driver = {\n+\t.probe = aspeed_jtag_probe,\n+\t.remove = aspeed_jtag_remove,\n+\t.driver = {\n+\t\t.name = ASPEED_JTAG_NAME,\n+\t\t.of_match_table = aspeed_jtag_of_match,\n+\t},\n+};\n+module_platform_driver(aspeed_jtag_driver);\n+\n+MODULE_AUTHOR(\"Oleksandr Shamray <oleksandrs@mellanox.com>\");\n+MODULE_DESCRIPTION(\"ASPEED JTAG driver\");\n+MODULE_LICENSE(\"GPL v2\");\n", "prefixes": [ "v7", "2/4" ] }