mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-25 06:00:43 +00:00
mtd: Add TI HyperBus Memory Controller driver
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 <vigneshr@ti.com> Reviewed-by: Stefan Roese <sr@denx.de>
This commit is contained in:
parent
d75eacf9b8
commit
c2dfd0a4d8
3 changed files with 113 additions and 0 deletions
|
@ -94,6 +94,13 @@ config RENESAS_RPC_HF
|
||||||
This enables access to Hyperflash memory through the Renesas
|
This enables access to Hyperflash memory through the Renesas
|
||||||
RCar Gen3 RPC controller.
|
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/nand/Kconfig"
|
||||||
|
|
||||||
source "drivers/mtd/spi/Kconfig"
|
source "drivers/mtd/spi/Kconfig"
|
||||||
|
|
|
@ -18,5 +18,6 @@ obj-$(CONFIG_FLASH_PIC32) += pic32_flash.o
|
||||||
obj-$(CONFIG_ST_SMI) += st_smi.o
|
obj-$(CONFIG_ST_SMI) += st_smi.o
|
||||||
obj-$(CONFIG_STM32_FLASH) += stm32_flash.o
|
obj-$(CONFIG_STM32_FLASH) += stm32_flash.o
|
||||||
obj-$(CONFIG_RENESAS_RPC_HF) += renesas_rpc_hf.o
|
obj-$(CONFIG_RENESAS_RPC_HF) += renesas_rpc_hf.o
|
||||||
|
obj-$(CONFIG_HBMC_AM654) += hbmc-am654.o
|
||||||
|
|
||||||
obj-y += nand/
|
obj-y += nand/
|
||||||
|
|
105
drivers/mtd/hbmc-am654.c
Normal file
105
drivers/mtd/hbmc-am654.c
Normal file
|
@ -0,0 +1,105 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
//
|
||||||
|
// Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/
|
||||||
|
// Author: Vignesh Raghavendra <vigneshr@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),
|
||||||
|
};
|
Loading…
Reference in a new issue