1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * DWC SATA platform driver
4 *
5 * (C) Copyright 2016
6 *     Texas Instruments Incorporated, <www.ti.com>
7 *
8 * Author: Mugunthan V N <mugunthanvnm@ti.com>
9 */
10
11#include <common.h>
12#include <dm.h>
13#include <ahci.h>
14#include <scsi.h>
15#include <sata.h>
16#ifdef CONFIG_ARCH_OMAP2PLUS
17#include <asm/arch/sata.h>
18#endif
19#include <asm/io.h>
20#include <generic-phy.h>
21#include <linux/printk.h>
22
23struct dwc_ahci_priv {
24	void *base;
25	void *wrapper_base;
26};
27
28static int dwc_ahci_bind(struct udevice *dev)
29{
30	struct udevice *scsi_dev;
31
32	return ahci_bind_scsi(dev, &scsi_dev);
33}
34
35static int dwc_ahci_of_to_plat(struct udevice *dev)
36{
37	struct dwc_ahci_priv *priv = dev_get_priv(dev);
38	fdt_addr_t addr;
39
40	priv->base = map_physmem(dev_read_addr(dev), sizeof(void *),
41				 MAP_NOCACHE);
42
43	addr = devfdt_get_addr_index(dev, 1);
44	if (addr != FDT_ADDR_T_NONE) {
45		priv->wrapper_base = map_physmem(addr, sizeof(void *),
46						 MAP_NOCACHE);
47	} else {
48		priv->wrapper_base = NULL;
49	}
50
51	return 0;
52}
53
54static int dwc_ahci_probe(struct udevice *dev)
55{
56	struct dwc_ahci_priv *priv = dev_get_priv(dev);
57	int ret;
58	struct phy phy;
59
60	ret = generic_phy_get_by_name(dev, "sata-phy", &phy);
61	if (ret) {
62		pr_err("can't get the phy from DT\n");
63		return ret;
64	}
65
66	ret = generic_phy_init(&phy);
67	if (ret) {
68		pr_debug("unable to initialize the sata phy\n");
69		return ret;
70	}
71
72	ret = generic_phy_power_on(&phy);
73	if (ret) {
74		pr_debug("unable to power on the sata phy\n");
75		return ret;
76	}
77
78#ifdef CONFIG_ARCH_OMAP2PLUS
79	if (priv->wrapper_base) {
80		u32 val = TI_SATA_IDLE_NO | TI_SATA_STANDBY_NO;
81
82		/* Enable SATA module, No Idle, No Standby */
83		writel(val, priv->wrapper_base + TI_SATA_SYSCONFIG);
84	}
85#endif
86
87	return ahci_probe_scsi(dev, (ulong)priv->base);
88}
89
90static const struct udevice_id dwc_ahci_ids[] = {
91	{ .compatible = "snps,dwc-ahci" },
92	{ }
93};
94
95U_BOOT_DRIVER(dwc_ahci) = {
96	.name	= "dwc_ahci",
97	.id	= UCLASS_AHCI,
98	.of_match = dwc_ahci_ids,
99	.bind	= dwc_ahci_bind,
100	.of_to_plat = dwc_ahci_of_to_plat,
101	.ops	= &scsi_ops,
102	.probe	= dwc_ahci_probe,
103	.priv_auto	= sizeof(struct dwc_ahci_priv),
104};
105