From patchwork Tue Feb 19 06:36:05 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Raghavendra, Vignesh" X-Patchwork-Id: 1044499 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=lists.infradead.org (client-ip=2607:7c80:54:e::133; helo=bombadil.infradead.org; envelope-from=linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=quarantine dis=none) header.from=ti.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="Hx9js5G2"; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=ti.com header.i=@ti.com header.b="L2tx3pX1"; dkim-atps=neutral Received: from bombadil.infradead.org (bombadil.infradead.org [IPv6:2607:7c80:54:e::133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 443WH00DB2z9sDX for ; Tue, 19 Feb 2019 17:36:44 +1100 (AEDT) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=EQvDmwO2kfqeJ/+2QiCGOTLAX+rPw4kDTGB+eYJR61A=; b=Hx9js5G2dnIPp5 RozsOsApiZgAwqm85nJO0t5IOuIuuwu4quPFZewzGr062d2Thp5RlkznnzcTD/9TxZDzAPaW7WEfy UPHCF7DwyrVdBJfhF1pUQSSW4366bqmw6CVt+BTUbndWGYmkFQ9PCH+UeG2x/AKj2bldstmTJo75S 3fQKaIu13rYoTAgVYaUQrMCuCLVGx2JI+JN3nnH2TZDW9betiq51Cf5IS299qJDhkLgjgWbIB/Oxy yx0Wgc3hJCkPrwy8v0JjdCIchrT1B3OToMZylNjTPCvkfH72X+joDoq79vpAjvgGUaewTgIjvQRpb z2hJrEAGISifMwR0FpFw==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.90_1 #2 (Red Hat Linux)) id 1gvz1B-0002PN-Q9; Tue, 19 Feb 2019 06:36:37 +0000 Received: from fllv0016.ext.ti.com ([198.47.19.142]) by bombadil.infradead.org with esmtps (Exim 4.90_1 #2 (Red Hat Linux)) id 1gvz0I-0001Ge-Nj; Tue, 19 Feb 2019 06:35:45 +0000 Received: from fllv0035.itg.ti.com ([10.64.41.0]) by fllv0016.ext.ti.com (8.15.2/8.15.2) with ESMTP id x1J6ZZQG073477; Tue, 19 Feb 2019 00:35:35 -0600 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ti.com; s=ti-com-17Q1; t=1550558135; bh=vxzw8soKU3JvNEV69lMF9xk8e7jCBElOTa2YADr4u68=; h=From:To:CC:Subject:Date:In-Reply-To:References; b=L2tx3pX1yNC2fLLp/g3B+db7FDB5/zN3ysjBvddTnSGyO4/eSKiwqaADTm9yoQPPp tAgHszcmEgui9VM4Mn4+kHOUfdBvIxKLit5LtoianSBAAkwVLWWn11yuaKvIZke2+U F7kDsfuR0FBVVQ/BH6dmsE87AQT316JD+qAzsuzU= Received: from DLEE113.ent.ti.com (dlee113.ent.ti.com [157.170.170.24]) by fllv0035.itg.ti.com (8.15.2/8.15.2) with ESMTPS id x1J6ZZ34021920 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=FAIL); Tue, 19 Feb 2019 00:35:35 -0600 Received: from DLEE115.ent.ti.com (157.170.170.26) by DLEE113.ent.ti.com (157.170.170.24) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.1591.10; Tue, 19 Feb 2019 00:35:35 -0600 Received: from dlep32.itg.ti.com (157.170.170.100) by DLEE115.ent.ti.com (157.170.170.26) with Microsoft SMTP Server (version=TLS1_0, cipher=TLS_RSA_WITH_AES_256_CBC_SHA) id 15.1.1591.10 via Frontend Transport; Tue, 19 Feb 2019 00:35:35 -0600 Received: from a0132425.india.ti.com (ileax41-snat.itg.ti.com [10.172.224.153]) by dlep32.itg.ti.com (8.14.3/8.13.8) with ESMTP id x1J6ZCt1025516; Tue, 19 Feb 2019 00:35:30 -0600 From: Vignesh R To: Vignesh R , David Woodhouse , Brian Norris , Boris Brezillon , Marek Vasut , Richard Weinberger , Rob Herring Subject: [RFC PATCH 3/5] mtd: Add support for Hyperbus memory devices Date: Tue, 19 Feb 2019 12:06:05 +0530 Message-ID: <20190219063607.29949-4-vigneshr@ti.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190219063607.29949-1-vigneshr@ti.com> References: <20190219063607.29949-1-vigneshr@ti.com> MIME-Version: 1.0 X-EXCLAIMER-MD-CONFIG: e1e8a2fd-e40a-4ac6-ac9b-f7e9cc9ee180 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20190218_223542_863831_834DD7FC X-CRM114-Status: GOOD ( 28.73 ) X-Spam-Score: -2.6 (--) X-Spam-Report: SpamAssassin version 3.4.2 on bombadil.infradead.org summary: Content analysis details: (-2.6 points) pts rule name description ---- ---------------------- -------------------------------------------------- -2.3 RCVD_IN_DNSWL_MED RBL: Sender listed at http://www.dnswl.org/, medium trust [198.47.19.142 listed in list.dnswl.org] -0.0 SPF_PASS SPF: sender matches SPF record -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from envelope-from domain -0.1 DKIMWL_WL_HIGH DKIMwl.org - Whitelisted High sender X-BeenThere: linux-mtd@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: Linux MTD discussion mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: devicetree@vger.kernel.org, Arnd Bergmann , tudor.ambarus@microchip.com, Greg Kroah-Hartman , nsekhar@ti.com, linux-kernel@vger.kernel.org, linux-mtd@lists.infradead.org, linux-arm-kernel@lists.infradead.org Sender: "linux-mtd" Errors-To: linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org Cypress HyperBus is Low Signal Count, High Performance Double Data Rate Bus interface between a host system master and one or more slave interfaces. HyperBus is used to connect microprocessor, microcontroller, or ASIC devices with random access NOR flash memory(called HyperFlash) or self refresh DRAM(called HyperRAM). Its a 8-bit data bus (DQ[7:0]) with Read-Write Data Strobe (RWDS) signal and either Single-ended clock(3.0V parts) or Differential clock (1.8V parts). It uses ChipSelect lines to select b/w multiple slaves. At bus level, it follows a separate protocol described in HyperBus specification[1]. HyperFlash follows CFI AMD/Fujitsu Extended Command Set (0x0002) similar to that of existing parallel NORs. Since Hyperbus is x8 DDR bus, its equivalent to x16 parallel NOR flash wrt bits per clk. But Hyperbus operates at >166MHz frequencies. HyperRAM provides direct random read/write access to flash memory array. But, Hyperbus memory controllers seem to abstract implementation details and expose a simple MMIO interface to access connected flash. Add support for registering HyperFlash devices with MTD framework. MTD maps framework along with CFI chip support framework are used to support communicate with flash. Framework is modelled along the lines of spi-nor framework. HyperBus memory controller(HBMC) drivers call hb_register_device() to register a single HyperFlash device. HyperFlash core parses MMIO access information from DT, sets up the map_info struct, probes CFI flash and registers it with MTD framework. Some HBMC masters need calibration/training sequence[3] to be carried out, in order for DLL inside the controller to lock, by reading a known string/pattern. This is done by repeatedly reading CFI Query Identification String. Calibration needs to be done before try to detect flash as part of CFI flash probe. HyperRAM is not supported atm. HyperBus specification can be found at[1] HyperFlash datasheet can be found at[2] [1] https://www.cypress.com/file/213356/download [2] https://www.cypress.com/file/213346/download [3] http://www.ti.com/lit/ug/spruid7b/spruid7b.pdf Table 12-5741. HyperFlash Access Sequence Signed-off-by: Vignesh R --- MAINTAINERS | 7 ++ drivers/mtd/Kconfig | 2 + drivers/mtd/Makefile | 1 + drivers/mtd/hyperbus/Kconfig | 23 +++++ drivers/mtd/hyperbus/Makefile | 4 + drivers/mtd/hyperbus/core.c | 167 ++++++++++++++++++++++++++++++++++ include/linux/mtd/hyperbus.h | 73 +++++++++++++++ 7 files changed, 277 insertions(+) create mode 100644 drivers/mtd/hyperbus/Kconfig create mode 100644 drivers/mtd/hyperbus/Makefile create mode 100644 drivers/mtd/hyperbus/core.c create mode 100644 include/linux/mtd/hyperbus.h diff --git a/MAINTAINERS b/MAINTAINERS index 08bf7418a97f..0808c22807bc 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7143,6 +7143,13 @@ F: include/uapi/linux/hyperv.h F: tools/hv/ F: Documentation/ABI/stable/sysfs-bus-vmbus +HYPERBUS SUPPORT +M: Vignesh R +S: Supported +F: drivers/mtd/hyperbus/ +F: include/linux/mtd/hyperbus.h +F: Documentation/devicetree/bindings/mtd/cypress,hyperbus.txt + HYPERVISOR VIRTUAL CONSOLE DRIVER L: linuxppc-dev@lists.ozlabs.org S: Odd Fixes diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig index 79a8ff542883..a915ff300390 100644 --- a/drivers/mtd/Kconfig +++ b/drivers/mtd/Kconfig @@ -290,4 +290,6 @@ source "drivers/mtd/spi-nor/Kconfig" source "drivers/mtd/ubi/Kconfig" +source "drivers/mtd/hyperbus/Kconfig" + endif # MTD diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile index 58fc327a5276..04c154906631 100644 --- a/drivers/mtd/Makefile +++ b/drivers/mtd/Makefile @@ -35,3 +35,4 @@ obj-y += chips/ lpddr/ maps/ devices/ nand/ tests/ obj-$(CONFIG_MTD_SPI_NOR) += spi-nor/ obj-$(CONFIG_MTD_UBI) += ubi/ +obj-$(CONFIG_MTD_HYPERBUS) += hyperbus/ diff --git a/drivers/mtd/hyperbus/Kconfig b/drivers/mtd/hyperbus/Kconfig new file mode 100644 index 000000000000..02c38afc5c50 --- /dev/null +++ b/drivers/mtd/hyperbus/Kconfig @@ -0,0 +1,23 @@ +menuconfig MTD_HYPERBUS + tristate "Hyperbus support" + select MTD_CFI + select MTD_MAP_BANK_WIDTH_2 + select MTD_CFI_AMDSTD + select MTD_COMPLEX_MAPPINGS + help + This is the framework for the Hyperbus which can be used by + the Hyperbus Controller driver to commmunicate with + Hyperflash. See Cypress Hyperbus specification for more + details + + +if MTD_HYPERBUS + +config HBMC_AM654 + tristate "Hyperbus controller driver for AM65x SoC" + help + This is the driver for Hyperbus controller on TI's AM65x and + other SoCs + +endif # MTD_HYPERBUS + diff --git a/drivers/mtd/hyperbus/Makefile b/drivers/mtd/hyperbus/Makefile new file mode 100644 index 000000000000..64e377d7f636 --- /dev/null +++ b/drivers/mtd/hyperbus/Makefile @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 + +obj-$(CONFIG_MTD_HYPERBUS) += core.o +obj-$(CONFIG_HBMC_AM654) += hbmc_am654.o diff --git a/drivers/mtd/hyperbus/core.c b/drivers/mtd/hyperbus/core.c new file mode 100644 index 000000000000..d3d44aab7503 --- /dev/null +++ b/drivers/mtd/hyperbus/core.c @@ -0,0 +1,167 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/ +// Author: Vignesh R + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define HB_CALIB_COUNT 25 + +static struct hb_device *map_to_hbdev(struct map_info *map) +{ + return container_of(map, struct hb_device, map); +} + +static map_word hb_read16(struct map_info *map, unsigned long addr) +{ + struct hb_device *hbdev = map_to_hbdev(map); + map_word read_data; + + read_data.x[0] = hbdev->ops->read16(hbdev, addr); + + return read_data; +} + +static void hb_write16(struct map_info *map, map_word d, unsigned long addr) +{ + struct hb_device *hbdev = map_to_hbdev(map); + + hbdev->ops->write16(hbdev, addr, d.x[0]); +} + +static void hb_copy_from(struct map_info *map, void *to, + unsigned long from, ssize_t len) +{ + struct hb_device *hbdev = map_to_hbdev(map); + + hbdev->ops->copy_from(hbdev, to, from, len); +} + +static void hb_copy_to(struct map_info *map, unsigned long to, + const void *from, ssize_t len) +{ + struct hb_device *hbdev = map_to_hbdev(map); + + hbdev->ops->copy_to(hbdev, to, from, len); +} + +/* Calibrate HBMC by repeatedly reading "QRY" string from CFI space */ +static int hb_calibrate(struct hb_device *hbdev) +{ + struct map_info *map = &hbdev->map; + struct cfi_private cfi; + int count = HB_CALIB_COUNT; + int ret; + + cfi.interleave = 1; + cfi.device_type = CFI_DEVICETYPE_X16; + cfi_send_gen_cmd(0xF0, 0, 0, map, &cfi, cfi.device_type, NULL); + cfi_send_gen_cmd(0x98, 0x55, 0, map, &cfi, cfi.device_type, NULL); + + while (count--) + cfi_qry_present(map, 0, &cfi); + + ret = cfi_qry_present(map, 0, &cfi); + cfi_qry_mode_off(0, map, &cfi); + + return ret; +} + +int hb_register_device(struct hb_device *hbdev) +{ + struct resource res; + struct device *dev; + struct device_node *np; + struct map_info *map; + struct hb_ops *ops; + int err; + + if (!hbdev || !hbdev->dev || !hbdev->np) { + pr_err("hyperbus: please fill all the necessary fields!\n"); + return -EINVAL; + } + + np = hbdev->np; + if (!of_device_is_compatible(np, "cypress,hyperflash")) + return -ENODEV; + + hbdev->memtype = HYPERFLASH; + + if (of_address_to_resource(np, 0, &res)) + return -EINVAL; + + dev = hbdev->dev; + map = &hbdev->map; + map->size = resource_size(&res); + map->virt = devm_ioremap_resource(dev, &res); + if (IS_ERR(map->virt)) + return PTR_ERR(map->virt); + + map->name = dev_name(dev); + map->bankwidth = 2; + + simple_map_init(map); + ops = hbdev->ops; + if (ops) { + if (ops->read16) + map->read = hb_read16; + if (ops->write16) + map->write = hb_write16; + if (ops->copy_to) + map->copy_to = hb_copy_to; + if (ops->copy_from) + map->copy_from = hb_copy_from; + } + + if (hbdev->needs_calib) { + err = hb_calibrate(hbdev); + if (!err) { + dev_err(hbdev->dev, "Calibration failed\n"); + return -ENODEV; + } + } + + hbdev->mtd = do_map_probe("cfi_probe", map); + if (!hbdev->mtd) { + dev_err(hbdev->dev, "probing failed\n"); + return -ENXIO; + } + + hbdev->mtd->dev.parent = hbdev->dev; + mtd_set_of_node(hbdev->mtd, np); + + err = mtd_device_register(hbdev->mtd, NULL, 0); + if (err) { + dev_err(hbdev->dev, "failed to register mtd device\n"); + goto err_destroy; + } + hbdev->registered = true; + + return 0; + +err_destroy: + map_destroy(hbdev->mtd); + return err; +} +EXPORT_SYMBOL_GPL(hb_register_device); + +int hb_unregister_device(struct hb_device *hbdev) +{ + int ret = 0; + + if (hbdev && hbdev->mtd && hbdev->registered) { + ret = mtd_device_unregister(hbdev->mtd); + map_destroy(hbdev->mtd); + } + + return ret; +} +EXPORT_SYMBOL_GPL(hb_unregister_device); diff --git a/include/linux/mtd/hyperbus.h b/include/linux/mtd/hyperbus.h new file mode 100644 index 000000000000..0aa11458c424 --- /dev/null +++ b/include/linux/mtd/hyperbus.h @@ -0,0 +1,73 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/ + */ + +#ifndef __LINUX_MTD_HYPERBUS_H__ +#define __LINUX_MTD_HYPERBUS_H__ + +#include + +enum hb_memtype { + HYPERFLASH, + HYPERRAM, +}; + +/** + * struct hb_device - struct representing Hyperbus slave device + * @map: map_info struct for accessing MMIO Hyperbus flash memory + * @dev: device pointer of Hyperbus Controller + * @np: pointer to Hyperbus slave device node + * @mtd: pointer to MTD struct + * @ops: pointer to custom Hyperbus ops + * @memtype: type of memory device: Hyperflash or HyperRAM + * @needs_calib: flag to indicate whether calibration sequence is needed + * @registered: flag to indicate whether device is registered with MTD core + */ + +struct hb_device { + struct map_info map; + struct device *dev; + struct device_node *np; + struct mtd_info *mtd; + struct hb_ops *ops; + enum hb_memtype memtype; + bool needs_calib; + bool registered; +}; + +/** + * struct hb_ops - struct representing custom Hyperbus operations + * @read16: read 16 bit of data, usually from register/ID-CFI space + * @write16: write 16 bit of data, usually to register/ID-CFI space + * copy_from: copy data from flash memory + * copy_to: copy data to flash_memory + */ + +struct hb_ops { + u16 (*read16)(struct hb_device *hbdev, unsigned long addr); + void (*write16)(struct hb_device *hbdev, unsigned long addr, u16 val); + + void (*copy_from)(struct hb_device *hbdev, void *to, + unsigned long from, ssize_t len); + void (*copy_to)(struct hb_device *dev, unsigned long to, + const void *from, ssize_t len); +}; + +/** + * hb_register_device - probe and register a Hyperbus slave memory device + * @hbdev: hb_device struct with dev, np populated + * + * Return: 0 for success, others for failure. + */ +int hb_register_device(struct hb_device *hbdev); + +/** + * hb_unregister_device - deregister Hyperbus slave memory device + * @hbdev: hb_device struct of device to be unregistered + * + * Return: 0 for success, others for failure. + */ +int hb_unregister_device(struct hb_device *hbdev); + +#endif /* __LINUX_MTD_HYPERBUS_H__ */