From: Frank Wunderlich Date: Thu, 13 Aug 2020 08:20:47 +0000 (+0200) Subject: ahci: mediatek: add ahci driver X-Git-Url: http://git.dujemihanovic.xyz/?a=commitdiff_plain;h=38bff327d7e320671b051440d73a0f6613203ade;p=u-boot.git ahci: mediatek: add ahci driver add AHCI driver ported from linux https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/ata/ahci_mtk.c Signed-off-by: Frank Wunderlich --- diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index d8c9756c2a..f2f8275aec 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -130,4 +130,12 @@ config AHCI_MVEBU onboard AHCI SATA. If unsure, say N. + +config MTK_AHCI + bool "Enable Mediatek AHCI driver support" + depends on AHCI + help + Enable this driver to support Sata devices through + Mediatek AHCI controller (e.g. MT7622). + endmenu diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile index a69edb10f7..98fb480700 100644 --- a/drivers/ata/Makefile +++ b/drivers/ata/Makefile @@ -19,3 +19,4 @@ obj-$(CONFIG_SATA_SIL) += sata_sil.o obj-$(CONFIG_SANDBOX) += sata_sandbox.o obj-$(CONFIG_AHCI_MVEBU) += ahci_mvebu.o obj-$(CONFIG_SUNXI_AHCI) += ahci_sunxi.o +obj-$(CONFIG_MTK_AHCI) += mtk_ahci.o diff --git a/drivers/ata/mtk_ahci.c b/drivers/ata/mtk_ahci.c new file mode 100644 index 0000000000..8e09c5f9e6 --- /dev/null +++ b/drivers/ata/mtk_ahci.c @@ -0,0 +1,130 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * MTK SATA platform driver + * + * (C) Copyright 2020 + * Mediatek + * + * Author: Frank Wunderlich + * based on https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/ata/ahci_mtk.c + * Author: Ryder Lee + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SYS_CFG 0x14 +#define SYS_CFG_SATA_MSK GENMASK(31, 30) +#define SYS_CFG_SATA_EN BIT(31) + +struct mtk_ahci_priv { + void *base; + + struct ahci_uc_priv ahci_priv; + struct regmap *mode; + struct reset_ctl_bulk rst_bulk; +}; + +static int mtk_ahci_bind(struct udevice *dev) +{ + struct udevice *scsi_dev; + + return ahci_bind_scsi(dev, &scsi_dev); +} + +static int mtk_ahci_ofdata_to_platdata(struct udevice *dev) +{ + struct mtk_ahci_priv *priv = dev_get_priv(dev); + + priv->base = devfdt_remap_addr_index(dev, 0); + + return 0; +} + +static int mtk_ahci_parse_property(struct ahci_uc_priv *hpriv, + struct udevice *dev) +{ + struct mtk_ahci_priv *plat = dev_get_priv(dev); + const void *fdt = gd->fdt_blob; + + /* enable SATA function if needed */ + if (fdt_get_property(fdt, dev_of_offset(dev), + "mediatek,phy-mode", NULL)) { + plat->mode = syscon_regmap_lookup_by_phandle(dev, + "mediatek,phy-mode"); + if (IS_ERR(plat->mode)) { + dev_err(dev, "missing phy-mode phandle\n"); + return PTR_ERR(plat->mode); + } + regmap_update_bits(plat->mode, SYS_CFG, + SYS_CFG_SATA_MSK, SYS_CFG_SATA_EN); + } + + ofnode_read_u32(dev->node, "ports-implemented", &hpriv->port_map); + return 0; +} + +static int mtk_ahci_probe(struct udevice *dev) +{ + struct mtk_ahci_priv *priv = dev_get_priv(dev); + int ret; + struct phy phy; + + ret = mtk_ahci_parse_property(&priv->ahci_priv, dev); + if (ret) + return ret; + + ret = reset_get_bulk(dev, &priv->rst_bulk); + if (!ret) { + reset_assert_bulk(&priv->rst_bulk); + reset_deassert_bulk(&priv->rst_bulk); + } else { + dev_err(dev, "Failed to get reset: %d\n", ret); + } + + ret = generic_phy_get_by_name(dev, "sata-phy", &phy); + if (ret) { + pr_err("can't get the phy from DT\n"); + return ret; + } + + ret = generic_phy_init(&phy); + if (ret) { + pr_err("unable to initialize the sata phy\n"); + return ret; + } + + ret = generic_phy_power_on(&phy); + if (ret) { + pr_err("unable to power on the sata phy\n"); + return ret; + } + + return ahci_probe_scsi(dev, (ulong)priv->base); +} + +static const struct udevice_id mtk_ahci_ids[] = { + { .compatible = "mediatek,mtk-ahci" }, + { } +}; + +U_BOOT_DRIVER(mtk_ahci) = { + .name = "mtk_ahci", + .id = UCLASS_AHCI, + .of_match = mtk_ahci_ids, + .bind = mtk_ahci_bind, + .ofdata_to_platdata = mtk_ahci_ofdata_to_platdata, + .ops = &scsi_ops, + .probe = mtk_ahci_probe, + .priv_auto_alloc_size = sizeof(struct mtk_ahci_priv), +};