xref: /freebsd/sys/arm/nvidia/tegra_ahci.c (revision 459dc61c8b05dedb61a2774348ffda7d7f8ea7c6)
1ef2ee5d0SMichal Meloun /*-
2ef2ee5d0SMichal Meloun  * Copyright (c) 2016 Michal Meloun <mmel@FreeBSD.org>
3ef2ee5d0SMichal Meloun  * All rights reserved.
4ef2ee5d0SMichal Meloun  *
5ef2ee5d0SMichal Meloun  * Redistribution and use in source and binary forms, with or without
6ef2ee5d0SMichal Meloun  * modification, are permitted provided that the following conditions
7ef2ee5d0SMichal Meloun  * are met:
8ef2ee5d0SMichal Meloun  * 1. Redistributions of source code must retain the above copyright
9ef2ee5d0SMichal Meloun  *    notice, this list of conditions and the following disclaimer.
10ef2ee5d0SMichal Meloun  * 2. Redistributions in binary form must reproduce the above copyright
11ef2ee5d0SMichal Meloun  *    notice, this list of conditions and the following disclaimer in the
12ef2ee5d0SMichal Meloun  *    documentation and/or other materials provided with the distribution.
13ef2ee5d0SMichal Meloun  *
14ef2ee5d0SMichal Meloun  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15ef2ee5d0SMichal Meloun  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16ef2ee5d0SMichal Meloun  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17ef2ee5d0SMichal Meloun  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18ef2ee5d0SMichal Meloun  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19ef2ee5d0SMichal Meloun  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20ef2ee5d0SMichal Meloun  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21ef2ee5d0SMichal Meloun  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22ef2ee5d0SMichal Meloun  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23ef2ee5d0SMichal Meloun  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24ef2ee5d0SMichal Meloun  * SUCH DAMAGE.
25ef2ee5d0SMichal Meloun  */
26ef2ee5d0SMichal Meloun 
27ef2ee5d0SMichal Meloun #include <sys/cdefs.h>
28ef2ee5d0SMichal Meloun /*
29ef2ee5d0SMichal Meloun  * AHCI driver for Tegra SoCs.
30ef2ee5d0SMichal Meloun  */
31ef2ee5d0SMichal Meloun #include <sys/param.h>
32ef2ee5d0SMichal Meloun #include <sys/module.h>
33ef2ee5d0SMichal Meloun #include <sys/systm.h>
34ef2ee5d0SMichal Meloun #include <sys/bus.h>
35ef2ee5d0SMichal Meloun #include <sys/conf.h>
36ef2ee5d0SMichal Meloun #include <sys/endian.h>
37ef2ee5d0SMichal Meloun #include <sys/kernel.h>
38ef2ee5d0SMichal Meloun #include <sys/lock.h>
39ef2ee5d0SMichal Meloun #include <sys/malloc.h>
40ef2ee5d0SMichal Meloun #include <sys/mutex.h>
41ef2ee5d0SMichal Meloun #include <sys/rman.h>
42ef2ee5d0SMichal Meloun 
43ef2ee5d0SMichal Meloun #include <machine/bus.h>
44ef2ee5d0SMichal Meloun #include <machine/resource.h>
45ef2ee5d0SMichal Meloun 
46ef2ee5d0SMichal Meloun #include <dev/ahci/ahci.h>
47be82b3a0SEmmanuel Vadot #include <dev/clk/clk.h>
481f469a9fSEmmanuel Vadot #include <dev/hwreset/hwreset.h>
49950a6087SEmmanuel Vadot #include <dev/phy/phy.h>
50b2f0caf1SEmmanuel Vadot #include <dev/regulator/regulator.h>
51ef2ee5d0SMichal Meloun #include <dev/fdt/fdt_pinctrl.h>
52ef2ee5d0SMichal Meloun #include <dev/ofw/ofw_bus.h>
53ef2ee5d0SMichal Meloun #include <dev/ofw/ofw_bus_subr.h>
54ef2ee5d0SMichal Meloun 
55ef2ee5d0SMichal Meloun #include <arm/nvidia/tegra_efuse.h>
56ef2ee5d0SMichal Meloun #include <arm/nvidia/tegra_pmc.h>
57ef2ee5d0SMichal Meloun 
58ef2ee5d0SMichal Meloun 
59ef2ee5d0SMichal Meloun #define	SATA_CONFIGURATION			0x180
60b9cbd68dSMichal Meloun #define  SATA_CONFIGURATION_CLK_OVERRIDE		(1U << 31)
61ef2ee5d0SMichal Meloun #define	 SATA_CONFIGURATION_EN_FPCI			(1  <<  0)
62ef2ee5d0SMichal Meloun 
63ef2ee5d0SMichal Meloun #define	SATA_FPCI_BAR5				0x94
64b9cbd68dSMichal Meloun #define	 SATA_FPCI_BAR_START(x)				(((x) & 0xFFFFFFF) << 4)
65b9cbd68dSMichal Meloun #define	 SATA_FPCI_BAR_ACCESS_TYPE			(1 << 0)
66ef2ee5d0SMichal Meloun 
67ef2ee5d0SMichal Meloun #define	SATA_INTR_MASK				0x188
68ef2ee5d0SMichal Meloun #define	SATA_INTR_MASK_IP_INT_MASK			(1 << 16)
69ef2ee5d0SMichal Meloun 
70ef2ee5d0SMichal Meloun #define	SCFG_OFFSET				0x1000
71ef2ee5d0SMichal Meloun 
72ef2ee5d0SMichal Meloun #define	T_SATA0_CFG_1				0x04
73ef2ee5d0SMichal Meloun #define	 T_SATA0_CFG_1_IO_SPACE				(1 << 0)
74ef2ee5d0SMichal Meloun #define	 T_SATA0_CFG_1_MEMORY_SPACE			(1 << 1)
75ef2ee5d0SMichal Meloun #define	 T_SATA0_CFG_1_BUS_MASTER			(1 << 2)
76ef2ee5d0SMichal Meloun #define	 T_SATA0_CFG_1_SERR				(1 << 8)
77ef2ee5d0SMichal Meloun 
78ef2ee5d0SMichal Meloun #define	T_SATA0_CFG_9				0x24
79ef2ee5d0SMichal Meloun #define	 T_SATA0_CFG_9_BASE_ADDRESS_SHIFT		13
80ef2ee5d0SMichal Meloun 
81b9cbd68dSMichal Meloun #define	T_SATA0_CFG_35				0x94
82b9cbd68dSMichal Meloun #define	 T_SATA0_CFG_35_IDP_INDEX_MASK			(0x7ff << 2)
83b9cbd68dSMichal Meloun #define	 T_SATA0_CFG_35_IDP_INDEX			(0x2a << 2)
84b9cbd68dSMichal Meloun 
85b9cbd68dSMichal Meloun #define	T_SATA0_AHCI_IDP1			0x98
86b9cbd68dSMichal Meloun #define	 T_SATA0_AHCI_IDP1_DATA				0x400040
87b9cbd68dSMichal Meloun 
88b9cbd68dSMichal Meloun #define	T_SATA0_CFG_PHY_1			0x12c
89b9cbd68dSMichal Meloun #define	 T_SATA0_CFG_PHY_1_PADS_IDDQ_EN			(1 << 23)
90b9cbd68dSMichal Meloun #define	 T_SATA0_CFG_PHY_1_PAD_PLL_IDDQ_EN		(1 << 22)
91b9cbd68dSMichal Meloun 
92b9cbd68dSMichal Meloun #define	T_SATA0_NVOOB				0x114
93b9cbd68dSMichal Meloun #define	 T_SATA0_NVOOB_SQUELCH_FILTER_LENGTH_MASK	(0x3 << 26)
94b9cbd68dSMichal Meloun #define	 T_SATA0_NVOOB_SQUELCH_FILTER_LENGTH		(0x3 << 26)
95b9cbd68dSMichal Meloun #define	 T_SATA0_NVOOB_SQUELCH_FILTER_MODE_MASK		(0x3 << 24)
96b9cbd68dSMichal Meloun #define	 T_SATA0_NVOOB_SQUELCH_FILTER_MODE		(0x1 << 24)
97b9cbd68dSMichal Meloun #define	 T_SATA0_NVOOB_COMMA_CNT_MASK			(0xff << 16)
98b9cbd68dSMichal Meloun #define	 T_SATA0_NVOOB_COMMA_CNT			(0x07 << 16)
99b9cbd68dSMichal Meloun 
100b9cbd68dSMichal Meloun #define	T_SATA0_CFG_PHY				0x120
101b9cbd68dSMichal Meloun #define	 T_SATA0_CFG_PHY_MASK_SQUELCH			(1 << 24)
102b9cbd68dSMichal Meloun #define	 T_SATA0_CFG_PHY_USE_7BIT_ALIGN_DET_FOR_SPD	(1 << 11)
103b9cbd68dSMichal Meloun 
104b9cbd68dSMichal Meloun #define	T_SATA0_CFG2NVOOB_2			0x134
105b9cbd68dSMichal Meloun #define	 T_SATA0_CFG2NVOOB_2_COMWAKE_IDLE_CNT_LOW_MASK	(0x1ff << 18)
106b9cbd68dSMichal Meloun #define	 T_SATA0_CFG2NVOOB_2_COMWAKE_IDLE_CNT_LOW	(0xc << 18)
107b9cbd68dSMichal Meloun 
108ef2ee5d0SMichal Meloun #define	T_SATA0_AHCI_HBA_CAP_BKDR		0x300
109b9cbd68dSMichal Meloun #define	 T_SATA0_AHCI_HBA_CAP_BKDR_SNCQ			(1 << 30)
110b9cbd68dSMichal Meloun #define	 T_SATA0_AHCI_HBA_CAP_BKDR_SUPP_PM		(1 << 17)
111b9cbd68dSMichal Meloun #define	 T_SATA0_AHCI_HBA_CAP_BKDR_SALP			(1 << 26)
112b9cbd68dSMichal Meloun #define	 T_SATA0_AHCI_HBA_CAP_BKDR_SLUMBER_ST_CAP	(1 << 14)
113b9cbd68dSMichal Meloun #define	 T_SATA0_AHCI_HBA_CAP_BKDR_PARTIAL_ST_CAP	(1 << 13)
114b9cbd68dSMichal Meloun 
115ef2ee5d0SMichal Meloun #define	T_SATA0_BKDOOR_CC			0x4a4
116b9cbd68dSMichal Meloun #define	 T_SATA0_BKDOOR_CC_CLASS_CODE_MASK		(0xffff << 16)
117b9cbd68dSMichal Meloun #define	 T_SATA0_BKDOOR_CC_CLASS_CODE			(0x0106 << 16)
118b9cbd68dSMichal Meloun #define	 T_SATA0_BKDOOR_CC_PROG_IF_MASK			(0xff << 8)
119b9cbd68dSMichal Meloun #define	 T_SATA0_BKDOOR_CC_PROG_IF			(0x01 << 8)
120b9cbd68dSMichal Meloun 
121ef2ee5d0SMichal Meloun #define	T_SATA0_CFG_SATA			0x54c
122ef2ee5d0SMichal Meloun #define	 T_SATA0_CFG_SATA_BACKDOOR_PROG_IF_EN		(1 << 12)
123ef2ee5d0SMichal Meloun 
124ef2ee5d0SMichal Meloun #define	T_SATA0_CFG_MISC			0x550
125ef2ee5d0SMichal Meloun #define	T_SATA0_INDEX				0x680
126ef2ee5d0SMichal Meloun 
127ef2ee5d0SMichal Meloun #define	T_SATA0_CHX_PHY_CTRL1_GEN1		0x690
128ef2ee5d0SMichal Meloun #define	 T_SATA0_CHX_PHY_CTRL1_GEN1_TX_PEAK_MASK	0xff
129ef2ee5d0SMichal Meloun #define	 T_SATA0_CHX_PHY_CTRL1_GEN1_TX_PEAK_SHIFT	8
130ef2ee5d0SMichal Meloun #define	 T_SATA0_CHX_PHY_CTRL1_GEN1_TX_AMP_MASK		0xff
131ef2ee5d0SMichal Meloun #define	 T_SATA0_CHX_PHY_CTRL1_GEN1_TX_AMP_SHIFT	0
132ef2ee5d0SMichal Meloun 
133ef2ee5d0SMichal Meloun #define	T_SATA0_CHX_PHY_CTRL1_GEN2		0x694
134ef2ee5d0SMichal Meloun #define	 T_SATA0_CHX_PHY_CTRL1_GEN2_TX_PEAK_MASK	0xff
135ef2ee5d0SMichal Meloun #define	 T_SATA0_CHX_PHY_CTRL1_GEN2_TX_PEAK_SHIFT	12
136ef2ee5d0SMichal Meloun #define	 T_SATA0_CHX_PHY_CTRL1_GEN2_TX_AMP_MASK		0xff
137ef2ee5d0SMichal Meloun #define	 T_SATA0_CHX_PHY_CTRL1_GEN2_TX_AMP_SHIFT	0
138ef2ee5d0SMichal Meloun 
139ef2ee5d0SMichal Meloun #define	T_SATA0_CHX_PHY_CTRL2			0x69c
140ef2ee5d0SMichal Meloun #define	 T_SATA0_CHX_PHY_CTRL2_CDR_CNTL_GEN1		0x23
141ef2ee5d0SMichal Meloun 
142ef2ee5d0SMichal Meloun #define	T_SATA0_CHX_PHY_CTRL11			0x6d0
143ef2ee5d0SMichal Meloun #define	 T_SATA0_CHX_PHY_CTRL11_GEN2_RX_EQ		(0x2800 << 16)
144ef2ee5d0SMichal Meloun 
145b9cbd68dSMichal Meloun #define T_SATA0_CHX_PHY_CTRL17			0x6e8
146b9cbd68dSMichal Meloun #define T_SATA0_CHX_PHY_CTRL18			0x6ec
147b9cbd68dSMichal Meloun #define T_SATA0_CHX_PHY_CTRL20			0x6f4
148b9cbd68dSMichal Meloun #define T_SATA0_CHX_PHY_CTRL21			0x6f8
149b9cbd68dSMichal Meloun 
150ef2ee5d0SMichal Meloun #define	FUSE_SATA_CALIB				0x124
151ef2ee5d0SMichal Meloun #define	FUSE_SATA_CALIB_MASK			0x3
152ef2ee5d0SMichal Meloun 
153ef2ee5d0SMichal Meloun #define	SATA_AUX_MISC_CNTL			0x1108
154ef2ee5d0SMichal Meloun #define	SATA_AUX_PAD_PLL_CTRL_0			0x1120
155ef2ee5d0SMichal Meloun #define	SATA_AUX_PAD_PLL_CTRL_1			0x1124
156ef2ee5d0SMichal Meloun #define	SATA_AUX_PAD_PLL_CTRL_2			0x1128
157ef2ee5d0SMichal Meloun #define	SATA_AUX_PAD_PLL_CTRL_3			0x112c
158ef2ee5d0SMichal Meloun 
159ef2ee5d0SMichal Meloun #define	T_AHCI_HBA_CCC_PORTS			0x0018
160ef2ee5d0SMichal Meloun #define	T_AHCI_HBA_CAP_BKDR			0x00A0
161ef2ee5d0SMichal Meloun #define	 T_AHCI_HBA_CAP_BKDR_S64A			(1 << 31)
162ef2ee5d0SMichal Meloun #define	 T_AHCI_HBA_CAP_BKDR_SNCQ			(1 << 30)
163ef2ee5d0SMichal Meloun #define	 T_AHCI_HBA_CAP_BKDR_SSNTF			(1 << 29)
164ef2ee5d0SMichal Meloun #define	 T_AHCI_HBA_CAP_BKDR_SMPS			(1 << 28)
165ef2ee5d0SMichal Meloun #define	 T_AHCI_HBA_CAP_BKDR_SUPP_STG_SPUP		(1 << 27)
166ef2ee5d0SMichal Meloun #define	 T_AHCI_HBA_CAP_BKDR_SALP			(1 << 26)
167ef2ee5d0SMichal Meloun #define	 T_AHCI_HBA_CAP_BKDR_SAL			(1 << 25)
168ef2ee5d0SMichal Meloun #define	 T_AHCI_HBA_CAP_BKDR_SUPP_CLO			(1 << 24)
169ef2ee5d0SMichal Meloun #define	 T_AHCI_HBA_CAP_BKDR_INTF_SPD_SUPP(x)		(((x) & 0xF) << 20)
170ef2ee5d0SMichal Meloun #define	 T_AHCI_HBA_CAP_BKDR_SUPP_NONZERO_OFFSET	(1 << 19)
171ef2ee5d0SMichal Meloun #define	 T_AHCI_HBA_CAP_BKDR_SUPP_AHCI_ONLY		(1 << 18)
172ef2ee5d0SMichal Meloun #define	 T_AHCI_HBA_CAP_BKDR_SUPP_PM			(1 << 17)
173ef2ee5d0SMichal Meloun #define	 T_AHCI_HBA_CAP_BKDR_FIS_SWITCHING		(1 << 16)
174ef2ee5d0SMichal Meloun #define	 T_AHCI_HBA_CAP_BKDR_PIO_MULT_DRQ_BLK		(1 << 15)
175ef2ee5d0SMichal Meloun #define	 T_AHCI_HBA_CAP_BKDR_SLUMBER_ST_CAP		(1 << 14)
176ef2ee5d0SMichal Meloun #define	 T_AHCI_HBA_CAP_BKDR_PARTIAL_ST_CAP		(1 << 13)
177ef2ee5d0SMichal Meloun #define	 T_AHCI_HBA_CAP_BKDR_NUM_CMD_SLOTS(x)		(((x) & 0x1F) <<  8)
178ef2ee5d0SMichal Meloun #define	 T_AHCI_HBA_CAP_BKDR_CMD_CMPL_COALESING		(1 <<  7)
179ef2ee5d0SMichal Meloun #define	 T_AHCI_HBA_CAP_BKDR_ENCL_MGMT_SUPP		(1 <<  6)
180ef2ee5d0SMichal Meloun #define	 T_AHCI_HBA_CAP_BKDR_EXT_SATA			(1 <<  5)
181ef2ee5d0SMichal Meloun #define	 T_AHCI_HBA_CAP_BKDR_NUM_PORTS(x)		(((x) & 0xF) <<  0)
182ef2ee5d0SMichal Meloun 
183ef2ee5d0SMichal Meloun #define	T_AHCI_PORT_BKDR			0x0170
184ef2ee5d0SMichal Meloun 
185ef2ee5d0SMichal Meloun #define	 T_AHCI_PORT_BKDR_PXDEVSLP_DETO_OVERRIDE_VAL(x)	(((x) & 0xFF) << 24)
186ef2ee5d0SMichal Meloun #define	 T_AHCI_PORT_BKDR_PXDEVSLP_MDAT_OVERRIDE_VAL(x)	(((x) & 0x1F) << 16)
187ef2ee5d0SMichal Meloun #define	 T_AHCI_PORT_BKDR_PXDEVSLP_DETO_OVERRIDE	(1 << 15)
188ef2ee5d0SMichal Meloun #define	 T_AHCI_PORT_BKDR_PXDEVSLP_MDAT_OVERRIDE	(1 << 14)
189ef2ee5d0SMichal Meloun #define	 T_AHCI_PORT_BKDR_PXDEVSLP_DM(x)		(((x) & 0xF) << 10)
190ef2ee5d0SMichal Meloun #define	 T_AHCI_PORT_BKDR_PORT_UNCONNECTED		(1 <<  9)
191ef2ee5d0SMichal Meloun #define	 T_AHCI_PORT_BKDR_CLK_CLAMP_CTRL_CLAMP_THIS_CH	(1 <<  8)
192ef2ee5d0SMichal Meloun #define	 T_AHCI_PORT_BKDR_CLK_CLAMP_CTRL_TXRXCLK_UNCLAMP (1 <<  7)
193ef2ee5d0SMichal Meloun #define	 T_AHCI_PORT_BKDR_CLK_CLAMP_CTRL_TXRXCLK_CLAMP	(1 <<  6)
194ef2ee5d0SMichal Meloun #define	 T_AHCI_PORT_BKDR_CLK_CLAMP_CTRL_DEVCLK_UNCLAMP	(1 <<  5)
195ef2ee5d0SMichal Meloun #define	 T_AHCI_PORT_BKDR_CLK_CLAMP_CTRL_DEVCLK_CLAMP	(1 <<  4)
196ef2ee5d0SMichal Meloun #define	 T_AHCI_PORT_BKDR_HOTPLUG_CAP			(1 <<  3)
197ef2ee5d0SMichal Meloun #define	 T_AHCI_PORT_BKDR_MECH_SWITCH			(1 <<  2)
198ef2ee5d0SMichal Meloun #define	 T_AHCI_PORT_BKDR_COLD_PRSN_DET			(1 <<  1)
199ef2ee5d0SMichal Meloun #define	 T_AHCI_PORT_BKDR_EXT_SATA_SUPP			(1 <<  0)
200ef2ee5d0SMichal Meloun 
201b9cbd68dSMichal Meloun /* AUX registers */
202b9cbd68dSMichal Meloun #define	SATA_AUX_MISC_CNTL_1			0x008
203b9cbd68dSMichal Meloun #define	 SATA_AUX_MISC_CNTL_1_DEVSLP_OVERRIDE		(1 << 17)
204b9cbd68dSMichal Meloun #define	 SATA_AUX_MISC_CNTL_1_SDS_SUPPORT		(1 << 13)
205b9cbd68dSMichal Meloun #define	 SATA_AUX_MISC_CNTL_1_DESO_SUPPORT		(1 << 15)
206b9cbd68dSMichal Meloun 
207b9cbd68dSMichal Meloun #define	AHCI_WR4(_sc, _r, _v)	bus_write_4((_sc)->ctlr.r_mem, (_r), (_v))
208b9cbd68dSMichal Meloun #define	AHCI_RD4(_sc, _r)	bus_read_4((_sc)->ctlr.r_mem, (_r))
209b9cbd68dSMichal Meloun #define	SATA_WR4(_sc, _r, _v)	bus_write_4((_sc)->sata_mem, (_r), (_v))
210b9cbd68dSMichal Meloun #define	SATA_RD4(_sc, _r)	bus_read_4((_sc)->sata_mem, (_r))
211b9cbd68dSMichal Meloun 
212b9cbd68dSMichal Meloun struct sata_pad_calibration {
213b9cbd68dSMichal Meloun 	uint32_t gen1_tx_amp;
214b9cbd68dSMichal Meloun 	uint32_t gen1_tx_peak;
215b9cbd68dSMichal Meloun 	uint32_t gen2_tx_amp;
216b9cbd68dSMichal Meloun 	uint32_t gen2_tx_peak;
217b9cbd68dSMichal Meloun };
218b9cbd68dSMichal Meloun 
219b9cbd68dSMichal Meloun static const struct sata_pad_calibration tegra124_pad_calibration[] = {
220b9cbd68dSMichal Meloun 	{0x18, 0x04, 0x18, 0x0a},
221b9cbd68dSMichal Meloun 	{0x0e, 0x04, 0x14, 0x0a},
222b9cbd68dSMichal Meloun 	{0x0e, 0x07, 0x1a, 0x0e},
223b9cbd68dSMichal Meloun 	{0x14, 0x0e, 0x1a, 0x0e},
224b9cbd68dSMichal Meloun };
225b9cbd68dSMichal Meloun 
226b9cbd68dSMichal Meloun struct ahci_soc;
227b9cbd68dSMichal Meloun struct tegra_ahci_sc {
228b9cbd68dSMichal Meloun 	struct ahci_controller	ctlr;	/* Must be first */
229b9cbd68dSMichal Meloun 	device_t		dev;
230b9cbd68dSMichal Meloun 	struct ahci_soc		*soc;
231b9cbd68dSMichal Meloun 	struct resource		*sata_mem;
232b9cbd68dSMichal Meloun 	struct resource		*aux_mem;
233b9cbd68dSMichal Meloun 	clk_t			clk_sata;
234b9cbd68dSMichal Meloun 	clk_t			clk_sata_oob;
235b9cbd68dSMichal Meloun 	clk_t			clk_pll_e;
236b9cbd68dSMichal Meloun 	clk_t			clk_cml;
237b9cbd68dSMichal Meloun 	hwreset_t		hwreset_sata;
238b9cbd68dSMichal Meloun 	hwreset_t		hwreset_sata_oob;
239b9cbd68dSMichal Meloun 	hwreset_t		hwreset_sata_cold;
240b9cbd68dSMichal Meloun 	regulator_t		regulators[16];		/* Safe maximum */
241b9cbd68dSMichal Meloun 	phy_t			phy;
242b9cbd68dSMichal Meloun };
243b9cbd68dSMichal Meloun 
244b9cbd68dSMichal Meloun struct ahci_soc {
245b9cbd68dSMichal Meloun 	char 	**regulator_names;
246b9cbd68dSMichal Meloun 	int	(*init)(struct tegra_ahci_sc *sc);
247b9cbd68dSMichal Meloun };
248b9cbd68dSMichal Meloun 
249b9cbd68dSMichal Meloun /* Tegra 124 config. */
250b9cbd68dSMichal Meloun static char *tegra124_reg_names[] = {
251b9cbd68dSMichal Meloun 	"hvdd-supply",
252b9cbd68dSMichal Meloun 	"vddio-supply",
253b9cbd68dSMichal Meloun 	"avdd-supply",
254b9cbd68dSMichal Meloun 	"target-5v-supply",
255b9cbd68dSMichal Meloun 	"target-12v-supply",
256b9cbd68dSMichal Meloun 	NULL
257b9cbd68dSMichal Meloun };
258b9cbd68dSMichal Meloun 
259b9cbd68dSMichal Meloun static int tegra124_ahci_init(struct tegra_ahci_sc *sc);
260b9cbd68dSMichal Meloun static struct ahci_soc tegra124_soc = {
261b9cbd68dSMichal Meloun 	.regulator_names = tegra124_reg_names,
262b9cbd68dSMichal Meloun 	.init = tegra124_ahci_init,
263b9cbd68dSMichal Meloun };
264b9cbd68dSMichal Meloun 
265b9cbd68dSMichal Meloun /* Tegra 210 config. */
266b9cbd68dSMichal Meloun static char *tegra210_reg_names[] = {
267b9cbd68dSMichal Meloun 	NULL
268b9cbd68dSMichal Meloun };
269b9cbd68dSMichal Meloun 
270b9cbd68dSMichal Meloun static struct ahci_soc tegra210_soc = {
271b9cbd68dSMichal Meloun 	.regulator_names = tegra210_reg_names,
272b9cbd68dSMichal Meloun };
273b9cbd68dSMichal Meloun 
274b9cbd68dSMichal Meloun 
275b9cbd68dSMichal Meloun static struct ofw_compat_data compat_data[] = {
276b9cbd68dSMichal Meloun 	{"nvidia,tegra124-ahci", (uintptr_t)&tegra124_soc},
277b9cbd68dSMichal Meloun 	{"nvidia,tegra210-ahci", (uintptr_t)&tegra210_soc},
278b9cbd68dSMichal Meloun 	{NULL,			0}
279b9cbd68dSMichal Meloun };
280b9cbd68dSMichal Meloun 
281ef2ee5d0SMichal Meloun static int
282ef2ee5d0SMichal Meloun get_fdt_resources(struct tegra_ahci_sc *sc, phandle_t node)
283ef2ee5d0SMichal Meloun {
284b9cbd68dSMichal Meloun 	int i, rv;
285ef2ee5d0SMichal Meloun 
286b9cbd68dSMichal Meloun 	/* Regulators. */
287b9cbd68dSMichal Meloun 	for (i = 0; sc->soc->regulator_names[i] != NULL; i++) {
288b9cbd68dSMichal Meloun 		if (i >= nitems(sc->regulators)) {
289b9cbd68dSMichal Meloun 			device_printf(sc->dev,
290b9cbd68dSMichal Meloun 			    "Too many regulators present in DT.\n");
291b9cbd68dSMichal Meloun 			return (EOVERFLOW);
292b9cbd68dSMichal Meloun 		}
293b9cbd68dSMichal Meloun 		rv = regulator_get_by_ofw_property(sc->dev, 0,
294b9cbd68dSMichal Meloun 		    sc->soc->regulator_names[i], sc->regulators + i);
295ef2ee5d0SMichal Meloun 		if (rv != 0) {
296b9cbd68dSMichal Meloun 			device_printf(sc->dev,
297b9cbd68dSMichal Meloun 			    "Cannot get '%s' regulator\n",
298b9cbd68dSMichal Meloun 			    sc->soc->regulator_names[i]);
299ef2ee5d0SMichal Meloun 			return (ENXIO);
300ef2ee5d0SMichal Meloun 		}
301ef2ee5d0SMichal Meloun 	}
302ef2ee5d0SMichal Meloun 
303b9cbd68dSMichal Meloun 	/* Resets. */
304dac93553SMichal Meloun 	rv = hwreset_get_by_ofw_name(sc->dev, 0, "sata", &sc->hwreset_sata );
305ef2ee5d0SMichal Meloun 	if (rv != 0) {
306ef2ee5d0SMichal Meloun 		device_printf(sc->dev, "Cannot get 'sata' reset\n");
307ef2ee5d0SMichal Meloun 		return (ENXIO);
308ef2ee5d0SMichal Meloun 	}
309dac93553SMichal Meloun 	rv = hwreset_get_by_ofw_name(sc->dev, 0, "sata-oob",
310ef2ee5d0SMichal Meloun 	    &sc->hwreset_sata_oob);
311ef2ee5d0SMichal Meloun 	if (rv != 0) {
312ef2ee5d0SMichal Meloun 		device_printf(sc->dev, "Cannot get 'sata oob' reset\n");
313ef2ee5d0SMichal Meloun 		return (ENXIO);
314ef2ee5d0SMichal Meloun 	}
315dac93553SMichal Meloun 	rv = hwreset_get_by_ofw_name(sc->dev, 0, "sata-cold",
316ef2ee5d0SMichal Meloun 	    &sc->hwreset_sata_cold);
317ef2ee5d0SMichal Meloun 	if (rv != 0) {
318ef2ee5d0SMichal Meloun 		device_printf(sc->dev, "Cannot get 'sata cold' reset\n");
319ef2ee5d0SMichal Meloun 		return (ENXIO);
320ef2ee5d0SMichal Meloun 	}
321ef2ee5d0SMichal Meloun 
322b9cbd68dSMichal Meloun 	/* Phy */
32323ea1f2bSOleksandr Tymoshenko 	rv = phy_get_by_ofw_name(sc->dev, 0, "sata-0", &sc->phy);
324ef2ee5d0SMichal Meloun 	if (rv != 0) {
325b9cbd68dSMichal Meloun 		rv = phy_get_by_ofw_idx(sc->dev, 0, 0, &sc->phy);
326b9cbd68dSMichal Meloun 		if (rv != 0) {
327ef2ee5d0SMichal Meloun 			device_printf(sc->dev, "Cannot get 'sata' phy\n");
328ef2ee5d0SMichal Meloun 			return (ENXIO);
329ef2ee5d0SMichal Meloun 		}
330b9cbd68dSMichal Meloun 	}
331ef2ee5d0SMichal Meloun 
332b9cbd68dSMichal Meloun 	/* Clocks. */
333dac93553SMichal Meloun 	rv = clk_get_by_ofw_name(sc->dev, 0, "sata", &sc->clk_sata);
334ef2ee5d0SMichal Meloun 	if (rv != 0) {
335ef2ee5d0SMichal Meloun 		device_printf(sc->dev, "Cannot get 'sata' clock\n");
336ef2ee5d0SMichal Meloun 		return (ENXIO);
337ef2ee5d0SMichal Meloun 	}
338dac93553SMichal Meloun 	rv = clk_get_by_ofw_name(sc->dev, 0, "sata-oob", &sc->clk_sata_oob);
339ef2ee5d0SMichal Meloun 	if (rv != 0) {
340ef2ee5d0SMichal Meloun 		device_printf(sc->dev, "Cannot get 'sata oob' clock\n");
341ef2ee5d0SMichal Meloun 		return (ENXIO);
342ef2ee5d0SMichal Meloun 	}
343b9cbd68dSMichal Meloun 	/* These are optional */
344dac93553SMichal Meloun 	rv = clk_get_by_ofw_name(sc->dev, 0, "cml1", &sc->clk_cml);
345b9cbd68dSMichal Meloun 	if (rv != 0)
346b9cbd68dSMichal Meloun 		sc->clk_cml = NULL;
347b9cbd68dSMichal Meloun 
348dac93553SMichal Meloun 	rv = clk_get_by_ofw_name(sc->dev, 0, "pll_e", &sc->clk_pll_e);
349b9cbd68dSMichal Meloun 	if (rv != 0)
350b9cbd68dSMichal Meloun 		sc->clk_pll_e = NULL;
351ef2ee5d0SMichal Meloun 	return (0);
352ef2ee5d0SMichal Meloun }
353ef2ee5d0SMichal Meloun 
354ef2ee5d0SMichal Meloun static int
355ef2ee5d0SMichal Meloun enable_fdt_resources(struct tegra_ahci_sc *sc)
356ef2ee5d0SMichal Meloun {
357b9cbd68dSMichal Meloun 	int i, rv;
358ef2ee5d0SMichal Meloun 
359b9cbd68dSMichal Meloun 	/* Enable regulators. */
360b9cbd68dSMichal Meloun 	for (i = 0; i < nitems(sc->regulators); i++) {
361b9cbd68dSMichal Meloun 		if (sc->regulators[i] == NULL)
362b9cbd68dSMichal Meloun 			continue;
363b9cbd68dSMichal Meloun 		rv = regulator_enable(sc->regulators[i]);
364ef2ee5d0SMichal Meloun 		if (rv != 0) {
365ef2ee5d0SMichal Meloun 			device_printf(sc->dev,
366b9cbd68dSMichal Meloun 			    "Cannot enable '%s' regulator\n",
367b9cbd68dSMichal Meloun 			    sc->soc->regulator_names[i]);
368ef2ee5d0SMichal Meloun 			return (rv);
369ef2ee5d0SMichal Meloun 		}
370ef2ee5d0SMichal Meloun 	}
371ef2ee5d0SMichal Meloun 
372ef2ee5d0SMichal Meloun 	/* Stop clocks */
373ef2ee5d0SMichal Meloun 	clk_stop(sc->clk_sata);
374ef2ee5d0SMichal Meloun 	clk_stop(sc->clk_sata_oob);
375ef2ee5d0SMichal Meloun 	tegra_powergate_power_off(TEGRA_POWERGATE_SAX);
376ef2ee5d0SMichal Meloun 
377ef2ee5d0SMichal Meloun 	rv = hwreset_assert(sc->hwreset_sata);
378ef2ee5d0SMichal Meloun 	if (rv != 0) {
379ef2ee5d0SMichal Meloun 		device_printf(sc->dev, "Cannot assert 'sata' reset\n");
380ef2ee5d0SMichal Meloun 		return (rv);
381ef2ee5d0SMichal Meloun 	}
382ef2ee5d0SMichal Meloun 	rv = hwreset_assert(sc->hwreset_sata_oob);
383ef2ee5d0SMichal Meloun 	if (rv != 0) {
384ef2ee5d0SMichal Meloun 		device_printf(sc->dev, "Cannot assert 'sata oob' reset\n");
385ef2ee5d0SMichal Meloun 		return (rv);
386ef2ee5d0SMichal Meloun 	}
387ef2ee5d0SMichal Meloun 
388ef2ee5d0SMichal Meloun 	rv = hwreset_assert(sc->hwreset_sata_cold);
389ef2ee5d0SMichal Meloun 	if (rv != 0) {
390ef2ee5d0SMichal Meloun 		device_printf(sc->dev, "Cannot assert 'sata cold' reset\n");
391ef2ee5d0SMichal Meloun 		return (rv);
392ef2ee5d0SMichal Meloun 	}
393ef2ee5d0SMichal Meloun 	rv = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_SAX,
394ef2ee5d0SMichal Meloun 	    sc->clk_sata, sc->hwreset_sata);
395ef2ee5d0SMichal Meloun 	if (rv != 0) {
396ef2ee5d0SMichal Meloun 		device_printf(sc->dev, "Cannot enable 'SAX' powergate\n");
397ef2ee5d0SMichal Meloun 		return (rv);
398ef2ee5d0SMichal Meloun 	}
399ef2ee5d0SMichal Meloun 
400ef2ee5d0SMichal Meloun 	rv = clk_enable(sc->clk_sata_oob);
401ef2ee5d0SMichal Meloun 	if (rv != 0) {
402ef2ee5d0SMichal Meloun 		device_printf(sc->dev, "Cannot enable 'sata oob' clock\n");
403ef2ee5d0SMichal Meloun 		return (rv);
404ef2ee5d0SMichal Meloun 	}
405b9cbd68dSMichal Meloun 	if (sc->clk_cml != NULL) {
406ef2ee5d0SMichal Meloun 		rv = clk_enable(sc->clk_cml);
407ef2ee5d0SMichal Meloun 		if (rv != 0) {
408ef2ee5d0SMichal Meloun 			device_printf(sc->dev, "Cannot enable 'cml' clock\n");
409ef2ee5d0SMichal Meloun 			return (rv);
410ef2ee5d0SMichal Meloun 		}
411b9cbd68dSMichal Meloun 	}
412b9cbd68dSMichal Meloun 	if (sc->clk_pll_e != NULL) {
413ef2ee5d0SMichal Meloun 		rv = clk_enable(sc->clk_pll_e);
414ef2ee5d0SMichal Meloun 		if (rv != 0) {
415ef2ee5d0SMichal Meloun 			device_printf(sc->dev, "Cannot enable 'pll e' clock\n");
416ef2ee5d0SMichal Meloun 			return (rv);
417ef2ee5d0SMichal Meloun 		}
418b9cbd68dSMichal Meloun 	}
419ef2ee5d0SMichal Meloun 
420ef2ee5d0SMichal Meloun 	rv = hwreset_deassert(sc->hwreset_sata_cold);
421ef2ee5d0SMichal Meloun 	if (rv != 0) {
422ef2ee5d0SMichal Meloun 		device_printf(sc->dev, "Cannot unreset 'sata cold' reset\n");
423ef2ee5d0SMichal Meloun 		return (rv);
424ef2ee5d0SMichal Meloun 	}
425ef2ee5d0SMichal Meloun 	rv = hwreset_deassert(sc->hwreset_sata_oob);
426ef2ee5d0SMichal Meloun 	if (rv != 0) {
427ef2ee5d0SMichal Meloun 		device_printf(sc->dev, "Cannot unreset 'sata oob' reset\n");
428ef2ee5d0SMichal Meloun 		return (rv);
429ef2ee5d0SMichal Meloun 	}
430ef2ee5d0SMichal Meloun 
431f8759facSMichal Meloun 	rv = phy_enable(sc->phy);
432ef2ee5d0SMichal Meloun 	if (rv != 0) {
433ef2ee5d0SMichal Meloun 		device_printf(sc->dev, "Cannot enable SATA phy\n");
434ef2ee5d0SMichal Meloun 		return (rv);
435ef2ee5d0SMichal Meloun 	}
436ef2ee5d0SMichal Meloun 
437ef2ee5d0SMichal Meloun 	return (0);
438ef2ee5d0SMichal Meloun }
439ef2ee5d0SMichal Meloun 
440ef2ee5d0SMichal Meloun static int
441b9cbd68dSMichal Meloun tegra124_ahci_init(struct tegra_ahci_sc *sc)
442ef2ee5d0SMichal Meloun {
443ef2ee5d0SMichal Meloun 	uint32_t val;
444ef2ee5d0SMichal Meloun 	const struct sata_pad_calibration *calib;
445ef2ee5d0SMichal Meloun 
446ef2ee5d0SMichal Meloun 	/* Pad calibration. */
447ef2ee5d0SMichal Meloun 	val = tegra_fuse_read_4(FUSE_SATA_CALIB);
448ef2ee5d0SMichal Meloun 	calib = tegra124_pad_calibration + (val & FUSE_SATA_CALIB_MASK);
449ef2ee5d0SMichal Meloun 	SATA_WR4(sc, SCFG_OFFSET + T_SATA0_INDEX, 1);
450ef2ee5d0SMichal Meloun 
451ef2ee5d0SMichal Meloun 	val = SATA_RD4(sc, SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL1_GEN1);
452ef2ee5d0SMichal Meloun 	val &= ~(T_SATA0_CHX_PHY_CTRL1_GEN1_TX_AMP_MASK <<
453ef2ee5d0SMichal Meloun 	    T_SATA0_CHX_PHY_CTRL1_GEN1_TX_AMP_SHIFT);
454ef2ee5d0SMichal Meloun 	val &= ~(T_SATA0_CHX_PHY_CTRL1_GEN1_TX_PEAK_MASK <<
455ef2ee5d0SMichal Meloun 	    T_SATA0_CHX_PHY_CTRL1_GEN1_TX_PEAK_SHIFT);
456ef2ee5d0SMichal Meloun 	val |= calib->gen1_tx_amp << T_SATA0_CHX_PHY_CTRL1_GEN1_TX_AMP_SHIFT;
457ef2ee5d0SMichal Meloun 	val |= calib->gen1_tx_peak << T_SATA0_CHX_PHY_CTRL1_GEN1_TX_PEAK_SHIFT;
458ef2ee5d0SMichal Meloun 	SATA_WR4(sc, SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL1_GEN1, val);
459ef2ee5d0SMichal Meloun 
460ef2ee5d0SMichal Meloun 	val = SATA_RD4(sc, SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL1_GEN2);
461ef2ee5d0SMichal Meloun 	val &= ~(T_SATA0_CHX_PHY_CTRL1_GEN2_TX_AMP_MASK <<
462ef2ee5d0SMichal Meloun 	    T_SATA0_CHX_PHY_CTRL1_GEN2_TX_AMP_SHIFT);
463ef2ee5d0SMichal Meloun 	val &= ~(T_SATA0_CHX_PHY_CTRL1_GEN2_TX_PEAK_MASK <<
464ef2ee5d0SMichal Meloun 	    T_SATA0_CHX_PHY_CTRL1_GEN2_TX_PEAK_SHIFT);
465ef2ee5d0SMichal Meloun 	val |= calib->gen2_tx_amp << T_SATA0_CHX_PHY_CTRL1_GEN2_TX_AMP_SHIFT;
466ef2ee5d0SMichal Meloun 	val |= calib->gen2_tx_peak << T_SATA0_CHX_PHY_CTRL1_GEN2_TX_PEAK_SHIFT;
467ef2ee5d0SMichal Meloun 	SATA_WR4(sc, SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL1_GEN2, val);
468ef2ee5d0SMichal Meloun 
469ef2ee5d0SMichal Meloun 	SATA_WR4(sc, SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL11,
470ef2ee5d0SMichal Meloun 	    T_SATA0_CHX_PHY_CTRL11_GEN2_RX_EQ);
471ef2ee5d0SMichal Meloun 
472ef2ee5d0SMichal Meloun 	SATA_WR4(sc, SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL2,
473ef2ee5d0SMichal Meloun 	    T_SATA0_CHX_PHY_CTRL2_CDR_CNTL_GEN1);
474ef2ee5d0SMichal Meloun 
475ef2ee5d0SMichal Meloun 	SATA_WR4(sc, SCFG_OFFSET + T_SATA0_INDEX, 0);
476ef2ee5d0SMichal Meloun 
477b9cbd68dSMichal Meloun 	return (0);
478b9cbd68dSMichal Meloun }
479b9cbd68dSMichal Meloun 
480b9cbd68dSMichal Meloun static int
481b9cbd68dSMichal Meloun tegra_ahci_ctrl_init(struct tegra_ahci_sc *sc)
482b9cbd68dSMichal Meloun {
483b9cbd68dSMichal Meloun 	uint32_t val;
484b9cbd68dSMichal Meloun 	int rv;
485b9cbd68dSMichal Meloun 
486b9cbd68dSMichal Meloun 	/* Enable SATA MMIO. */
487b9cbd68dSMichal Meloun 	val = SATA_RD4(sc, SATA_FPCI_BAR5);
488b9cbd68dSMichal Meloun 	val &= ~SATA_FPCI_BAR_START(~0);
489b9cbd68dSMichal Meloun 	val |= SATA_FPCI_BAR_START(0x10000);
490b9cbd68dSMichal Meloun 	val |= SATA_FPCI_BAR_ACCESS_TYPE;
491b9cbd68dSMichal Meloun 	SATA_WR4(sc, SATA_FPCI_BAR5, val);
492b9cbd68dSMichal Meloun 
493b9cbd68dSMichal Meloun 	/* Enable FPCI access */
494b9cbd68dSMichal Meloun 	val = SATA_RD4(sc, SATA_CONFIGURATION);
495b9cbd68dSMichal Meloun 	val |= SATA_CONFIGURATION_EN_FPCI;
496b9cbd68dSMichal Meloun 	SATA_WR4(sc, SATA_CONFIGURATION, val);
497b9cbd68dSMichal Meloun 
498b9cbd68dSMichal Meloun 	/* Recommended electrical settings for phy */
499b9cbd68dSMichal Meloun 	SATA_WR4(sc, SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL17, 0x55010000);
500b9cbd68dSMichal Meloun 	SATA_WR4(sc, SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL18, 0x55010000);
501b9cbd68dSMichal Meloun 	SATA_WR4(sc, SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL20, 0x1);
502b9cbd68dSMichal Meloun 	SATA_WR4(sc, SCFG_OFFSET + T_SATA0_CHX_PHY_CTRL21, 0x1);
503b9cbd68dSMichal Meloun 
504b9cbd68dSMichal Meloun 	/* SQUELCH and Gen3 */
505b9cbd68dSMichal Meloun 	val = SATA_RD4(sc, SCFG_OFFSET + T_SATA0_CFG_PHY);
506b9cbd68dSMichal Meloun 	val |= T_SATA0_CFG_PHY_MASK_SQUELCH;
507b9cbd68dSMichal Meloun 	val &= ~T_SATA0_CFG_PHY_USE_7BIT_ALIGN_DET_FOR_SPD;
508b9cbd68dSMichal Meloun 	SATA_WR4(sc, SCFG_OFFSET + T_SATA0_CFG_PHY, val);
509b9cbd68dSMichal Meloun 
510b9cbd68dSMichal Meloun 	val = SATA_RD4(sc, SCFG_OFFSET + T_SATA0_NVOOB);
511b9cbd68dSMichal Meloun 	val &= ~T_SATA0_NVOOB_COMMA_CNT_MASK;
512b9cbd68dSMichal Meloun 	val &= ~T_SATA0_NVOOB_SQUELCH_FILTER_LENGTH_MASK;
513b9cbd68dSMichal Meloun 	val &= ~T_SATA0_NVOOB_SQUELCH_FILTER_MODE_MASK;
514b9cbd68dSMichal Meloun 	val |= T_SATA0_NVOOB_COMMA_CNT;
515b9cbd68dSMichal Meloun 	val |= T_SATA0_NVOOB_SQUELCH_FILTER_LENGTH;
516b9cbd68dSMichal Meloun 	val |= T_SATA0_NVOOB_SQUELCH_FILTER_MODE;
517b9cbd68dSMichal Meloun 	SATA_WR4(sc, SCFG_OFFSET + T_SATA0_NVOOB, val);
518b9cbd68dSMichal Meloun 
519b9cbd68dSMichal Meloun 	 /* Setup COMWAKE_IDLE_CNT */
520b9cbd68dSMichal Meloun 	val = SATA_RD4(sc, SCFG_OFFSET + T_SATA0_CFG2NVOOB_2);
521b9cbd68dSMichal Meloun 	val &= ~T_SATA0_CFG2NVOOB_2_COMWAKE_IDLE_CNT_LOW_MASK;
522b9cbd68dSMichal Meloun 	val |= T_SATA0_CFG2NVOOB_2_COMWAKE_IDLE_CNT_LOW;
523b9cbd68dSMichal Meloun 	SATA_WR4(sc, SCFG_OFFSET + T_SATA0_CFG2NVOOB_2, val);
524b9cbd68dSMichal Meloun 
525b9cbd68dSMichal Meloun 	if (sc->soc->init != NULL) {
526b9cbd68dSMichal Meloun 		rv = sc->soc->init(sc);
527b9cbd68dSMichal Meloun 		if (rv != 0) {
528b9cbd68dSMichal Meloun 			device_printf(sc->dev,
529b9cbd68dSMichal Meloun 			    "SOC specific intialization failed: %d\n", rv);
530b9cbd68dSMichal Meloun 			return (rv);
531b9cbd68dSMichal Meloun 		}
532b9cbd68dSMichal Meloun 	}
533b9cbd68dSMichal Meloun 
534b9cbd68dSMichal Meloun 	/* Enable backdoor programming. */
535ef2ee5d0SMichal Meloun 	val = SATA_RD4(sc, SCFG_OFFSET + T_SATA0_CFG_SATA);
536ef2ee5d0SMichal Meloun 	val |= T_SATA0_CFG_SATA_BACKDOOR_PROG_IF_EN;
537ef2ee5d0SMichal Meloun 	SATA_WR4(sc, SCFG_OFFSET + T_SATA0_CFG_SATA, val);
538ef2ee5d0SMichal Meloun 
539b9cbd68dSMichal Meloun 	/* Set device class and interface */
540b9cbd68dSMichal Meloun 	val = SATA_RD4(sc, SCFG_OFFSET + T_SATA0_BKDOOR_CC);
541b9cbd68dSMichal Meloun 	val &= ~T_SATA0_BKDOOR_CC_CLASS_CODE_MASK;
542b9cbd68dSMichal Meloun 	val &= ~T_SATA0_BKDOOR_CC_PROG_IF_MASK;
543b9cbd68dSMichal Meloun 	val |= T_SATA0_BKDOOR_CC_CLASS_CODE;
544b9cbd68dSMichal Meloun 	val |= T_SATA0_BKDOOR_CC_PROG_IF;
545b9cbd68dSMichal Meloun 	SATA_WR4(sc, SCFG_OFFSET + T_SATA0_BKDOOR_CC, val);
546ef2ee5d0SMichal Meloun 
547b9cbd68dSMichal Meloun 	/* Enable LPM capabilities  */
548b9cbd68dSMichal Meloun 	val = SATA_RD4(sc, SCFG_OFFSET +  T_SATA0_AHCI_HBA_CAP_BKDR);
549b9cbd68dSMichal Meloun 	val |= T_SATA0_AHCI_HBA_CAP_BKDR_PARTIAL_ST_CAP;
550b9cbd68dSMichal Meloun 	val |= T_SATA0_AHCI_HBA_CAP_BKDR_SLUMBER_ST_CAP;
551b9cbd68dSMichal Meloun 	val |= T_SATA0_AHCI_HBA_CAP_BKDR_SALP;
552b9cbd68dSMichal Meloun 	val |= T_SATA0_AHCI_HBA_CAP_BKDR_SUPP_PM;
553b9cbd68dSMichal Meloun 	SATA_WR4(sc, SCFG_OFFSET + T_SATA0_AHCI_HBA_CAP_BKDR, val);
554b9cbd68dSMichal Meloun 
555b9cbd68dSMichal Meloun 	/* Disable backdoor programming. */
556ef2ee5d0SMichal Meloun 	val = SATA_RD4(sc, SCFG_OFFSET + T_SATA0_CFG_SATA);
557ef2ee5d0SMichal Meloun 	val &= ~T_SATA0_CFG_SATA_BACKDOOR_PROG_IF_EN;
558ef2ee5d0SMichal Meloun 	SATA_WR4(sc, SCFG_OFFSET + T_SATA0_CFG_SATA, val);
559ef2ee5d0SMichal Meloun 
560b9cbd68dSMichal Meloun 	/* SATA Second Level Clock Gating */
561b9cbd68dSMichal Meloun 	val = SATA_RD4(sc, SCFG_OFFSET + T_SATA0_CFG_35);
562b9cbd68dSMichal Meloun 	val &= ~T_SATA0_CFG_35_IDP_INDEX_MASK;
563b9cbd68dSMichal Meloun 	val |= T_SATA0_CFG_35_IDP_INDEX;
564b9cbd68dSMichal Meloun 	SATA_WR4(sc, SCFG_OFFSET + T_SATA0_CFG_35, val);
565b9cbd68dSMichal Meloun 
566b9cbd68dSMichal Meloun 	SATA_WR4(sc, SCFG_OFFSET + T_SATA0_AHCI_IDP1, 0x400040);
567b9cbd68dSMichal Meloun 
568b9cbd68dSMichal Meloun 	val = SATA_RD4(sc, SCFG_OFFSET + T_SATA0_CFG_PHY_1);
569b9cbd68dSMichal Meloun 	val |= T_SATA0_CFG_PHY_1_PADS_IDDQ_EN;
570b9cbd68dSMichal Meloun 	val |= T_SATA0_CFG_PHY_1_PAD_PLL_IDDQ_EN;
571b9cbd68dSMichal Meloun 	SATA_WR4(sc, SCFG_OFFSET + T_SATA0_CFG_PHY_1, val);
572b9cbd68dSMichal Meloun 
573b9cbd68dSMichal Meloun 	/*
574b9cbd68dSMichal Meloun 	 * Indicate Sata only has the capability to enter DevSleep
575b9cbd68dSMichal Meloun 	 * from slumber link.
576b9cbd68dSMichal Meloun 	 */
577b9cbd68dSMichal Meloun 	if (sc->aux_mem != NULL) {
578b9cbd68dSMichal Meloun 		val = bus_read_4(sc->aux_mem, SATA_AUX_MISC_CNTL_1);
579b9cbd68dSMichal Meloun 		val |= SATA_AUX_MISC_CNTL_1_DESO_SUPPORT;
580b9cbd68dSMichal Meloun 		bus_write_4(sc->aux_mem, SATA_AUX_MISC_CNTL_1, val);
581b9cbd68dSMichal Meloun 	}
582b9cbd68dSMichal Meloun 
583b9cbd68dSMichal Meloun 	/* Enable IPFS Clock Gating */
584b9cbd68dSMichal Meloun 	val = SATA_RD4(sc, SCFG_OFFSET + SATA_CONFIGURATION);
585b9cbd68dSMichal Meloun 	val &= ~SATA_CONFIGURATION_CLK_OVERRIDE;
586b9cbd68dSMichal Meloun 	SATA_WR4(sc, SCFG_OFFSET + SATA_CONFIGURATION, val);
587b9cbd68dSMichal Meloun 
588b9cbd68dSMichal Meloun 
589ef2ee5d0SMichal Meloun 	/* Enable IO & memory access, bus master mode */
590ef2ee5d0SMichal Meloun 	val = SATA_RD4(sc, SCFG_OFFSET + T_SATA0_CFG_1);
591ef2ee5d0SMichal Meloun 	val |= T_SATA0_CFG_1_IO_SPACE;
592ef2ee5d0SMichal Meloun 	val |= T_SATA0_CFG_1_MEMORY_SPACE;
593ef2ee5d0SMichal Meloun 	val |= T_SATA0_CFG_1_BUS_MASTER;
594ef2ee5d0SMichal Meloun 	val |= T_SATA0_CFG_1_SERR;
595ef2ee5d0SMichal Meloun 	SATA_WR4(sc, SCFG_OFFSET + T_SATA0_CFG_1, val);
596ef2ee5d0SMichal Meloun 
597ef2ee5d0SMichal Meloun 	/* AHCI bar */
598ef2ee5d0SMichal Meloun 	SATA_WR4(sc, SCFG_OFFSET + T_SATA0_CFG_9,
599ef2ee5d0SMichal Meloun 	    0x08000 << T_SATA0_CFG_9_BASE_ADDRESS_SHIFT);
600ef2ee5d0SMichal Meloun 
601ef2ee5d0SMichal Meloun 	/* Unmask  interrupts. */
602ef2ee5d0SMichal Meloun 	val = SATA_RD4(sc, SATA_INTR_MASK);
603ef2ee5d0SMichal Meloun 	val |= SATA_INTR_MASK_IP_INT_MASK;
604ef2ee5d0SMichal Meloun 	SATA_WR4(sc, SATA_INTR_MASK, val);
605ef2ee5d0SMichal Meloun 
606ef2ee5d0SMichal Meloun 	return (0);
607ef2ee5d0SMichal Meloun }
608ef2ee5d0SMichal Meloun 
609ef2ee5d0SMichal Meloun static int
610ef2ee5d0SMichal Meloun tegra_ahci_ctlr_reset(device_t dev)
611ef2ee5d0SMichal Meloun {
612ef2ee5d0SMichal Meloun 	struct tegra_ahci_sc *sc;
613ef2ee5d0SMichal Meloun 	int rv;
614ef2ee5d0SMichal Meloun 	uint32_t reg;
615ef2ee5d0SMichal Meloun 
616ef2ee5d0SMichal Meloun 	sc = device_get_softc(dev);
617ef2ee5d0SMichal Meloun 	rv = ahci_ctlr_reset(dev);
618ef2ee5d0SMichal Meloun 	if (rv != 0)
619ef2ee5d0SMichal Meloun 		return (0);
620ef2ee5d0SMichal Meloun 	AHCI_WR4(sc, T_AHCI_HBA_CCC_PORTS, 1);
621ef2ee5d0SMichal Meloun 
622ef2ee5d0SMichal Meloun 	/* Overwrite AHCI capabilites. */
623ef2ee5d0SMichal Meloun 	reg  = AHCI_RD4(sc, T_AHCI_HBA_CAP_BKDR);
624ef2ee5d0SMichal Meloun 	reg &= ~T_AHCI_HBA_CAP_BKDR_NUM_PORTS(~0);
625ef2ee5d0SMichal Meloun 	reg |= T_AHCI_HBA_CAP_BKDR_NUM_PORTS(0);
626ef2ee5d0SMichal Meloun 	reg |= T_AHCI_HBA_CAP_BKDR_EXT_SATA;
627ef2ee5d0SMichal Meloun 	reg |= T_AHCI_HBA_CAP_BKDR_CMD_CMPL_COALESING;
628ef2ee5d0SMichal Meloun 	reg |= T_AHCI_HBA_CAP_BKDR_FIS_SWITCHING;
629ef2ee5d0SMichal Meloun 	reg |= T_AHCI_HBA_CAP_BKDR_SUPP_PM;
630ef2ee5d0SMichal Meloun 	reg |= T_AHCI_HBA_CAP_BKDR_SUPP_CLO;
631ef2ee5d0SMichal Meloun 	reg |= T_AHCI_HBA_CAP_BKDR_SUPP_STG_SPUP;
632ef2ee5d0SMichal Meloun 	AHCI_WR4(sc, T_AHCI_HBA_CAP_BKDR, reg);
633ef2ee5d0SMichal Meloun 
634ef2ee5d0SMichal Meloun 	/* Overwrite AHCI portcapabilites. */
635ef2ee5d0SMichal Meloun 	reg  = AHCI_RD4(sc, T_AHCI_PORT_BKDR);
636ef2ee5d0SMichal Meloun 	reg |= T_AHCI_PORT_BKDR_COLD_PRSN_DET;
637ef2ee5d0SMichal Meloun 	reg |= T_AHCI_PORT_BKDR_HOTPLUG_CAP;
638ef2ee5d0SMichal Meloun 	reg |= T_AHCI_PORT_BKDR_EXT_SATA_SUPP;
639ef2ee5d0SMichal Meloun 	AHCI_WR4(sc, T_AHCI_PORT_BKDR, reg);
640ef2ee5d0SMichal Meloun 
641ef2ee5d0SMichal Meloun 	return (0);
642ef2ee5d0SMichal Meloun }
643ef2ee5d0SMichal Meloun 
644ef2ee5d0SMichal Meloun static int
645ef2ee5d0SMichal Meloun tegra_ahci_probe(device_t dev)
646ef2ee5d0SMichal Meloun {
647ef2ee5d0SMichal Meloun 
648ef2ee5d0SMichal Meloun 	if (!ofw_bus_status_okay(dev))
649ef2ee5d0SMichal Meloun 		return (ENXIO);
650ef2ee5d0SMichal Meloun 
651ef2ee5d0SMichal Meloun 	if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data)
652ef2ee5d0SMichal Meloun 		return (ENXIO);
653ef2ee5d0SMichal Meloun 
654*459dc61cSMark Johnston 	device_set_desc(dev, "AHCI SATA controller");
655ef2ee5d0SMichal Meloun 	return (BUS_PROBE_DEFAULT);
656ef2ee5d0SMichal Meloun }
657ef2ee5d0SMichal Meloun 
658ef2ee5d0SMichal Meloun static int
659ef2ee5d0SMichal Meloun tegra_ahci_attach(device_t dev)
660ef2ee5d0SMichal Meloun {
661ef2ee5d0SMichal Meloun 	struct tegra_ahci_sc *sc;
662ef2ee5d0SMichal Meloun 	struct ahci_controller *ctlr;
663ef2ee5d0SMichal Meloun 	phandle_t node;
664ef2ee5d0SMichal Meloun 	int rv, rid;
665ef2ee5d0SMichal Meloun 
666ef2ee5d0SMichal Meloun 	sc = device_get_softc(dev);
667ef2ee5d0SMichal Meloun 	sc->dev = dev;
668ef2ee5d0SMichal Meloun 	ctlr = &sc->ctlr;
669ef2ee5d0SMichal Meloun 	node = ofw_bus_get_node(dev);
670b9cbd68dSMichal Meloun 	sc->soc = (struct ahci_soc *)ofw_bus_search_compatible(dev,
671b9cbd68dSMichal Meloun 	    compat_data)->ocd_data;
672ef2ee5d0SMichal Meloun 
673ef2ee5d0SMichal Meloun 	ctlr->r_rid = 0;
674ef2ee5d0SMichal Meloun 	ctlr->r_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
675ef2ee5d0SMichal Meloun 	    &ctlr->r_rid, RF_ACTIVE);
676ef2ee5d0SMichal Meloun 	if (ctlr->r_mem == NULL)
677ef2ee5d0SMichal Meloun 		return (ENXIO);
678ef2ee5d0SMichal Meloun 
679ef2ee5d0SMichal Meloun 	rid = 1;
680ef2ee5d0SMichal Meloun 	sc->sata_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
681ef2ee5d0SMichal Meloun 	    &rid, RF_ACTIVE);
682ef2ee5d0SMichal Meloun 	if (sc->sata_mem == NULL) {
683ef2ee5d0SMichal Meloun 		rv = ENXIO;
684ef2ee5d0SMichal Meloun 		goto fail;
685ef2ee5d0SMichal Meloun 	}
686b9cbd68dSMichal Meloun 
687b9cbd68dSMichal Meloun 	/* Aux is optionall */
688b9cbd68dSMichal Meloun 	rid = 2;
689b9cbd68dSMichal Meloun 	sc->aux_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
690b9cbd68dSMichal Meloun 	    &rid, RF_ACTIVE);
691b9cbd68dSMichal Meloun 
692ef2ee5d0SMichal Meloun 	rv = get_fdt_resources(sc, node);
693ef2ee5d0SMichal Meloun 	if (rv != 0) {
694ef2ee5d0SMichal Meloun 		device_printf(sc->dev, "Failed to allocate FDT resource(s)\n");
695ef2ee5d0SMichal Meloun 		goto fail;
696ef2ee5d0SMichal Meloun 	}
697ef2ee5d0SMichal Meloun 
698ef2ee5d0SMichal Meloun 	rv = enable_fdt_resources(sc);
699ef2ee5d0SMichal Meloun 	if (rv != 0) {
700ef2ee5d0SMichal Meloun 		device_printf(sc->dev, "Failed to enable FDT resource(s)\n");
701ef2ee5d0SMichal Meloun 		goto fail;
702ef2ee5d0SMichal Meloun 	}
703ef2ee5d0SMichal Meloun 	rv = tegra_ahci_ctrl_init(sc);
704ef2ee5d0SMichal Meloun 	if (rv != 0) {
705ef2ee5d0SMichal Meloun 		device_printf(sc->dev, "Failed to initialize controller)\n");
706ef2ee5d0SMichal Meloun 		goto fail;
707ef2ee5d0SMichal Meloun 	}
708ef2ee5d0SMichal Meloun 
709ef2ee5d0SMichal Meloun 	/* Setup controller defaults. */
710ef2ee5d0SMichal Meloun 	ctlr->msi = 0;
711ef2ee5d0SMichal Meloun 	ctlr->numirqs = 1;
712ef2ee5d0SMichal Meloun 	ctlr->ccc = 0;
713ef2ee5d0SMichal Meloun 
714ef2ee5d0SMichal Meloun 	/* Reset controller. */
715ef2ee5d0SMichal Meloun 	rv = tegra_ahci_ctlr_reset(dev);
716ef2ee5d0SMichal Meloun 	if (rv != 0)
717ef2ee5d0SMichal Meloun 		goto fail;
718ef2ee5d0SMichal Meloun 	rv = ahci_attach(dev);
719ef2ee5d0SMichal Meloun 	return (rv);
720ef2ee5d0SMichal Meloun 
721ef2ee5d0SMichal Meloun fail:
722ef2ee5d0SMichal Meloun 	/* XXX FDT  stuff */
723ef2ee5d0SMichal Meloun 	if (sc->sata_mem != NULL)
724ef2ee5d0SMichal Meloun 		bus_release_resource(dev, SYS_RES_MEMORY, 1, sc->sata_mem);
725ef2ee5d0SMichal Meloun 	if (ctlr->r_mem != NULL)
726ef2ee5d0SMichal Meloun 		bus_release_resource(dev, SYS_RES_MEMORY, ctlr->r_rid,
727ef2ee5d0SMichal Meloun 		    ctlr->r_mem);
728ef2ee5d0SMichal Meloun 	return (rv);
729ef2ee5d0SMichal Meloun }
730ef2ee5d0SMichal Meloun 
731ef2ee5d0SMichal Meloun static int
732ef2ee5d0SMichal Meloun tegra_ahci_detach(device_t dev)
733ef2ee5d0SMichal Meloun {
734ef2ee5d0SMichal Meloun 
735ef2ee5d0SMichal Meloun 	ahci_detach(dev);
736ef2ee5d0SMichal Meloun 	return (0);
737ef2ee5d0SMichal Meloun }
738ef2ee5d0SMichal Meloun 
739ef2ee5d0SMichal Meloun static int
740ef2ee5d0SMichal Meloun tegra_ahci_suspend(device_t dev)
741ef2ee5d0SMichal Meloun {
742ef2ee5d0SMichal Meloun 	struct tegra_ahci_sc *sc = device_get_softc(dev);
743ef2ee5d0SMichal Meloun 
744ef2ee5d0SMichal Meloun 	bus_generic_suspend(dev);
745ef2ee5d0SMichal Meloun 	/* Disable interupts, so the state change(s) doesn't trigger. */
746ef2ee5d0SMichal Meloun 	ATA_OUTL(sc->ctlr.r_mem, AHCI_GHC,
747ef2ee5d0SMichal Meloun 	     ATA_INL(sc->ctlr.r_mem, AHCI_GHC) & (~AHCI_GHC_IE));
748ef2ee5d0SMichal Meloun 	return (0);
749ef2ee5d0SMichal Meloun }
750ef2ee5d0SMichal Meloun 
751ef2ee5d0SMichal Meloun static int
752ef2ee5d0SMichal Meloun tegra_ahci_resume(device_t dev)
753ef2ee5d0SMichal Meloun {
754ef2ee5d0SMichal Meloun 	int res;
755ef2ee5d0SMichal Meloun 
756ef2ee5d0SMichal Meloun 	if ((res = tegra_ahci_ctlr_reset(dev)) != 0)
757ef2ee5d0SMichal Meloun 		return (res);
758ef2ee5d0SMichal Meloun 	ahci_ctlr_setup(dev);
759ef2ee5d0SMichal Meloun 	return (bus_generic_resume(dev));
760ef2ee5d0SMichal Meloun }
761ef2ee5d0SMichal Meloun 
7621d59a5bbSMichal Meloun static device_method_t tegra_ahci_methods[] = {
763ef2ee5d0SMichal Meloun 	DEVMETHOD(device_probe,		tegra_ahci_probe),
764ef2ee5d0SMichal Meloun 	DEVMETHOD(device_attach,	tegra_ahci_attach),
765ef2ee5d0SMichal Meloun 	DEVMETHOD(device_detach,	tegra_ahci_detach),
766ef2ee5d0SMichal Meloun 	DEVMETHOD(device_suspend,	tegra_ahci_suspend),
767ef2ee5d0SMichal Meloun 	DEVMETHOD(device_resume,	tegra_ahci_resume),
768ef2ee5d0SMichal Meloun 	DEVMETHOD(bus_print_child,	ahci_print_child),
769ef2ee5d0SMichal Meloun 	DEVMETHOD(bus_alloc_resource,	ahci_alloc_resource),
770ef2ee5d0SMichal Meloun 	DEVMETHOD(bus_release_resource,	ahci_release_resource),
771ef2ee5d0SMichal Meloun 	DEVMETHOD(bus_setup_intr,	ahci_setup_intr),
772ef2ee5d0SMichal Meloun 	DEVMETHOD(bus_teardown_intr,	ahci_teardown_intr),
773ddfc9c4cSWarner Losh 	DEVMETHOD(bus_child_location,	ahci_child_location),
774ef2ee5d0SMichal Meloun 	DEVMETHOD(bus_get_dma_tag,	ahci_get_dma_tag),
775ef2ee5d0SMichal Meloun 
776ef2ee5d0SMichal Meloun 	DEVMETHOD_END
777ef2ee5d0SMichal Meloun };
7781d59a5bbSMichal Meloun 
7794bda238aSMichal Meloun static DEFINE_CLASS_0(ahci, tegra_ahci_driver, tegra_ahci_methods,
7804bda238aSMichal Meloun     sizeof(struct tegra_ahci_sc));
78123802d41SJohn Baldwin DRIVER_MODULE(tegra_ahci, simplebus, tegra_ahci_driver, NULL, NULL);
782