13e0a4e85SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2eba68f82SYendapally Reddy Dhananjaya Reddy /*
3eba68f82SYendapally Reddy Dhananjaya Reddy * Broadcom SATA3 AHCI Controller Driver
4eba68f82SYendapally Reddy Dhananjaya Reddy *
5eba68f82SYendapally Reddy Dhananjaya Reddy * Copyright © 2009-2015 Broadcom Corporation
6eba68f82SYendapally Reddy Dhananjaya Reddy */
7eba68f82SYendapally Reddy Dhananjaya Reddy
8eba68f82SYendapally Reddy Dhananjaya Reddy #include <linux/ahci_platform.h>
9eba68f82SYendapally Reddy Dhananjaya Reddy #include <linux/compiler.h>
10eba68f82SYendapally Reddy Dhananjaya Reddy #include <linux/device.h>
11eba68f82SYendapally Reddy Dhananjaya Reddy #include <linux/init.h>
12eba68f82SYendapally Reddy Dhananjaya Reddy #include <linux/interrupt.h>
13eba68f82SYendapally Reddy Dhananjaya Reddy #include <linux/io.h>
14eba68f82SYendapally Reddy Dhananjaya Reddy #include <linux/kernel.h>
15eba68f82SYendapally Reddy Dhananjaya Reddy #include <linux/libata.h>
16eba68f82SYendapally Reddy Dhananjaya Reddy #include <linux/module.h>
17eba68f82SYendapally Reddy Dhananjaya Reddy #include <linux/of.h>
18eba68f82SYendapally Reddy Dhananjaya Reddy #include <linux/platform_device.h>
192b2c47d9SFlorian Fainelli #include <linux/reset.h>
20eba68f82SYendapally Reddy Dhananjaya Reddy #include <linux/string.h>
21eba68f82SYendapally Reddy Dhananjaya Reddy
22eba68f82SYendapally Reddy Dhananjaya Reddy #include "ahci.h"
23eba68f82SYendapally Reddy Dhananjaya Reddy
24eba68f82SYendapally Reddy Dhananjaya Reddy #define DRV_NAME "brcm-ahci"
25eba68f82SYendapally Reddy Dhananjaya Reddy
26eba68f82SYendapally Reddy Dhananjaya Reddy #define SATA_TOP_CTRL_VERSION 0x0
27eba68f82SYendapally Reddy Dhananjaya Reddy #define SATA_TOP_CTRL_BUS_CTRL 0x4
28eba68f82SYendapally Reddy Dhananjaya Reddy #define MMIO_ENDIAN_SHIFT 0 /* CPU->AHCI */
29eba68f82SYendapally Reddy Dhananjaya Reddy #define DMADESC_ENDIAN_SHIFT 2 /* AHCI->DDR */
30eba68f82SYendapally Reddy Dhananjaya Reddy #define DMADATA_ENDIAN_SHIFT 4 /* AHCI->DDR */
31eba68f82SYendapally Reddy Dhananjaya Reddy #define PIODATA_ENDIAN_SHIFT 6
32eba68f82SYendapally Reddy Dhananjaya Reddy #define ENDIAN_SWAP_NONE 0
33eba68f82SYendapally Reddy Dhananjaya Reddy #define ENDIAN_SWAP_FULL 2
34eba68f82SYendapally Reddy Dhananjaya Reddy #define SATA_TOP_CTRL_TP_CTRL 0x8
35eba68f82SYendapally Reddy Dhananjaya Reddy #define SATA_TOP_CTRL_PHY_CTRL 0xc
36eba68f82SYendapally Reddy Dhananjaya Reddy #define SATA_TOP_CTRL_PHY_CTRL_1 0x0
37eba68f82SYendapally Reddy Dhananjaya Reddy #define SATA_TOP_CTRL_1_PHY_DEFAULT_POWER_STATE BIT(14)
38eba68f82SYendapally Reddy Dhananjaya Reddy #define SATA_TOP_CTRL_PHY_CTRL_2 0x4
39eba68f82SYendapally Reddy Dhananjaya Reddy #define SATA_TOP_CTRL_2_SW_RST_MDIOREG BIT(0)
40eba68f82SYendapally Reddy Dhananjaya Reddy #define SATA_TOP_CTRL_2_SW_RST_OOB BIT(1)
41eba68f82SYendapally Reddy Dhananjaya Reddy #define SATA_TOP_CTRL_2_SW_RST_RX BIT(2)
42eba68f82SYendapally Reddy Dhananjaya Reddy #define SATA_TOP_CTRL_2_SW_RST_TX BIT(3)
43eba68f82SYendapally Reddy Dhananjaya Reddy #define SATA_TOP_CTRL_2_PHY_GLOBAL_RESET BIT(14)
44eba68f82SYendapally Reddy Dhananjaya Reddy #define SATA_TOP_CTRL_PHY_OFFS 0x8
45eba68f82SYendapally Reddy Dhananjaya Reddy #define SATA_TOP_MAX_PHYS 2
46eba68f82SYendapally Reddy Dhananjaya Reddy
47eba68f82SYendapally Reddy Dhananjaya Reddy #define SATA_FIRST_PORT_CTRL 0x700
48eba68f82SYendapally Reddy Dhananjaya Reddy #define SATA_NEXT_PORT_CTRL_OFFSET 0x80
49eba68f82SYendapally Reddy Dhananjaya Reddy #define SATA_PORT_PCTRL6(reg_base) (reg_base + 0x18)
50eba68f82SYendapally Reddy Dhananjaya Reddy
51eba68f82SYendapally Reddy Dhananjaya Reddy /* On big-endian MIPS, buses are reversed to big endian, so switch them back */
52eba68f82SYendapally Reddy Dhananjaya Reddy #if defined(CONFIG_MIPS) && defined(__BIG_ENDIAN)
53eba68f82SYendapally Reddy Dhananjaya Reddy #define DATA_ENDIAN 2 /* AHCI->DDR inbound accesses */
54eba68f82SYendapally Reddy Dhananjaya Reddy #define MMIO_ENDIAN 2 /* CPU->AHCI outbound accesses */
55eba68f82SYendapally Reddy Dhananjaya Reddy #else
56eba68f82SYendapally Reddy Dhananjaya Reddy #define DATA_ENDIAN 0
57eba68f82SYendapally Reddy Dhananjaya Reddy #define MMIO_ENDIAN 0
58eba68f82SYendapally Reddy Dhananjaya Reddy #endif
59eba68f82SYendapally Reddy Dhananjaya Reddy
60eba68f82SYendapally Reddy Dhananjaya Reddy #define BUS_CTRL_ENDIAN_CONF \
61eba68f82SYendapally Reddy Dhananjaya Reddy ((DATA_ENDIAN << DMADATA_ENDIAN_SHIFT) | \
62eba68f82SYendapally Reddy Dhananjaya Reddy (DATA_ENDIAN << DMADESC_ENDIAN_SHIFT) | \
63eba68f82SYendapally Reddy Dhananjaya Reddy (MMIO_ENDIAN << MMIO_ENDIAN_SHIFT))
64eba68f82SYendapally Reddy Dhananjaya Reddy
6536fffd6aSFlorian Fainelli #define BUS_CTRL_ENDIAN_NSP_CONF \
6636fffd6aSFlorian Fainelli (0x02 << DMADATA_ENDIAN_SHIFT | 0x02 << DMADESC_ENDIAN_SHIFT)
6736fffd6aSFlorian Fainelli
6836fffd6aSFlorian Fainelli #define BUS_CTRL_ENDIAN_CONF_MASK \
6936fffd6aSFlorian Fainelli (0x3 << MMIO_ENDIAN_SHIFT | 0x3 << DMADESC_ENDIAN_SHIFT | \
7036fffd6aSFlorian Fainelli 0x3 << DMADATA_ENDIAN_SHIFT | 0x3 << PIODATA_ENDIAN_SHIFT)
7136fffd6aSFlorian Fainelli
723ee2e6dcSYendapally Reddy Dhananjaya Reddy enum brcm_ahci_version {
733ee2e6dcSYendapally Reddy Dhananjaya Reddy BRCM_SATA_BCM7425 = 1,
743ee2e6dcSYendapally Reddy Dhananjaya Reddy BRCM_SATA_BCM7445,
753ee2e6dcSYendapally Reddy Dhananjaya Reddy BRCM_SATA_NSP,
76c345ec6aSFlorian Fainelli BRCM_SATA_BCM7216,
773ee2e6dcSYendapally Reddy Dhananjaya Reddy };
783ee2e6dcSYendapally Reddy Dhananjaya Reddy
79eba68f82SYendapally Reddy Dhananjaya Reddy enum brcm_ahci_quirks {
801a3d78cbSFlorian Fainelli BRCM_AHCI_QUIRK_SKIP_PHY_ENABLE = BIT(0),
81eba68f82SYendapally Reddy Dhananjaya Reddy };
82eba68f82SYendapally Reddy Dhananjaya Reddy
83eba68f82SYendapally Reddy Dhananjaya Reddy struct brcm_ahci_priv {
84eba68f82SYendapally Reddy Dhananjaya Reddy struct device *dev;
85eba68f82SYendapally Reddy Dhananjaya Reddy void __iomem *top_ctrl;
86eba68f82SYendapally Reddy Dhananjaya Reddy u32 port_mask;
87eba68f82SYendapally Reddy Dhananjaya Reddy u32 quirks;
883ee2e6dcSYendapally Reddy Dhananjaya Reddy enum brcm_ahci_version version;
89e8d6f9e5SJim Quinlan struct reset_control *rcdev_rescal;
90e8d6f9e5SJim Quinlan struct reset_control *rcdev_ahci;
91eba68f82SYendapally Reddy Dhananjaya Reddy };
92eba68f82SYendapally Reddy Dhananjaya Reddy
brcm_sata_readreg(void __iomem * addr)93eba68f82SYendapally Reddy Dhananjaya Reddy static inline u32 brcm_sata_readreg(void __iomem *addr)
94eba68f82SYendapally Reddy Dhananjaya Reddy {
95eba68f82SYendapally Reddy Dhananjaya Reddy /*
96eba68f82SYendapally Reddy Dhananjaya Reddy * MIPS endianness is configured by boot strap, which also reverses all
97eba68f82SYendapally Reddy Dhananjaya Reddy * bus endianness (i.e., big-endian CPU + big endian bus ==> native
98eba68f82SYendapally Reddy Dhananjaya Reddy * endian I/O).
99eba68f82SYendapally Reddy Dhananjaya Reddy *
100eba68f82SYendapally Reddy Dhananjaya Reddy * Other architectures (e.g., ARM) either do not support big endian, or
101eba68f82SYendapally Reddy Dhananjaya Reddy * else leave I/O in little endian mode.
102eba68f82SYendapally Reddy Dhananjaya Reddy */
103eba68f82SYendapally Reddy Dhananjaya Reddy if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN))
104eba68f82SYendapally Reddy Dhananjaya Reddy return __raw_readl(addr);
105eba68f82SYendapally Reddy Dhananjaya Reddy else
106eba68f82SYendapally Reddy Dhananjaya Reddy return readl_relaxed(addr);
107eba68f82SYendapally Reddy Dhananjaya Reddy }
108eba68f82SYendapally Reddy Dhananjaya Reddy
brcm_sata_writereg(u32 val,void __iomem * addr)109eba68f82SYendapally Reddy Dhananjaya Reddy static inline void brcm_sata_writereg(u32 val, void __iomem *addr)
110eba68f82SYendapally Reddy Dhananjaya Reddy {
111eba68f82SYendapally Reddy Dhananjaya Reddy /* See brcm_sata_readreg() comments */
112eba68f82SYendapally Reddy Dhananjaya Reddy if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN))
113eba68f82SYendapally Reddy Dhananjaya Reddy __raw_writel(val, addr);
114eba68f82SYendapally Reddy Dhananjaya Reddy else
115eba68f82SYendapally Reddy Dhananjaya Reddy writel_relaxed(val, addr);
116eba68f82SYendapally Reddy Dhananjaya Reddy }
117eba68f82SYendapally Reddy Dhananjaya Reddy
brcm_sata_alpm_init(struct ahci_host_priv * hpriv)118eba68f82SYendapally Reddy Dhananjaya Reddy static void brcm_sata_alpm_init(struct ahci_host_priv *hpriv)
119eba68f82SYendapally Reddy Dhananjaya Reddy {
120eba68f82SYendapally Reddy Dhananjaya Reddy struct brcm_ahci_priv *priv = hpriv->plat_data;
121da8fa9ccSDoug Berger u32 port_ctrl, host_caps;
122eba68f82SYendapally Reddy Dhananjaya Reddy int i;
123eba68f82SYendapally Reddy Dhananjaya Reddy
124eba68f82SYendapally Reddy Dhananjaya Reddy /* Enable support for ALPM */
125eba68f82SYendapally Reddy Dhananjaya Reddy host_caps = readl(hpriv->mmio + HOST_CAP);
126da8fa9ccSDoug Berger if (!(host_caps & HOST_CAP_ALPM))
127da8fa9ccSDoug Berger hpriv->flags |= AHCI_HFLAG_YES_ALPM;
128eba68f82SYendapally Reddy Dhananjaya Reddy
129eba68f82SYendapally Reddy Dhananjaya Reddy /*
130eba68f82SYendapally Reddy Dhananjaya Reddy * Adjust timeout to allow PLL sufficient time to lock while waking
131eba68f82SYendapally Reddy Dhananjaya Reddy * up from slumber mode.
132eba68f82SYendapally Reddy Dhananjaya Reddy */
133eba68f82SYendapally Reddy Dhananjaya Reddy for (i = 0, port_ctrl = SATA_FIRST_PORT_CTRL;
134eba68f82SYendapally Reddy Dhananjaya Reddy i < SATA_TOP_MAX_PHYS;
135eba68f82SYendapally Reddy Dhananjaya Reddy i++, port_ctrl += SATA_NEXT_PORT_CTRL_OFFSET) {
136eba68f82SYendapally Reddy Dhananjaya Reddy if (priv->port_mask & BIT(i))
137eba68f82SYendapally Reddy Dhananjaya Reddy writel(0xff1003fc,
138eba68f82SYendapally Reddy Dhananjaya Reddy hpriv->mmio + SATA_PORT_PCTRL6(port_ctrl));
139eba68f82SYendapally Reddy Dhananjaya Reddy }
140eba68f82SYendapally Reddy Dhananjaya Reddy }
141eba68f82SYendapally Reddy Dhananjaya Reddy
brcm_sata_phy_enable(struct brcm_ahci_priv * priv,int port)142eba68f82SYendapally Reddy Dhananjaya Reddy static void brcm_sata_phy_enable(struct brcm_ahci_priv *priv, int port)
143eba68f82SYendapally Reddy Dhananjaya Reddy {
144eba68f82SYendapally Reddy Dhananjaya Reddy void __iomem *phyctrl = priv->top_ctrl + SATA_TOP_CTRL_PHY_CTRL +
145eba68f82SYendapally Reddy Dhananjaya Reddy (port * SATA_TOP_CTRL_PHY_OFFS);
146eba68f82SYendapally Reddy Dhananjaya Reddy void __iomem *p;
147eba68f82SYendapally Reddy Dhananjaya Reddy u32 reg;
148eba68f82SYendapally Reddy Dhananjaya Reddy
149eba68f82SYendapally Reddy Dhananjaya Reddy if (priv->quirks & BRCM_AHCI_QUIRK_SKIP_PHY_ENABLE)
150eba68f82SYendapally Reddy Dhananjaya Reddy return;
151eba68f82SYendapally Reddy Dhananjaya Reddy
152eba68f82SYendapally Reddy Dhananjaya Reddy /* clear PHY_DEFAULT_POWER_STATE */
153eba68f82SYendapally Reddy Dhananjaya Reddy p = phyctrl + SATA_TOP_CTRL_PHY_CTRL_1;
154eba68f82SYendapally Reddy Dhananjaya Reddy reg = brcm_sata_readreg(p);
155eba68f82SYendapally Reddy Dhananjaya Reddy reg &= ~SATA_TOP_CTRL_1_PHY_DEFAULT_POWER_STATE;
156eba68f82SYendapally Reddy Dhananjaya Reddy brcm_sata_writereg(reg, p);
157eba68f82SYendapally Reddy Dhananjaya Reddy
158eba68f82SYendapally Reddy Dhananjaya Reddy /* reset the PHY digital logic */
159eba68f82SYendapally Reddy Dhananjaya Reddy p = phyctrl + SATA_TOP_CTRL_PHY_CTRL_2;
160eba68f82SYendapally Reddy Dhananjaya Reddy reg = brcm_sata_readreg(p);
161eba68f82SYendapally Reddy Dhananjaya Reddy reg &= ~(SATA_TOP_CTRL_2_SW_RST_MDIOREG | SATA_TOP_CTRL_2_SW_RST_OOB |
162eba68f82SYendapally Reddy Dhananjaya Reddy SATA_TOP_CTRL_2_SW_RST_RX);
163eba68f82SYendapally Reddy Dhananjaya Reddy reg |= SATA_TOP_CTRL_2_SW_RST_TX;
164eba68f82SYendapally Reddy Dhananjaya Reddy brcm_sata_writereg(reg, p);
165eba68f82SYendapally Reddy Dhananjaya Reddy reg = brcm_sata_readreg(p);
166eba68f82SYendapally Reddy Dhananjaya Reddy reg |= SATA_TOP_CTRL_2_PHY_GLOBAL_RESET;
167eba68f82SYendapally Reddy Dhananjaya Reddy brcm_sata_writereg(reg, p);
168eba68f82SYendapally Reddy Dhananjaya Reddy reg = brcm_sata_readreg(p);
169eba68f82SYendapally Reddy Dhananjaya Reddy reg &= ~SATA_TOP_CTRL_2_PHY_GLOBAL_RESET;
170eba68f82SYendapally Reddy Dhananjaya Reddy brcm_sata_writereg(reg, p);
171eba68f82SYendapally Reddy Dhananjaya Reddy (void)brcm_sata_readreg(p);
172eba68f82SYendapally Reddy Dhananjaya Reddy }
173eba68f82SYendapally Reddy Dhananjaya Reddy
brcm_sata_phy_disable(struct brcm_ahci_priv * priv,int port)174eba68f82SYendapally Reddy Dhananjaya Reddy static void brcm_sata_phy_disable(struct brcm_ahci_priv *priv, int port)
175eba68f82SYendapally Reddy Dhananjaya Reddy {
176eba68f82SYendapally Reddy Dhananjaya Reddy void __iomem *phyctrl = priv->top_ctrl + SATA_TOP_CTRL_PHY_CTRL +
177eba68f82SYendapally Reddy Dhananjaya Reddy (port * SATA_TOP_CTRL_PHY_OFFS);
178eba68f82SYendapally Reddy Dhananjaya Reddy void __iomem *p;
179eba68f82SYendapally Reddy Dhananjaya Reddy u32 reg;
180eba68f82SYendapally Reddy Dhananjaya Reddy
181eba68f82SYendapally Reddy Dhananjaya Reddy if (priv->quirks & BRCM_AHCI_QUIRK_SKIP_PHY_ENABLE)
182eba68f82SYendapally Reddy Dhananjaya Reddy return;
183eba68f82SYendapally Reddy Dhananjaya Reddy
184eba68f82SYendapally Reddy Dhananjaya Reddy /* power-off the PHY digital logic */
185eba68f82SYendapally Reddy Dhananjaya Reddy p = phyctrl + SATA_TOP_CTRL_PHY_CTRL_2;
186eba68f82SYendapally Reddy Dhananjaya Reddy reg = brcm_sata_readreg(p);
187eba68f82SYendapally Reddy Dhananjaya Reddy reg |= (SATA_TOP_CTRL_2_SW_RST_MDIOREG | SATA_TOP_CTRL_2_SW_RST_OOB |
188eba68f82SYendapally Reddy Dhananjaya Reddy SATA_TOP_CTRL_2_SW_RST_RX | SATA_TOP_CTRL_2_SW_RST_TX |
189eba68f82SYendapally Reddy Dhananjaya Reddy SATA_TOP_CTRL_2_PHY_GLOBAL_RESET);
190eba68f82SYendapally Reddy Dhananjaya Reddy brcm_sata_writereg(reg, p);
191eba68f82SYendapally Reddy Dhananjaya Reddy
192eba68f82SYendapally Reddy Dhananjaya Reddy /* set PHY_DEFAULT_POWER_STATE */
193eba68f82SYendapally Reddy Dhananjaya Reddy p = phyctrl + SATA_TOP_CTRL_PHY_CTRL_1;
194eba68f82SYendapally Reddy Dhananjaya Reddy reg = brcm_sata_readreg(p);
195eba68f82SYendapally Reddy Dhananjaya Reddy reg |= SATA_TOP_CTRL_1_PHY_DEFAULT_POWER_STATE;
196eba68f82SYendapally Reddy Dhananjaya Reddy brcm_sata_writereg(reg, p);
197eba68f82SYendapally Reddy Dhananjaya Reddy }
198eba68f82SYendapally Reddy Dhananjaya Reddy
brcm_sata_phys_enable(struct brcm_ahci_priv * priv)199eba68f82SYendapally Reddy Dhananjaya Reddy static void brcm_sata_phys_enable(struct brcm_ahci_priv *priv)
200eba68f82SYendapally Reddy Dhananjaya Reddy {
201eba68f82SYendapally Reddy Dhananjaya Reddy int i;
202eba68f82SYendapally Reddy Dhananjaya Reddy
203eba68f82SYendapally Reddy Dhananjaya Reddy for (i = 0; i < SATA_TOP_MAX_PHYS; i++)
204eba68f82SYendapally Reddy Dhananjaya Reddy if (priv->port_mask & BIT(i))
205eba68f82SYendapally Reddy Dhananjaya Reddy brcm_sata_phy_enable(priv, i);
206eba68f82SYendapally Reddy Dhananjaya Reddy }
207eba68f82SYendapally Reddy Dhananjaya Reddy
brcm_sata_phys_disable(struct brcm_ahci_priv * priv)208eba68f82SYendapally Reddy Dhananjaya Reddy static void brcm_sata_phys_disable(struct brcm_ahci_priv *priv)
209eba68f82SYendapally Reddy Dhananjaya Reddy {
210eba68f82SYendapally Reddy Dhananjaya Reddy int i;
211eba68f82SYendapally Reddy Dhananjaya Reddy
212eba68f82SYendapally Reddy Dhananjaya Reddy for (i = 0; i < SATA_TOP_MAX_PHYS; i++)
213eba68f82SYendapally Reddy Dhananjaya Reddy if (priv->port_mask & BIT(i))
214eba68f82SYendapally Reddy Dhananjaya Reddy brcm_sata_phy_disable(priv, i);
215eba68f82SYendapally Reddy Dhananjaya Reddy }
216eba68f82SYendapally Reddy Dhananjaya Reddy
brcm_ahci_get_portmask(struct ahci_host_priv * hpriv,struct brcm_ahci_priv * priv)217c0cdf2acSFlorian Fainelli static u32 brcm_ahci_get_portmask(struct ahci_host_priv *hpriv,
218eba68f82SYendapally Reddy Dhananjaya Reddy struct brcm_ahci_priv *priv)
219eba68f82SYendapally Reddy Dhananjaya Reddy {
220eba68f82SYendapally Reddy Dhananjaya Reddy u32 impl;
221eba68f82SYendapally Reddy Dhananjaya Reddy
222c0cdf2acSFlorian Fainelli impl = readl(hpriv->mmio + HOST_PORTS_IMPL);
223eba68f82SYendapally Reddy Dhananjaya Reddy
224eba68f82SYendapally Reddy Dhananjaya Reddy if (fls(impl) > SATA_TOP_MAX_PHYS)
225eba68f82SYendapally Reddy Dhananjaya Reddy dev_warn(priv->dev, "warning: more ports than PHYs (%#x)\n",
226eba68f82SYendapally Reddy Dhananjaya Reddy impl);
227eba68f82SYendapally Reddy Dhananjaya Reddy else if (!impl)
228eba68f82SYendapally Reddy Dhananjaya Reddy dev_info(priv->dev, "no ports found\n");
229eba68f82SYendapally Reddy Dhananjaya Reddy
230eba68f82SYendapally Reddy Dhananjaya Reddy return impl;
231eba68f82SYendapally Reddy Dhananjaya Reddy }
232eba68f82SYendapally Reddy Dhananjaya Reddy
brcm_sata_init(struct brcm_ahci_priv * priv)233eba68f82SYendapally Reddy Dhananjaya Reddy static void brcm_sata_init(struct brcm_ahci_priv *priv)
234eba68f82SYendapally Reddy Dhananjaya Reddy {
2353ee2e6dcSYendapally Reddy Dhananjaya Reddy void __iomem *ctrl = priv->top_ctrl + SATA_TOP_CTRL_BUS_CTRL;
23636fffd6aSFlorian Fainelli u32 data;
2373ee2e6dcSYendapally Reddy Dhananjaya Reddy
238eba68f82SYendapally Reddy Dhananjaya Reddy /* Configure endianness */
23936fffd6aSFlorian Fainelli data = brcm_sata_readreg(ctrl);
24036fffd6aSFlorian Fainelli data &= ~BUS_CTRL_ENDIAN_CONF_MASK;
24136fffd6aSFlorian Fainelli if (priv->version == BRCM_SATA_NSP)
24236fffd6aSFlorian Fainelli data |= BUS_CTRL_ENDIAN_NSP_CONF;
24336fffd6aSFlorian Fainelli else
24436fffd6aSFlorian Fainelli data |= BUS_CTRL_ENDIAN_CONF;
2453ee2e6dcSYendapally Reddy Dhananjaya Reddy brcm_sata_writereg(data, ctrl);
246eba68f82SYendapally Reddy Dhananjaya Reddy }
247eba68f82SYendapally Reddy Dhananjaya Reddy
brcm_ahci_read_id(struct ata_device * dev,struct ata_taskfile * tf,__le16 * id)248eb73390aSFlorian Fainelli static unsigned int brcm_ahci_read_id(struct ata_device *dev,
2490561e514SDamien Le Moal struct ata_taskfile *tf, __le16 *id)
250eb73390aSFlorian Fainelli {
251eb73390aSFlorian Fainelli struct ata_port *ap = dev->link->ap;
252eb73390aSFlorian Fainelli struct ata_host *host = ap->host;
253eb73390aSFlorian Fainelli struct ahci_host_priv *hpriv = host->private_data;
254eb73390aSFlorian Fainelli struct brcm_ahci_priv *priv = hpriv->plat_data;
255eb73390aSFlorian Fainelli void __iomem *mmio = hpriv->mmio;
256eb73390aSFlorian Fainelli unsigned int err_mask;
257eb73390aSFlorian Fainelli unsigned long flags;
258eb73390aSFlorian Fainelli int i, rc;
259eb73390aSFlorian Fainelli u32 ctl;
260eb73390aSFlorian Fainelli
261eb73390aSFlorian Fainelli /* Try to read the device ID and, if this fails, proceed with the
262eb73390aSFlorian Fainelli * recovery sequence below
263eb73390aSFlorian Fainelli */
264eb73390aSFlorian Fainelli err_mask = ata_do_dev_read_id(dev, tf, id);
265eb73390aSFlorian Fainelli if (likely(!err_mask))
266eb73390aSFlorian Fainelli return err_mask;
267eb73390aSFlorian Fainelli
268eb73390aSFlorian Fainelli /* Disable host interrupts */
269eb73390aSFlorian Fainelli spin_lock_irqsave(&host->lock, flags);
270eb73390aSFlorian Fainelli ctl = readl(mmio + HOST_CTL);
271eb73390aSFlorian Fainelli ctl &= ~HOST_IRQ_EN;
272eb73390aSFlorian Fainelli writel(ctl, mmio + HOST_CTL);
273eb73390aSFlorian Fainelli readl(mmio + HOST_CTL); /* flush */
274eb73390aSFlorian Fainelli spin_unlock_irqrestore(&host->lock, flags);
275eb73390aSFlorian Fainelli
276eb73390aSFlorian Fainelli /* Perform the SATA PHY reset sequence */
277eb73390aSFlorian Fainelli brcm_sata_phy_disable(priv, ap->port_no);
278eb73390aSFlorian Fainelli
279bf0e5013SFlorian Fainelli /* Reset the SATA clock */
280bf0e5013SFlorian Fainelli ahci_platform_disable_clks(hpriv);
281bf0e5013SFlorian Fainelli msleep(10);
282bf0e5013SFlorian Fainelli
283bf0e5013SFlorian Fainelli ahci_platform_enable_clks(hpriv);
284bf0e5013SFlorian Fainelli msleep(10);
285bf0e5013SFlorian Fainelli
286eb73390aSFlorian Fainelli /* Bring the PHY back on */
287eb73390aSFlorian Fainelli brcm_sata_phy_enable(priv, ap->port_no);
288eb73390aSFlorian Fainelli
289eb73390aSFlorian Fainelli /* Re-initialize and calibrate the PHY */
290eb73390aSFlorian Fainelli for (i = 0; i < hpriv->nports; i++) {
291eb73390aSFlorian Fainelli rc = phy_init(hpriv->phys[i]);
292eb73390aSFlorian Fainelli if (rc)
293eb73390aSFlorian Fainelli goto disable_phys;
294eb73390aSFlorian Fainelli
295eb73390aSFlorian Fainelli rc = phy_calibrate(hpriv->phys[i]);
296eb73390aSFlorian Fainelli if (rc) {
297eb73390aSFlorian Fainelli phy_exit(hpriv->phys[i]);
298eb73390aSFlorian Fainelli goto disable_phys;
299eb73390aSFlorian Fainelli }
300eb73390aSFlorian Fainelli }
301eb73390aSFlorian Fainelli
302eb73390aSFlorian Fainelli /* Re-enable host interrupts */
303eb73390aSFlorian Fainelli spin_lock_irqsave(&host->lock, flags);
304eb73390aSFlorian Fainelli ctl = readl(mmio + HOST_CTL);
305eb73390aSFlorian Fainelli ctl |= HOST_IRQ_EN;
306eb73390aSFlorian Fainelli writel(ctl, mmio + HOST_CTL);
307eb73390aSFlorian Fainelli readl(mmio + HOST_CTL); /* flush */
308eb73390aSFlorian Fainelli spin_unlock_irqrestore(&host->lock, flags);
309eb73390aSFlorian Fainelli
310eb73390aSFlorian Fainelli return ata_do_dev_read_id(dev, tf, id);
311eb73390aSFlorian Fainelli
312eb73390aSFlorian Fainelli disable_phys:
313eb73390aSFlorian Fainelli while (--i >= 0) {
314eb73390aSFlorian Fainelli phy_power_off(hpriv->phys[i]);
315eb73390aSFlorian Fainelli phy_exit(hpriv->phys[i]);
316eb73390aSFlorian Fainelli }
317eb73390aSFlorian Fainelli
318eb73390aSFlorian Fainelli return AC_ERR_OTHER;
319eb73390aSFlorian Fainelli }
320eb73390aSFlorian Fainelli
brcm_ahci_host_stop(struct ata_host * host)321eb73390aSFlorian Fainelli static void brcm_ahci_host_stop(struct ata_host *host)
322eb73390aSFlorian Fainelli {
323eb73390aSFlorian Fainelli struct ahci_host_priv *hpriv = host->private_data;
324eb73390aSFlorian Fainelli
325eb73390aSFlorian Fainelli ahci_platform_disable_resources(hpriv);
326eb73390aSFlorian Fainelli }
327eb73390aSFlorian Fainelli
328eb73390aSFlorian Fainelli static struct ata_port_operations ahci_brcm_platform_ops = {
329eb73390aSFlorian Fainelli .inherits = &ahci_ops,
330eb73390aSFlorian Fainelli .host_stop = brcm_ahci_host_stop,
331eb73390aSFlorian Fainelli .read_id = brcm_ahci_read_id,
332eb73390aSFlorian Fainelli };
333eb73390aSFlorian Fainelli
334eb73390aSFlorian Fainelli static const struct ata_port_info ahci_brcm_port_info = {
335eb73390aSFlorian Fainelli .flags = AHCI_FLAG_COMMON | ATA_FLAG_NO_DIPM,
336b9ba367cSPaul Menzel .link_flags = ATA_LFLAG_NO_DEBOUNCE_DELAY,
337eb73390aSFlorian Fainelli .pio_mask = ATA_PIO4,
338eb73390aSFlorian Fainelli .udma_mask = ATA_UDMA6,
339eb73390aSFlorian Fainelli .port_ops = &ahci_brcm_platform_ops,
340eb73390aSFlorian Fainelli };
341eb73390aSFlorian Fainelli
brcm_ahci_suspend(struct device * dev)342eba68f82SYendapally Reddy Dhananjaya Reddy static int brcm_ahci_suspend(struct device *dev)
343eba68f82SYendapally Reddy Dhananjaya Reddy {
344eba68f82SYendapally Reddy Dhananjaya Reddy struct ata_host *host = dev_get_drvdata(dev);
345eba68f82SYendapally Reddy Dhananjaya Reddy struct ahci_host_priv *hpriv = host->private_data;
346eba68f82SYendapally Reddy Dhananjaya Reddy struct brcm_ahci_priv *priv = hpriv->plat_data;
3473c696ac4SFlorian Fainelli int ret;
348eba68f82SYendapally Reddy Dhananjaya Reddy
349eba68f82SYendapally Reddy Dhananjaya Reddy brcm_sata_phys_disable(priv);
350c0cdf2acSFlorian Fainelli
351ed87ad19SArnd Bergmann if (IS_ENABLED(CONFIG_PM_SLEEP))
3523c696ac4SFlorian Fainelli ret = ahci_platform_suspend(dev);
353ed87ad19SArnd Bergmann else
354ed87ad19SArnd Bergmann ret = 0;
3553c696ac4SFlorian Fainelli
356e8d6f9e5SJim Quinlan reset_control_assert(priv->rcdev_ahci);
357e8d6f9e5SJim Quinlan reset_control_rearm(priv->rcdev_rescal);
3583c696ac4SFlorian Fainelli
3593c696ac4SFlorian Fainelli return ret;
360eba68f82SYendapally Reddy Dhananjaya Reddy }
361eba68f82SYendapally Reddy Dhananjaya Reddy
brcm_ahci_resume(struct device * dev)362ed87ad19SArnd Bergmann static int __maybe_unused brcm_ahci_resume(struct device *dev)
363eba68f82SYendapally Reddy Dhananjaya Reddy {
364eba68f82SYendapally Reddy Dhananjaya Reddy struct ata_host *host = dev_get_drvdata(dev);
365eba68f82SYendapally Reddy Dhananjaya Reddy struct ahci_host_priv *hpriv = host->private_data;
366eba68f82SYendapally Reddy Dhananjaya Reddy struct brcm_ahci_priv *priv = hpriv->plat_data;
3673c696ac4SFlorian Fainelli int ret = 0;
3683c696ac4SFlorian Fainelli
369e8d6f9e5SJim Quinlan ret = reset_control_deassert(priv->rcdev_ahci);
370e8d6f9e5SJim Quinlan if (ret)
371e8d6f9e5SJim Quinlan return ret;
372e8d6f9e5SJim Quinlan ret = reset_control_reset(priv->rcdev_rescal);
3733c696ac4SFlorian Fainelli if (ret)
3743c696ac4SFlorian Fainelli return ret;
375c0cdf2acSFlorian Fainelli
376c0cdf2acSFlorian Fainelli /* Make sure clocks are turned on before re-configuration */
377c0cdf2acSFlorian Fainelli ret = ahci_platform_enable_clks(hpriv);
378c0cdf2acSFlorian Fainelli if (ret)
379c0cdf2acSFlorian Fainelli return ret;
380eba68f82SYendapally Reddy Dhananjaya Reddy
38110340f8dSFlorian Fainelli ret = ahci_platform_enable_regulators(hpriv);
38210340f8dSFlorian Fainelli if (ret)
38310340f8dSFlorian Fainelli goto out_disable_clks;
38410340f8dSFlorian Fainelli
385eba68f82SYendapally Reddy Dhananjaya Reddy brcm_sata_init(priv);
386eba68f82SYendapally Reddy Dhananjaya Reddy brcm_sata_phys_enable(priv);
387eba68f82SYendapally Reddy Dhananjaya Reddy brcm_sata_alpm_init(hpriv);
388c0cdf2acSFlorian Fainelli
389c0cdf2acSFlorian Fainelli /* Since we had to enable clocks earlier on, we cannot use
390c0cdf2acSFlorian Fainelli * ahci_platform_resume() as-is since a second call to
391c0cdf2acSFlorian Fainelli * ahci_platform_enable_resources() would bump up the resources
392c0cdf2acSFlorian Fainelli * (regulators, clocks, PHYs) count artificially so we copy the part
393c0cdf2acSFlorian Fainelli * after ahci_platform_enable_resources().
394c0cdf2acSFlorian Fainelli */
395c0cdf2acSFlorian Fainelli ret = ahci_platform_enable_phys(hpriv);
396c0cdf2acSFlorian Fainelli if (ret)
397c0cdf2acSFlorian Fainelli goto out_disable_phys;
398c0cdf2acSFlorian Fainelli
399c0cdf2acSFlorian Fainelli ret = ahci_platform_resume_host(dev);
400c0cdf2acSFlorian Fainelli if (ret)
401c0cdf2acSFlorian Fainelli goto out_disable_platform_phys;
402c0cdf2acSFlorian Fainelli
403c0cdf2acSFlorian Fainelli /* We resumed so update PM runtime state */
404c0cdf2acSFlorian Fainelli pm_runtime_disable(dev);
405c0cdf2acSFlorian Fainelli pm_runtime_set_active(dev);
406c0cdf2acSFlorian Fainelli pm_runtime_enable(dev);
407c0cdf2acSFlorian Fainelli
408c0cdf2acSFlorian Fainelli return 0;
409c0cdf2acSFlorian Fainelli
410c0cdf2acSFlorian Fainelli out_disable_platform_phys:
411c0cdf2acSFlorian Fainelli ahci_platform_disable_phys(hpriv);
412c0cdf2acSFlorian Fainelli out_disable_phys:
413c0cdf2acSFlorian Fainelli brcm_sata_phys_disable(priv);
41410340f8dSFlorian Fainelli ahci_platform_disable_regulators(hpriv);
41510340f8dSFlorian Fainelli out_disable_clks:
416c0cdf2acSFlorian Fainelli ahci_platform_disable_clks(hpriv);
417c0cdf2acSFlorian Fainelli return ret;
418eba68f82SYendapally Reddy Dhananjaya Reddy }
419eba68f82SYendapally Reddy Dhananjaya Reddy
420*25df73d9SBart Van Assche static const struct scsi_host_template ahci_platform_sht = {
421eba68f82SYendapally Reddy Dhananjaya Reddy AHCI_SHT(DRV_NAME),
422eba68f82SYendapally Reddy Dhananjaya Reddy };
423eba68f82SYendapally Reddy Dhananjaya Reddy
4243ee2e6dcSYendapally Reddy Dhananjaya Reddy static const struct of_device_id ahci_of_match[] = {
4253ee2e6dcSYendapally Reddy Dhananjaya Reddy {.compatible = "brcm,bcm7425-ahci", .data = (void *)BRCM_SATA_BCM7425},
4263ee2e6dcSYendapally Reddy Dhananjaya Reddy {.compatible = "brcm,bcm7445-ahci", .data = (void *)BRCM_SATA_BCM7445},
427fb8506f1SFlorian Fainelli {.compatible = "brcm,bcm63138-ahci", .data = (void *)BRCM_SATA_BCM7445},
4283ee2e6dcSYendapally Reddy Dhananjaya Reddy {.compatible = "brcm,bcm-nsp-ahci", .data = (void *)BRCM_SATA_NSP},
429c345ec6aSFlorian Fainelli {.compatible = "brcm,bcm7216-ahci", .data = (void *)BRCM_SATA_BCM7216},
4305e776d7bSGeert Uytterhoeven { /* sentinel */ }
4313ee2e6dcSYendapally Reddy Dhananjaya Reddy };
4323ee2e6dcSYendapally Reddy Dhananjaya Reddy MODULE_DEVICE_TABLE(of, ahci_of_match);
4333ee2e6dcSYendapally Reddy Dhananjaya Reddy
brcm_ahci_probe(struct platform_device * pdev)434eba68f82SYendapally Reddy Dhananjaya Reddy static int brcm_ahci_probe(struct platform_device *pdev)
435eba68f82SYendapally Reddy Dhananjaya Reddy {
4363ee2e6dcSYendapally Reddy Dhananjaya Reddy const struct of_device_id *of_id;
437eba68f82SYendapally Reddy Dhananjaya Reddy struct device *dev = &pdev->dev;
438eba68f82SYendapally Reddy Dhananjaya Reddy struct brcm_ahci_priv *priv;
439eba68f82SYendapally Reddy Dhananjaya Reddy struct ahci_host_priv *hpriv;
440eba68f82SYendapally Reddy Dhananjaya Reddy struct resource *res;
441eba68f82SYendapally Reddy Dhananjaya Reddy int ret;
442eba68f82SYendapally Reddy Dhananjaya Reddy
443eba68f82SYendapally Reddy Dhananjaya Reddy priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
444eba68f82SYendapally Reddy Dhananjaya Reddy if (!priv)
445eba68f82SYendapally Reddy Dhananjaya Reddy return -ENOMEM;
4463ee2e6dcSYendapally Reddy Dhananjaya Reddy
4473ee2e6dcSYendapally Reddy Dhananjaya Reddy of_id = of_match_node(ahci_of_match, pdev->dev.of_node);
4483ee2e6dcSYendapally Reddy Dhananjaya Reddy if (!of_id)
4493ee2e6dcSYendapally Reddy Dhananjaya Reddy return -ENODEV;
4503ee2e6dcSYendapally Reddy Dhananjaya Reddy
4517d7b0c85SDamien Le Moal priv->version = (unsigned long)of_id->data;
452eba68f82SYendapally Reddy Dhananjaya Reddy priv->dev = dev;
453eba68f82SYendapally Reddy Dhananjaya Reddy
454eba68f82SYendapally Reddy Dhananjaya Reddy res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "top-ctrl");
455eba68f82SYendapally Reddy Dhananjaya Reddy priv->top_ctrl = devm_ioremap_resource(dev, res);
456eba68f82SYendapally Reddy Dhananjaya Reddy if (IS_ERR(priv->top_ctrl))
457eba68f82SYendapally Reddy Dhananjaya Reddy return PTR_ERR(priv->top_ctrl);
458eba68f82SYendapally Reddy Dhananjaya Reddy
459e8d6f9e5SJim Quinlan if (priv->version == BRCM_SATA_BCM7216) {
460e8d6f9e5SJim Quinlan priv->rcdev_rescal = devm_reset_control_get_optional_shared(
461e8d6f9e5SJim Quinlan &pdev->dev, "rescal");
462e8d6f9e5SJim Quinlan if (IS_ERR(priv->rcdev_rescal))
463e8d6f9e5SJim Quinlan return PTR_ERR(priv->rcdev_rescal);
464e8d6f9e5SJim Quinlan }
465e8d6f9e5SJim Quinlan priv->rcdev_ahci = devm_reset_control_get_optional(&pdev->dev, "ahci");
466e8d6f9e5SJim Quinlan if (IS_ERR(priv->rcdev_ahci))
467e8d6f9e5SJim Quinlan return PTR_ERR(priv->rcdev_ahci);
4686fedae3cSArnd Bergmann
469c0cdf2acSFlorian Fainelli hpriv = ahci_platform_get_resources(pdev, 0);
4701a0600d1SFlorian Fainelli if (IS_ERR(hpriv))
4711a0600d1SFlorian Fainelli return PTR_ERR(hpriv);
472c0cdf2acSFlorian Fainelli
4731a3d78cbSFlorian Fainelli hpriv->plat_data = priv;
4741a3d78cbSFlorian Fainelli hpriv->flags = AHCI_HFLAG_WAKE_BEFORE_STOP | AHCI_HFLAG_NO_WRITE_TO_RO;
4751a3d78cbSFlorian Fainelli
4761a3d78cbSFlorian Fainelli switch (priv->version) {
4771a3d78cbSFlorian Fainelli case BRCM_SATA_BCM7425:
4781a3d78cbSFlorian Fainelli hpriv->flags |= AHCI_HFLAG_DELAY_ENGINE;
479df561f66SGustavo A. R. Silva fallthrough;
4801a3d78cbSFlorian Fainelli case BRCM_SATA_NSP:
4811a3d78cbSFlorian Fainelli hpriv->flags |= AHCI_HFLAG_NO_NCQ;
4821a3d78cbSFlorian Fainelli priv->quirks |= BRCM_AHCI_QUIRK_SKIP_PHY_ENABLE;
4831a3d78cbSFlorian Fainelli break;
4841a3d78cbSFlorian Fainelli default:
4851a3d78cbSFlorian Fainelli break;
4861a3d78cbSFlorian Fainelli }
4871a3d78cbSFlorian Fainelli
488e8d6f9e5SJim Quinlan ret = reset_control_reset(priv->rcdev_rescal);
489e8d6f9e5SJim Quinlan if (ret)
490e8d6f9e5SJim Quinlan return ret;
491e8d6f9e5SJim Quinlan ret = reset_control_deassert(priv->rcdev_ahci);
4921a0600d1SFlorian Fainelli if (ret)
4931a0600d1SFlorian Fainelli return ret;
4941a0600d1SFlorian Fainelli
495c0cdf2acSFlorian Fainelli ret = ahci_platform_enable_clks(hpriv);
496c0cdf2acSFlorian Fainelli if (ret)
497c0cdf2acSFlorian Fainelli goto out_reset;
498c0cdf2acSFlorian Fainelli
49910340f8dSFlorian Fainelli ret = ahci_platform_enable_regulators(hpriv);
50010340f8dSFlorian Fainelli if (ret)
50110340f8dSFlorian Fainelli goto out_disable_clks;
50210340f8dSFlorian Fainelli
503c0cdf2acSFlorian Fainelli /* Must be first so as to configure endianness including that
504c0cdf2acSFlorian Fainelli * of the standard AHCI register space.
505c0cdf2acSFlorian Fainelli */
506eba68f82SYendapally Reddy Dhananjaya Reddy brcm_sata_init(priv);
507eba68f82SYendapally Reddy Dhananjaya Reddy
508c0cdf2acSFlorian Fainelli /* Initializes priv->port_mask which is used below */
509c0cdf2acSFlorian Fainelli priv->port_mask = brcm_ahci_get_portmask(hpriv, priv);
510c0cdf2acSFlorian Fainelli if (!priv->port_mask) {
511c0cdf2acSFlorian Fainelli ret = -ENODEV;
51210340f8dSFlorian Fainelli goto out_disable_regulators;
513c0cdf2acSFlorian Fainelli }
514eba68f82SYendapally Reddy Dhananjaya Reddy
515c0cdf2acSFlorian Fainelli /* Must be done before ahci_platform_enable_phys() */
516eba68f82SYendapally Reddy Dhananjaya Reddy brcm_sata_phys_enable(priv);
517eba68f82SYendapally Reddy Dhananjaya Reddy
518eba68f82SYendapally Reddy Dhananjaya Reddy brcm_sata_alpm_init(hpriv);
519eba68f82SYendapally Reddy Dhananjaya Reddy
520c0cdf2acSFlorian Fainelli ret = ahci_platform_enable_phys(hpriv);
521c0cdf2acSFlorian Fainelli if (ret)
522c0cdf2acSFlorian Fainelli goto out_disable_phys;
523c0cdf2acSFlorian Fainelli
524eba68f82SYendapally Reddy Dhananjaya Reddy ret = ahci_platform_init_host(pdev, hpriv, &ahci_brcm_port_info,
525eba68f82SYendapally Reddy Dhananjaya Reddy &ahci_platform_sht);
526eba68f82SYendapally Reddy Dhananjaya Reddy if (ret)
527c0cdf2acSFlorian Fainelli goto out_disable_platform_phys;
528eba68f82SYendapally Reddy Dhananjaya Reddy
529eba68f82SYendapally Reddy Dhananjaya Reddy dev_info(dev, "Broadcom AHCI SATA3 registered\n");
530eba68f82SYendapally Reddy Dhananjaya Reddy
531eba68f82SYendapally Reddy Dhananjaya Reddy return 0;
532c0cdf2acSFlorian Fainelli
533c0cdf2acSFlorian Fainelli out_disable_platform_phys:
534c0cdf2acSFlorian Fainelli ahci_platform_disable_phys(hpriv);
535c0cdf2acSFlorian Fainelli out_disable_phys:
536c0cdf2acSFlorian Fainelli brcm_sata_phys_disable(priv);
53710340f8dSFlorian Fainelli out_disable_regulators:
53810340f8dSFlorian Fainelli ahci_platform_disable_regulators(hpriv);
539c0cdf2acSFlorian Fainelli out_disable_clks:
540c0cdf2acSFlorian Fainelli ahci_platform_disable_clks(hpriv);
541c0cdf2acSFlorian Fainelli out_reset:
542e8d6f9e5SJim Quinlan reset_control_assert(priv->rcdev_ahci);
543e8d6f9e5SJim Quinlan reset_control_rearm(priv->rcdev_rescal);
544c0cdf2acSFlorian Fainelli return ret;
545eba68f82SYendapally Reddy Dhananjaya Reddy }
546eba68f82SYendapally Reddy Dhananjaya Reddy
brcm_ahci_remove(struct platform_device * pdev)547eba68f82SYendapally Reddy Dhananjaya Reddy static void brcm_ahci_remove(struct platform_device *pdev)
548eba68f82SYendapally Reddy Dhananjaya Reddy {
549eba68f82SYendapally Reddy Dhananjaya Reddy struct ata_host *host = dev_get_drvdata(&pdev->dev);
550eba68f82SYendapally Reddy Dhananjaya Reddy struct ahci_host_priv *hpriv = host->private_data;
551eba68f82SYendapally Reddy Dhananjaya Reddy struct brcm_ahci_priv *priv = hpriv->plat_data;
552eba68f82SYendapally Reddy Dhananjaya Reddy
553c0cdf2acSFlorian Fainelli brcm_sata_phys_disable(priv);
554c0cdf2acSFlorian Fainelli
555ec194bdbSMinghao Chi ata_platform_remove_one(pdev);
556eba68f82SYendapally Reddy Dhananjaya Reddy }
557eba68f82SYendapally Reddy Dhananjaya Reddy
brcm_ahci_shutdown(struct platform_device * pdev)5587de9b168SFlorian Fainelli static void brcm_ahci_shutdown(struct platform_device *pdev)
5597de9b168SFlorian Fainelli {
5607de9b168SFlorian Fainelli int ret;
5617de9b168SFlorian Fainelli
5627de9b168SFlorian Fainelli /* All resources releasing happens via devres, but our device, unlike a
5637de9b168SFlorian Fainelli * proper remove is not disappearing, therefore using
5647de9b168SFlorian Fainelli * brcm_ahci_suspend() here which does explicit power management is
5657de9b168SFlorian Fainelli * appropriate.
5667de9b168SFlorian Fainelli */
5677de9b168SFlorian Fainelli ret = brcm_ahci_suspend(&pdev->dev);
5687de9b168SFlorian Fainelli if (ret)
5697de9b168SFlorian Fainelli dev_err(&pdev->dev, "failed to shutdown\n");
5707de9b168SFlorian Fainelli }
5717de9b168SFlorian Fainelli
572eba68f82SYendapally Reddy Dhananjaya Reddy static SIMPLE_DEV_PM_OPS(ahci_brcm_pm_ops, brcm_ahci_suspend, brcm_ahci_resume);
573eba68f82SYendapally Reddy Dhananjaya Reddy
574eba68f82SYendapally Reddy Dhananjaya Reddy static struct platform_driver brcm_ahci_driver = {
575eba68f82SYendapally Reddy Dhananjaya Reddy .probe = brcm_ahci_probe,
576eba68f82SYendapally Reddy Dhananjaya Reddy .remove_new = brcm_ahci_remove,
5777de9b168SFlorian Fainelli .shutdown = brcm_ahci_shutdown,
578eba68f82SYendapally Reddy Dhananjaya Reddy .driver = {
579eba68f82SYendapally Reddy Dhananjaya Reddy .name = DRV_NAME,
580eba68f82SYendapally Reddy Dhananjaya Reddy .of_match_table = ahci_of_match,
581eba68f82SYendapally Reddy Dhananjaya Reddy .pm = &ahci_brcm_pm_ops,
582eba68f82SYendapally Reddy Dhananjaya Reddy },
583eba68f82SYendapally Reddy Dhananjaya Reddy };
584eba68f82SYendapally Reddy Dhananjaya Reddy module_platform_driver(brcm_ahci_driver);
585eba68f82SYendapally Reddy Dhananjaya Reddy
586eba68f82SYendapally Reddy Dhananjaya Reddy MODULE_DESCRIPTION("Broadcom SATA3 AHCI Controller Driver");
587eba68f82SYendapally Reddy Dhananjaya Reddy MODULE_AUTHOR("Brian Norris");
588eba68f82SYendapally Reddy Dhananjaya Reddy MODULE_LICENSE("GPL");
589eba68f82SYendapally Reddy Dhananjaya Reddy MODULE_ALIAS("platform:sata-brcmstb");
590