AM654/J721e has HyperBus Memory Controller that supports HyperFlash and
HyperRAM devices. It provides a memory mapped interface to interact with
these devices. Add a driver to support the same.
Driver calibrates the controller, setups up for MMIO access and probes
HyperFlash child node.

Signed-off-by: Vignesh Raghavendra <vigne...@ti.com>
---
v2: No change

 drivers/mtd/Kconfig      |   7 +++
 drivers/mtd/Makefile     |   1 +
 drivers/mtd/hbmc-am654.c | 105 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 113 insertions(+)
 create mode 100644 drivers/mtd/hbmc-am654.c

diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig
index 0050fb2b9bf1..37f379d47803 100644
--- a/drivers/mtd/Kconfig
+++ b/drivers/mtd/Kconfig
@@ -94,6 +94,13 @@ config RENESAS_RPC_HF
          This enables access to Hyperflash memory through the Renesas
          RCar Gen3 RPC controller.
 
+config HBMC_AM654
+       bool "HyperBus controller driver for AM65x SoC"
+       depends on SYSCON
+       help
+        This is the driver for HyperBus controller on TI's AM65x and
+        other SoCs
+
 source "drivers/mtd/nand/Kconfig"
 
 source "drivers/mtd/spi/Kconfig"
diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile
index 22ceda93c06d..293079d709aa 100644
--- a/drivers/mtd/Makefile
+++ b/drivers/mtd/Makefile
@@ -18,5 +18,6 @@ obj-$(CONFIG_FLASH_PIC32) += pic32_flash.o
 obj-$(CONFIG_ST_SMI) += st_smi.o
 obj-$(CONFIG_STM32_FLASH) += stm32_flash.o
 obj-$(CONFIG_RENESAS_RPC_HF) += renesas_rpc_hf.o
+obj-$(CONFIG_HBMC_AM654) += hbmc-am654.o
 
 obj-y += nand/
diff --git a/drivers/mtd/hbmc-am654.c b/drivers/mtd/hbmc-am654.c
new file mode 100644
index 000000000000..5a560f1253ba
--- /dev/null
+++ b/drivers/mtd/hbmc-am654.c
@@ -0,0 +1,105 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/
+// Author: Vignesh Raghavendra <vigne...@ti.com>
+
+#include <common.h>
+#include <asm/io.h>
+#include <dm.h>
+#include <regmap.h>
+#include <syscon.h>
+
+#define FSS_SYSC_REG   0x4
+
+#define HYPERBUS_CALIB_COUNT 25
+
+struct am654_hbmc_priv {
+       void __iomem *mmiobase;
+       bool calibrated;
+};
+
+/* Calibrate by looking for "QRY" string within the CFI space */
+static int am654_hyperbus_calibrate(struct udevice *dev)
+{
+       struct am654_hbmc_priv *priv = dev_get_priv(dev);
+       int count = HYPERBUS_CALIB_COUNT;
+       int pass_count = 0;
+       u16 qry[3];
+
+       if (priv->calibrated)
+               return 0;
+
+       writew(0xF0, priv->mmiobase);
+       writew(0x98, priv->mmiobase + 0xaa);
+
+       while (count--) {
+               qry[0] = readw(priv->mmiobase + 0x20);
+               qry[1] = readw(priv->mmiobase + 0x22);
+               qry[2] = readw(priv->mmiobase + 0x24);
+
+               if (qry[0] == 'Q' && qry[1] == 'R' && qry[2] == 'Y')
+                       pass_count++;
+               else
+                       pass_count = 0;
+               if (pass_count == 5)
+                       break;
+       }
+       writew(0xF0, priv->mmiobase);
+       writew(0xFF, priv->mmiobase);
+
+       return pass_count == 5;
+}
+
+static int am654_select_hbmc(struct udevice *dev)
+{
+       struct regmap *regmap = syscon_get_regmap(dev_get_parent(dev));
+
+       return regmap_update_bits(regmap, FSS_SYSC_REG, 0x2, 0x2);
+}
+
+static int am654_hbmc_bind(struct udevice *dev)
+{
+       return dm_scan_fdt_dev(dev);
+}
+
+static int am654_hbmc_probe(struct udevice *dev)
+{
+       struct am654_hbmc_priv *priv = dev_get_priv(dev);
+       int ret;
+
+       priv->mmiobase = devfdt_remap_addr_index(dev, 1);
+       if (dev_read_bool(dev, "mux-controls")) {
+               ret = am654_select_hbmc(dev);
+               if (ret) {
+                       dev_err(dev, "Failed to select HBMC mux\n");
+                       return ret;
+               }
+       }
+
+       if (!priv->calibrated) {
+               ret = am654_hyperbus_calibrate(dev);
+               if (!ret) {
+                       dev_err(dev, "Calibration Failed\n");
+                       return -EIO;
+               }
+       }
+       priv->calibrated = true;
+
+       return 0;
+}
+
+static const struct udevice_id am654_hbmc_dt_ids[] = {
+       {
+               .compatible = "ti,am654-hbmc",
+       },
+       { /* end of table */ }
+};
+
+U_BOOT_DRIVER(hbmc_am654) = {
+       .name   = "hbmc-am654",
+       .id     = UCLASS_MTD,
+       .of_match = am654_hbmc_dt_ids,
+       .probe = am654_hbmc_probe,
+       .bind = am654_hbmc_bind,
+       .priv_auto_alloc_size = sizeof(struct am654_hbmc_priv),
+};
-- 
2.23.0

_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
https://lists.denx.de/listinfo/u-boot

Reply via email to