Blame view

drivers/ata/ahci_brcm.c 15 KB
3e0a4e858   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-or-later
766a2d979   Brian Norris   ata: add Broadcom...
2
3
4
5
  /*
   * Broadcom SATA3 AHCI Controller Driver
   *
   * Copyright © 2009-2015 Broadcom Corporation
766a2d979   Brian Norris   ata: add Broadcom...
6
7
8
9
10
11
12
13
14
15
16
17
18
   */
  
  #include <linux/ahci_platform.h>
  #include <linux/compiler.h>
  #include <linux/device.h>
  #include <linux/init.h>
  #include <linux/interrupt.h>
  #include <linux/io.h>
  #include <linux/kernel.h>
  #include <linux/libata.h>
  #include <linux/module.h>
  #include <linux/of.h>
  #include <linux/platform_device.h>
2b2c47d9e   Florian Fainelli   ata: ahci_brcm: A...
19
  #include <linux/reset.h>
766a2d979   Brian Norris   ata: add Broadcom...
20
21
22
23
24
25
26
27
28
29
30
31
32
33
  #include <linux/string.h>
  
  #include "ahci.h"
  
  #define DRV_NAME					"brcm-ahci"
  
  #define SATA_TOP_CTRL_VERSION				0x0
  #define SATA_TOP_CTRL_BUS_CTRL				0x4
   #define MMIO_ENDIAN_SHIFT				0 /* CPU->AHCI */
   #define DMADESC_ENDIAN_SHIFT				2 /* AHCI->DDR */
   #define DMADATA_ENDIAN_SHIFT				4 /* AHCI->DDR */
   #define PIODATA_ENDIAN_SHIFT				6
    #define ENDIAN_SWAP_NONE				0
    #define ENDIAN_SWAP_FULL				2
766a2d979   Brian Norris   ata: add Broadcom...
34
35
36
37
38
39
40
41
42
43
44
45
  #define SATA_TOP_CTRL_TP_CTRL				0x8
  #define SATA_TOP_CTRL_PHY_CTRL				0xc
   #define SATA_TOP_CTRL_PHY_CTRL_1			0x0
    #define SATA_TOP_CTRL_1_PHY_DEFAULT_POWER_STATE	BIT(14)
   #define SATA_TOP_CTRL_PHY_CTRL_2			0x4
    #define SATA_TOP_CTRL_2_SW_RST_MDIOREG		BIT(0)
    #define SATA_TOP_CTRL_2_SW_RST_OOB			BIT(1)
    #define SATA_TOP_CTRL_2_SW_RST_RX			BIT(2)
    #define SATA_TOP_CTRL_2_SW_RST_TX			BIT(3)
    #define SATA_TOP_CTRL_2_PHY_GLOBAL_RESET		BIT(14)
   #define SATA_TOP_CTRL_PHY_OFFS				0x8
   #define SATA_TOP_MAX_PHYS				2
766a2d979   Brian Norris   ata: add Broadcom...
46

6863caaf1   Danesh Petigara   ata: ahci_brcmstb...
47
48
49
  #define SATA_FIRST_PORT_CTRL				0x700
  #define SATA_NEXT_PORT_CTRL_OFFSET			0x80
  #define SATA_PORT_PCTRL6(reg_base)			(reg_base + 0x18)
766a2d979   Brian Norris   ata: add Broadcom...
50
51
52
53
54
55
56
57
58
59
60
61
62
  /* On big-endian MIPS, buses are reversed to big endian, so switch them back */
  #if defined(CONFIG_MIPS) && defined(__BIG_ENDIAN)
  #define DATA_ENDIAN			 2 /* AHCI->DDR inbound accesses */
  #define MMIO_ENDIAN			 2 /* CPU->AHCI outbound accesses */
  #else
  #define DATA_ENDIAN			 0
  #define MMIO_ENDIAN			 0
  #endif
  
  #define BUS_CTRL_ENDIAN_CONF				\
  	((DATA_ENDIAN << DMADATA_ENDIAN_SHIFT) |	\
  	(DATA_ENDIAN << DMADESC_ENDIAN_SHIFT) |		\
  	(MMIO_ENDIAN << MMIO_ENDIAN_SHIFT))
36fffd6a1   Florian Fainelli   ata: ahci_brcm: A...
63
64
65
66
67
68
  #define BUS_CTRL_ENDIAN_NSP_CONF			\
  	(0x02 << DMADATA_ENDIAN_SHIFT | 0x02 << DMADESC_ENDIAN_SHIFT)
  
  #define BUS_CTRL_ENDIAN_CONF_MASK			\
  	(0x3 << MMIO_ENDIAN_SHIFT | 0x3 << DMADESC_ENDIAN_SHIFT |	\
  	 0x3 << DMADATA_ENDIAN_SHIFT | 0x3 << PIODATA_ENDIAN_SHIFT)
3ee2e6dca   Yendapally Reddy Dhananjaya Reddy   ata: ahci_brcm: A...
69
70
71
72
  enum brcm_ahci_version {
  	BRCM_SATA_BCM7425 = 1,
  	BRCM_SATA_BCM7445,
  	BRCM_SATA_NSP,
c345ec6a5   Florian Fainelli   ata: ahci_brcm: S...
73
  	BRCM_SATA_BCM7216,
3ee2e6dca   Yendapally Reddy Dhananjaya Reddy   ata: ahci_brcm: A...
74
  };
7de324453   Jaedon Shin   ata: ahci_brcmstb...
75
  enum brcm_ahci_quirks {
1a3d78cb6   Florian Fainelli   ata: ahci_brcm: B...
76
  	BRCM_AHCI_QUIRK_SKIP_PHY_ENABLE	= BIT(0),
7de324453   Jaedon Shin   ata: ahci_brcmstb...
77
  };
766a2d979   Brian Norris   ata: add Broadcom...
78
79
80
81
  struct brcm_ahci_priv {
  	struct device *dev;
  	void __iomem *top_ctrl;
  	u32 port_mask;
7de324453   Jaedon Shin   ata: ahci_brcmstb...
82
  	u32 quirks;
3ee2e6dca   Yendapally Reddy Dhananjaya Reddy   ata: ahci_brcm: A...
83
  	enum brcm_ahci_version version;
2b2c47d9e   Florian Fainelli   ata: ahci_brcm: A...
84
  	struct reset_control *rcdev;
766a2d979   Brian Norris   ata: add Broadcom...
85
  };
766a2d979   Brian Norris   ata: add Broadcom...
86
87
88
89
90
91
92
93
94
95
  static inline u32 brcm_sata_readreg(void __iomem *addr)
  {
  	/*
  	 * MIPS endianness is configured by boot strap, which also reverses all
  	 * bus endianness (i.e., big-endian CPU + big endian bus ==> native
  	 * endian I/O).
  	 *
  	 * Other architectures (e.g., ARM) either do not support big endian, or
  	 * else leave I/O in little endian mode.
  	 */
f9114d357   Axel Lin   ata: ahci_brcmstb...
96
  	if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN))
766a2d979   Brian Norris   ata: add Broadcom...
97
98
99
100
101
102
103
104
  		return __raw_readl(addr);
  	else
  		return readl_relaxed(addr);
  }
  
  static inline void brcm_sata_writereg(u32 val, void __iomem *addr)
  {
  	/* See brcm_sata_readreg() comments */
f9114d357   Axel Lin   ata: ahci_brcmstb...
105
  	if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN))
766a2d979   Brian Norris   ata: add Broadcom...
106
107
108
109
  		__raw_writel(val, addr);
  	else
  		writel_relaxed(val, addr);
  }
6863caaf1   Danesh Petigara   ata: ahci_brcmstb...
110
111
112
  static void brcm_sata_alpm_init(struct ahci_host_priv *hpriv)
  {
  	struct brcm_ahci_priv *priv = hpriv->plat_data;
da8fa9cca   Doug Berger   ata: ahci_brcm: A...
113
  	u32 port_ctrl, host_caps;
6863caaf1   Danesh Petigara   ata: ahci_brcmstb...
114
115
116
  	int i;
  
  	/* Enable support for ALPM */
6863caaf1   Danesh Petigara   ata: ahci_brcmstb...
117
  	host_caps = readl(hpriv->mmio + HOST_CAP);
da8fa9cca   Doug Berger   ata: ahci_brcm: A...
118
119
  	if (!(host_caps & HOST_CAP_ALPM))
  		hpriv->flags |= AHCI_HFLAG_YES_ALPM;
6863caaf1   Danesh Petigara   ata: ahci_brcmstb...
120
121
122
123
124
125
126
127
128
129
130
131
132
  
  	/*
  	 * Adjust timeout to allow PLL sufficient time to lock while waking
  	 * up from slumber mode.
  	 */
  	for (i = 0, port_ctrl = SATA_FIRST_PORT_CTRL;
  	     i < SATA_TOP_MAX_PHYS;
  	     i++, port_ctrl += SATA_NEXT_PORT_CTRL_OFFSET) {
  		if (priv->port_mask & BIT(i))
  			writel(0xff1003fc,
  			       hpriv->mmio + SATA_PORT_PCTRL6(port_ctrl));
  	}
  }
766a2d979   Brian Norris   ata: add Broadcom...
133
134
135
136
137
138
  static void brcm_sata_phy_enable(struct brcm_ahci_priv *priv, int port)
  {
  	void __iomem *phyctrl = priv->top_ctrl + SATA_TOP_CTRL_PHY_CTRL +
  				(port * SATA_TOP_CTRL_PHY_OFFS);
  	void __iomem *p;
  	u32 reg;
b46f79bc7   Jaedon Shin   ata: ahci_brcmstb...
139
140
  	if (priv->quirks & BRCM_AHCI_QUIRK_SKIP_PHY_ENABLE)
  		return;
766a2d979   Brian Norris   ata: add Broadcom...
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
  	/* clear PHY_DEFAULT_POWER_STATE */
  	p = phyctrl + SATA_TOP_CTRL_PHY_CTRL_1;
  	reg = brcm_sata_readreg(p);
  	reg &= ~SATA_TOP_CTRL_1_PHY_DEFAULT_POWER_STATE;
  	brcm_sata_writereg(reg, p);
  
  	/* reset the PHY digital logic */
  	p = phyctrl + SATA_TOP_CTRL_PHY_CTRL_2;
  	reg = brcm_sata_readreg(p);
  	reg &= ~(SATA_TOP_CTRL_2_SW_RST_MDIOREG | SATA_TOP_CTRL_2_SW_RST_OOB |
  		 SATA_TOP_CTRL_2_SW_RST_RX);
  	reg |= SATA_TOP_CTRL_2_SW_RST_TX;
  	brcm_sata_writereg(reg, p);
  	reg = brcm_sata_readreg(p);
  	reg |= SATA_TOP_CTRL_2_PHY_GLOBAL_RESET;
  	brcm_sata_writereg(reg, p);
  	reg = brcm_sata_readreg(p);
  	reg &= ~SATA_TOP_CTRL_2_PHY_GLOBAL_RESET;
  	brcm_sata_writereg(reg, p);
  	(void)brcm_sata_readreg(p);
  }
  
  static void brcm_sata_phy_disable(struct brcm_ahci_priv *priv, int port)
  {
  	void __iomem *phyctrl = priv->top_ctrl + SATA_TOP_CTRL_PHY_CTRL +
  				(port * SATA_TOP_CTRL_PHY_OFFS);
  	void __iomem *p;
  	u32 reg;
b46f79bc7   Jaedon Shin   ata: ahci_brcmstb...
169
170
  	if (priv->quirks & BRCM_AHCI_QUIRK_SKIP_PHY_ENABLE)
  		return;
766a2d979   Brian Norris   ata: add Broadcom...
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
  	/* power-off the PHY digital logic */
  	p = phyctrl + SATA_TOP_CTRL_PHY_CTRL_2;
  	reg = brcm_sata_readreg(p);
  	reg |= (SATA_TOP_CTRL_2_SW_RST_MDIOREG | SATA_TOP_CTRL_2_SW_RST_OOB |
  		SATA_TOP_CTRL_2_SW_RST_RX | SATA_TOP_CTRL_2_SW_RST_TX |
  		SATA_TOP_CTRL_2_PHY_GLOBAL_RESET);
  	brcm_sata_writereg(reg, p);
  
  	/* set PHY_DEFAULT_POWER_STATE */
  	p = phyctrl + SATA_TOP_CTRL_PHY_CTRL_1;
  	reg = brcm_sata_readreg(p);
  	reg |= SATA_TOP_CTRL_1_PHY_DEFAULT_POWER_STATE;
  	brcm_sata_writereg(reg, p);
  }
  
  static void brcm_sata_phys_enable(struct brcm_ahci_priv *priv)
  {
  	int i;
  
  	for (i = 0; i < SATA_TOP_MAX_PHYS; i++)
  		if (priv->port_mask & BIT(i))
  			brcm_sata_phy_enable(priv, i);
  }
  
  static void brcm_sata_phys_disable(struct brcm_ahci_priv *priv)
  {
  	int i;
  
  	for (i = 0; i < SATA_TOP_MAX_PHYS; i++)
  		if (priv->port_mask & BIT(i))
  			brcm_sata_phy_disable(priv, i);
  }
c0cdf2ac4   Florian Fainelli   ata: ahci_brcm: F...
203
  static u32 brcm_ahci_get_portmask(struct ahci_host_priv *hpriv,
766a2d979   Brian Norris   ata: add Broadcom...
204
205
  				  struct brcm_ahci_priv *priv)
  {
766a2d979   Brian Norris   ata: add Broadcom...
206
  	u32 impl;
c0cdf2ac4   Florian Fainelli   ata: ahci_brcm: F...
207
  	impl = readl(hpriv->mmio + HOST_PORTS_IMPL);
766a2d979   Brian Norris   ata: add Broadcom...
208
209
210
211
212
213
214
215
  
  	if (fls(impl) > SATA_TOP_MAX_PHYS)
  		dev_warn(priv->dev, "warning: more ports than PHYs (%#x)
  ",
  			 impl);
  	else if (!impl)
  		dev_info(priv->dev, "no ports found
  ");
766a2d979   Brian Norris   ata: add Broadcom...
216
217
218
219
220
  	return impl;
  }
  
  static void brcm_sata_init(struct brcm_ahci_priv *priv)
  {
3ee2e6dca   Yendapally Reddy Dhananjaya Reddy   ata: ahci_brcm: A...
221
  	void __iomem *ctrl = priv->top_ctrl + SATA_TOP_CTRL_BUS_CTRL;
36fffd6a1   Florian Fainelli   ata: ahci_brcm: A...
222
  	u32 data;
3ee2e6dca   Yendapally Reddy Dhananjaya Reddy   ata: ahci_brcm: A...
223

766a2d979   Brian Norris   ata: add Broadcom...
224
  	/* Configure endianness */
36fffd6a1   Florian Fainelli   ata: ahci_brcm: A...
225
226
227
228
229
230
231
  	data = brcm_sata_readreg(ctrl);
  	data &= ~BUS_CTRL_ENDIAN_CONF_MASK;
  	if (priv->version == BRCM_SATA_NSP)
  		data |= BUS_CTRL_ENDIAN_NSP_CONF;
  	else
  		data |= BUS_CTRL_ENDIAN_CONF;
  	brcm_sata_writereg(data, ctrl);
766a2d979   Brian Norris   ata: add Broadcom...
232
  }
eb73390ae   Florian Fainelli   ata: ahci_brcm: R...
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
  static unsigned int brcm_ahci_read_id(struct ata_device *dev,
  				      struct ata_taskfile *tf, u16 *id)
  {
  	struct ata_port *ap = dev->link->ap;
  	struct ata_host *host = ap->host;
  	struct ahci_host_priv *hpriv = host->private_data;
  	struct brcm_ahci_priv *priv = hpriv->plat_data;
  	void __iomem *mmio = hpriv->mmio;
  	unsigned int err_mask;
  	unsigned long flags;
  	int i, rc;
  	u32 ctl;
  
  	/* Try to read the device ID and, if this fails, proceed with the
  	 * recovery sequence below
  	 */
  	err_mask = ata_do_dev_read_id(dev, tf, id);
  	if (likely(!err_mask))
  		return err_mask;
  
  	/* Disable host interrupts */
  	spin_lock_irqsave(&host->lock, flags);
  	ctl = readl(mmio + HOST_CTL);
  	ctl &= ~HOST_IRQ_EN;
  	writel(ctl, mmio + HOST_CTL);
  	readl(mmio + HOST_CTL); /* flush */
  	spin_unlock_irqrestore(&host->lock, flags);
  
  	/* Perform the SATA PHY reset sequence */
  	brcm_sata_phy_disable(priv, ap->port_no);
bf0e5013b   Florian Fainelli   ata: ahci_brcm: A...
263
264
265
266
267
268
  	/* Reset the SATA clock */
  	ahci_platform_disable_clks(hpriv);
  	msleep(10);
  
  	ahci_platform_enable_clks(hpriv);
  	msleep(10);
eb73390ae   Florian Fainelli   ata: ahci_brcm: R...
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
  	/* Bring the PHY back on */
  	brcm_sata_phy_enable(priv, ap->port_no);
  
  	/* Re-initialize and calibrate the PHY */
  	for (i = 0; i < hpriv->nports; i++) {
  		rc = phy_init(hpriv->phys[i]);
  		if (rc)
  			goto disable_phys;
  
  		rc = phy_calibrate(hpriv->phys[i]);
  		if (rc) {
  			phy_exit(hpriv->phys[i]);
  			goto disable_phys;
  		}
  	}
  
  	/* Re-enable host interrupts */
  	spin_lock_irqsave(&host->lock, flags);
  	ctl = readl(mmio + HOST_CTL);
  	ctl |= HOST_IRQ_EN;
  	writel(ctl, mmio + HOST_CTL);
  	readl(mmio + HOST_CTL); /* flush */
  	spin_unlock_irqrestore(&host->lock, flags);
  
  	return ata_do_dev_read_id(dev, tf, id);
  
  disable_phys:
  	while (--i >= 0) {
  		phy_power_off(hpriv->phys[i]);
  		phy_exit(hpriv->phys[i]);
  	}
  
  	return AC_ERR_OTHER;
  }
  
  static void brcm_ahci_host_stop(struct ata_host *host)
  {
  	struct ahci_host_priv *hpriv = host->private_data;
  
  	ahci_platform_disable_resources(hpriv);
  }
  
  static struct ata_port_operations ahci_brcm_platform_ops = {
  	.inherits	= &ahci_ops,
  	.host_stop	= brcm_ahci_host_stop,
  	.read_id	= brcm_ahci_read_id,
  };
  
  static const struct ata_port_info ahci_brcm_port_info = {
  	.flags		= AHCI_FLAG_COMMON | ATA_FLAG_NO_DIPM,
  	.link_flags	= ATA_LFLAG_NO_DB_DELAY,
  	.pio_mask	= ATA_PIO4,
  	.udma_mask	= ATA_UDMA6,
  	.port_ops	= &ahci_brcm_platform_ops,
  };
766a2d979   Brian Norris   ata: add Broadcom...
324
325
326
327
328
  static int brcm_ahci_suspend(struct device *dev)
  {
  	struct ata_host *host = dev_get_drvdata(dev);
  	struct ahci_host_priv *hpriv = host->private_data;
  	struct brcm_ahci_priv *priv = hpriv->plat_data;
3c696ac41   Florian Fainelli   ata: ahci_brcm: M...
329
  	int ret;
766a2d979   Brian Norris   ata: add Broadcom...
330

766a2d979   Brian Norris   ata: add Broadcom...
331
  	brcm_sata_phys_disable(priv);
c0cdf2ac4   Florian Fainelli   ata: ahci_brcm: F...
332

ed87ad196   Arnd Bergmann   ata: brcm: mark P...
333
334
335
336
  	if (IS_ENABLED(CONFIG_PM_SLEEP))
  		ret = ahci_platform_suspend(dev);
  	else
  		ret = 0;
3c696ac41   Florian Fainelli   ata: ahci_brcm: M...
337

272ecd60a   Florian Fainelli   ata: ahci_brcm: B...
338
339
  	if (priv->version != BRCM_SATA_BCM7216)
  		reset_control_assert(priv->rcdev);
3c696ac41   Florian Fainelli   ata: ahci_brcm: M...
340
341
  
  	return ret;
766a2d979   Brian Norris   ata: add Broadcom...
342
  }
ed87ad196   Arnd Bergmann   ata: brcm: mark P...
343
  static int __maybe_unused brcm_ahci_resume(struct device *dev)
766a2d979   Brian Norris   ata: add Broadcom...
344
345
346
347
  {
  	struct ata_host *host = dev_get_drvdata(dev);
  	struct ahci_host_priv *hpriv = host->private_data;
  	struct brcm_ahci_priv *priv = hpriv->plat_data;
3c696ac41   Florian Fainelli   ata: ahci_brcm: M...
348
  	int ret = 0;
272ecd60a   Florian Fainelli   ata: ahci_brcm: B...
349
350
351
352
  	if (priv->version == BRCM_SATA_BCM7216)
  		ret = reset_control_reset(priv->rcdev);
  	else
  		ret = reset_control_deassert(priv->rcdev);
3c696ac41   Florian Fainelli   ata: ahci_brcm: M...
353
354
  	if (ret)
  		return ret;
c0cdf2ac4   Florian Fainelli   ata: ahci_brcm: F...
355
356
357
358
359
  
  	/* Make sure clocks are turned on before re-configuration */
  	ret = ahci_platform_enable_clks(hpriv);
  	if (ret)
  		return ret;
766a2d979   Brian Norris   ata: add Broadcom...
360
361
362
  
  	brcm_sata_init(priv);
  	brcm_sata_phys_enable(priv);
6863caaf1   Danesh Petigara   ata: ahci_brcmstb...
363
  	brcm_sata_alpm_init(hpriv);
c0cdf2ac4   Florian Fainelli   ata: ahci_brcm: F...
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
  
  	/* Since we had to enable clocks earlier on, we cannot use
  	 * ahci_platform_resume() as-is since a second call to
  	 * ahci_platform_enable_resources() would bump up the resources
  	 * (regulators, clocks, PHYs) count artificially so we copy the part
  	 * after ahci_platform_enable_resources().
  	 */
  	ret = ahci_platform_enable_phys(hpriv);
  	if (ret)
  		goto out_disable_phys;
  
  	ret = ahci_platform_resume_host(dev);
  	if (ret)
  		goto out_disable_platform_phys;
  
  	/* We resumed so update PM runtime state */
  	pm_runtime_disable(dev);
  	pm_runtime_set_active(dev);
  	pm_runtime_enable(dev);
  
  	return 0;
  
  out_disable_platform_phys:
  	ahci_platform_disable_phys(hpriv);
  out_disable_phys:
  	brcm_sata_phys_disable(priv);
  	ahci_platform_disable_clks(hpriv);
  	return ret;
766a2d979   Brian Norris   ata: add Broadcom...
392
393
394
395
396
  }
  
  static struct scsi_host_template ahci_platform_sht = {
  	AHCI_SHT(DRV_NAME),
  };
3ee2e6dca   Yendapally Reddy Dhananjaya Reddy   ata: ahci_brcm: A...
397
398
399
  static const struct of_device_id ahci_of_match[] = {
  	{.compatible = "brcm,bcm7425-ahci", .data = (void *)BRCM_SATA_BCM7425},
  	{.compatible = "brcm,bcm7445-ahci", .data = (void *)BRCM_SATA_BCM7445},
fb8506f15   Florian Fainelli   ata: ahci_brcm: M...
400
  	{.compatible = "brcm,bcm63138-ahci", .data = (void *)BRCM_SATA_BCM7445},
3ee2e6dca   Yendapally Reddy Dhananjaya Reddy   ata: ahci_brcm: A...
401
  	{.compatible = "brcm,bcm-nsp-ahci", .data = (void *)BRCM_SATA_NSP},
c345ec6a5   Florian Fainelli   ata: ahci_brcm: S...
402
  	{.compatible = "brcm,bcm7216-ahci", .data = (void *)BRCM_SATA_BCM7216},
3ee2e6dca   Yendapally Reddy Dhananjaya Reddy   ata: ahci_brcm: A...
403
404
405
  	{},
  };
  MODULE_DEVICE_TABLE(of, ahci_of_match);
766a2d979   Brian Norris   ata: add Broadcom...
406
407
  static int brcm_ahci_probe(struct platform_device *pdev)
  {
3ee2e6dca   Yendapally Reddy Dhananjaya Reddy   ata: ahci_brcm: A...
408
  	const struct of_device_id *of_id;
766a2d979   Brian Norris   ata: add Broadcom...
409
  	struct device *dev = &pdev->dev;
c345ec6a5   Florian Fainelli   ata: ahci_brcm: S...
410
  	const char *reset_name = NULL;
766a2d979   Brian Norris   ata: add Broadcom...
411
412
413
414
415
416
417
418
  	struct brcm_ahci_priv *priv;
  	struct ahci_host_priv *hpriv;
  	struct resource *res;
  	int ret;
  
  	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
  	if (!priv)
  		return -ENOMEM;
3ee2e6dca   Yendapally Reddy Dhananjaya Reddy   ata: ahci_brcm: A...
419
420
421
422
423
424
  
  	of_id = of_match_node(ahci_of_match, pdev->dev.of_node);
  	if (!of_id)
  		return -ENODEV;
  
  	priv->version = (enum brcm_ahci_version)of_id->data;
766a2d979   Brian Norris   ata: add Broadcom...
425
426
427
428
429
430
  	priv->dev = dev;
  
  	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "top-ctrl");
  	priv->top_ctrl = devm_ioremap_resource(dev, res);
  	if (IS_ERR(priv->top_ctrl))
  		return PTR_ERR(priv->top_ctrl);
c345ec6a5   Florian Fainelli   ata: ahci_brcm: S...
431
432
433
434
435
  	/* Reset is optional depending on platform and named differently */
  	if (priv->version == BRCM_SATA_BCM7216)
  		reset_name = "rescal";
  	else
  		reset_name = "ahci";
6fedae3ca   Arnd Bergmann   ata: brcm: fix re...
436
437
438
  	priv->rcdev = devm_reset_control_get_optional(&pdev->dev, reset_name);
  	if (IS_ERR(priv->rcdev))
  		return PTR_ERR(priv->rcdev);
c0cdf2ac4   Florian Fainelli   ata: ahci_brcm: F...
439
  	hpriv = ahci_platform_get_resources(pdev, 0);
1a0600d11   Florian Fainelli   ata: ahci_brcm: P...
440
441
  	if (IS_ERR(hpriv))
  		return PTR_ERR(hpriv);
c0cdf2ac4   Florian Fainelli   ata: ahci_brcm: F...
442

1a3d78cb6   Florian Fainelli   ata: ahci_brcm: B...
443
444
445
446
447
448
  	hpriv->plat_data = priv;
  	hpriv->flags = AHCI_HFLAG_WAKE_BEFORE_STOP | AHCI_HFLAG_NO_WRITE_TO_RO;
  
  	switch (priv->version) {
  	case BRCM_SATA_BCM7425:
  		hpriv->flags |= AHCI_HFLAG_DELAY_ENGINE;
df561f668   Gustavo A. R. Silva   treewide: Use fal...
449
  		fallthrough;
1a3d78cb6   Florian Fainelli   ata: ahci_brcm: B...
450
451
452
453
454
455
456
  	case BRCM_SATA_NSP:
  		hpriv->flags |= AHCI_HFLAG_NO_NCQ;
  		priv->quirks |= BRCM_AHCI_QUIRK_SKIP_PHY_ENABLE;
  		break;
  	default:
  		break;
  	}
272ecd60a   Florian Fainelli   ata: ahci_brcm: B...
457
458
459
460
  	if (priv->version == BRCM_SATA_BCM7216)
  		ret = reset_control_reset(priv->rcdev);
  	else
  		ret = reset_control_deassert(priv->rcdev);
1a0600d11   Florian Fainelli   ata: ahci_brcm: P...
461
462
  	if (ret)
  		return ret;
c0cdf2ac4   Florian Fainelli   ata: ahci_brcm: F...
463
464
465
466
467
468
469
  	ret = ahci_platform_enable_clks(hpriv);
  	if (ret)
  		goto out_reset;
  
  	/* Must be first so as to configure endianness including that
  	 * of the standard AHCI register space.
  	 */
766a2d979   Brian Norris   ata: add Broadcom...
470
  	brcm_sata_init(priv);
c0cdf2ac4   Florian Fainelli   ata: ahci_brcm: F...
471
472
473
474
475
476
  	/* Initializes priv->port_mask which is used below */
  	priv->port_mask = brcm_ahci_get_portmask(hpriv, priv);
  	if (!priv->port_mask) {
  		ret = -ENODEV;
  		goto out_disable_clks;
  	}
766a2d979   Brian Norris   ata: add Broadcom...
477

c0cdf2ac4   Florian Fainelli   ata: ahci_brcm: F...
478
  	/* Must be done before ahci_platform_enable_phys() */
766a2d979   Brian Norris   ata: add Broadcom...
479
  	brcm_sata_phys_enable(priv);
6863caaf1   Danesh Petigara   ata: ahci_brcmstb...
480
  	brcm_sata_alpm_init(hpriv);
c0cdf2ac4   Florian Fainelli   ata: ahci_brcm: F...
481
482
483
  	ret = ahci_platform_enable_phys(hpriv);
  	if (ret)
  		goto out_disable_phys;
766a2d979   Brian Norris   ata: add Broadcom...
484
485
486
  	ret = ahci_platform_init_host(pdev, hpriv, &ahci_brcm_port_info,
  				      &ahci_platform_sht);
  	if (ret)
c0cdf2ac4   Florian Fainelli   ata: ahci_brcm: F...
487
  		goto out_disable_platform_phys;
766a2d979   Brian Norris   ata: add Broadcom...
488
489
490
491
492
  
  	dev_info(dev, "Broadcom AHCI SATA3 registered
  ");
  
  	return 0;
c0cdf2ac4   Florian Fainelli   ata: ahci_brcm: F...
493
494
495
496
497
498
499
500
  
  out_disable_platform_phys:
  	ahci_platform_disable_phys(hpriv);
  out_disable_phys:
  	brcm_sata_phys_disable(priv);
  out_disable_clks:
  	ahci_platform_disable_clks(hpriv);
  out_reset:
272ecd60a   Florian Fainelli   ata: ahci_brcm: B...
501
502
  	if (priv->version != BRCM_SATA_BCM7216)
  		reset_control_assert(priv->rcdev);
c0cdf2ac4   Florian Fainelli   ata: ahci_brcm: F...
503
  	return ret;
766a2d979   Brian Norris   ata: add Broadcom...
504
505
506
507
508
509
510
511
  }
  
  static int brcm_ahci_remove(struct platform_device *pdev)
  {
  	struct ata_host *host = dev_get_drvdata(&pdev->dev);
  	struct ahci_host_priv *hpriv = host->private_data;
  	struct brcm_ahci_priv *priv = hpriv->plat_data;
  	int ret;
c0cdf2ac4   Florian Fainelli   ata: ahci_brcm: F...
512
  	brcm_sata_phys_disable(priv);
766a2d979   Brian Norris   ata: add Broadcom...
513
514
515
  	ret = ata_platform_remove_one(pdev);
  	if (ret)
  		return ret;
766a2d979   Brian Norris   ata: add Broadcom...
516
517
  	return 0;
  }
7de9b1688   Florian Fainelli   ata: ahci_brcm: A...
518
519
520
521
522
523
524
525
526
527
528
529
530
531
  static void brcm_ahci_shutdown(struct platform_device *pdev)
  {
  	int ret;
  
  	/* All resources releasing happens via devres, but our device, unlike a
  	 * proper remove is not disappearing, therefore using
  	 * brcm_ahci_suspend() here which does explicit power management is
  	 * appropriate.
  	 */
  	ret = brcm_ahci_suspend(&pdev->dev);
  	if (ret)
  		dev_err(&pdev->dev, "failed to shutdown
  ");
  }
766a2d979   Brian Norris   ata: add Broadcom...
532
533
534
535
536
  static SIMPLE_DEV_PM_OPS(ahci_brcm_pm_ops, brcm_ahci_suspend, brcm_ahci_resume);
  
  static struct platform_driver brcm_ahci_driver = {
  	.probe = brcm_ahci_probe,
  	.remove = brcm_ahci_remove,
7de9b1688   Florian Fainelli   ata: ahci_brcm: A...
537
  	.shutdown = brcm_ahci_shutdown,
766a2d979   Brian Norris   ata: add Broadcom...
538
539
540
541
542
543
544
545
546
547
548
549
  	.driver = {
  		.name = DRV_NAME,
  		.of_match_table = ahci_of_match,
  		.pm = &ahci_brcm_pm_ops,
  	},
  };
  module_platform_driver(brcm_ahci_driver);
  
  MODULE_DESCRIPTION("Broadcom SATA3 AHCI Controller Driver");
  MODULE_AUTHOR("Brian Norris");
  MODULE_LICENSE("GPL");
  MODULE_ALIAS("platform:sata-brcmstb");