1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * MTK SATA platform driver 4 * 5 * Copyright (C) 2020 MediaTek Inc. 6 * 7 * Author: Ryder Lee <ryder.lee@mediatek.com> 8 * Author: Frank Wunderlich <frank-w@public-files.de> 9 */ 10 11#include <common.h> 12#include <ahci.h> 13#include <asm/global_data.h> 14#include <asm/io.h> 15#include <dm.h> 16#include <dm/of_access.h> 17#include <generic-phy.h> 18#include <linux/err.h> 19#include <regmap.h> 20#include <reset.h> 21#include <sata.h> 22#include <scsi.h> 23#include <syscon.h> 24#include <dm/device_compat.h> 25 26#define SYS_CFG 0x14 27#define SYS_CFG_SATA_MSK GENMASK(31, 30) 28#define SYS_CFG_SATA_EN BIT(31) 29 30struct mtk_ahci_priv { 31 void *base; 32 33 struct ahci_uc_priv ahci_priv; 34 struct regmap *mode; 35 struct reset_ctl_bulk rst_bulk; 36}; 37 38static int mtk_ahci_bind(struct udevice *dev) 39{ 40 struct udevice *scsi_dev; 41 42 return ahci_bind_scsi(dev, &scsi_dev); 43} 44 45static int mtk_ahci_of_to_plat(struct udevice *dev) 46{ 47 struct mtk_ahci_priv *priv = dev_get_priv(dev); 48 49 priv->base = devfdt_remap_addr_index(dev, 0); 50 51 return 0; 52} 53 54static int mtk_ahci_parse_property(struct ahci_uc_priv *hpriv, 55 struct udevice *dev) 56{ 57 struct mtk_ahci_priv *plat = dev_get_priv(dev); 58 const void *fdt = gd->fdt_blob; 59 60 /* enable SATA function if needed */ 61 if (fdt_get_property(fdt, dev_of_offset(dev), 62 "mediatek,phy-mode", NULL)) { 63 plat->mode = syscon_regmap_lookup_by_phandle(dev, 64 "mediatek,phy-mode"); 65 if (IS_ERR(plat->mode)) { 66 dev_err(dev, "missing phy-mode phandle\n"); 67 return PTR_ERR(plat->mode); 68 } 69 regmap_update_bits(plat->mode, SYS_CFG, 70 SYS_CFG_SATA_MSK, SYS_CFG_SATA_EN); 71 } 72 73 ofnode_read_u32(dev_ofnode(dev), "ports-implemented", 74 &hpriv->port_map); 75 return 0; 76} 77 78static int mtk_ahci_probe(struct udevice *dev) 79{ 80 struct mtk_ahci_priv *priv = dev_get_priv(dev); 81 int ret; 82 struct phy phy; 83 84 ret = mtk_ahci_parse_property(&priv->ahci_priv, dev); 85 if (ret) 86 return ret; 87 88 ret = reset_get_bulk(dev, &priv->rst_bulk); 89 if (!ret) { 90 reset_assert_bulk(&priv->rst_bulk); 91 reset_deassert_bulk(&priv->rst_bulk); 92 } else { 93 dev_err(dev, "Failed to get reset: %d\n", ret); 94 } 95 96 ret = generic_phy_get_by_name(dev, "sata-phy", &phy); 97 if (ret) { 98 pr_err("can't get the phy from DT\n"); 99 return ret; 100 } 101 102 ret = generic_phy_init(&phy); 103 if (ret) { 104 pr_err("unable to initialize the sata phy\n"); 105 return ret; 106 } 107 108 ret = generic_phy_power_on(&phy); 109 if (ret) { 110 pr_err("unable to power on the sata phy\n"); 111 return ret; 112 } 113 114 return ahci_probe_scsi(dev, (ulong)priv->base); 115} 116 117static const struct udevice_id mtk_ahci_ids[] = { 118 { .compatible = "mediatek,mtk-ahci" }, 119 { } 120}; 121 122U_BOOT_DRIVER(mtk_ahci) = { 123 .name = "mtk_ahci", 124 .id = UCLASS_AHCI, 125 .of_match = mtk_ahci_ids, 126 .bind = mtk_ahci_bind, 127 .of_to_plat = mtk_ahci_of_to_plat, 128 .ops = &scsi_ops, 129 .probe = mtk_ahci_probe, 130 .priv_auto = sizeof(struct mtk_ahci_priv), 131}; 132