xref: /netbsd-src/sys/dev/ic/anx_dp.c (revision 82249e7b1dc8fd35a9ff1d0ac0d6d4ab0cb481c0)
1*82249e7bSmlelstv /* $NetBSD: anx_dp.c,v 1.6 2023/12/11 13:28:15 mlelstv Exp $ */
2ad370c5cSjakllsch 
3ad370c5cSjakllsch /*-
4ad370c5cSjakllsch  * Copyright (c) 2019 Jonathan A. Kollasch <jakllsch@kollasch.net>
5ad370c5cSjakllsch  * All rights reserved.
6ad370c5cSjakllsch  *
7ad370c5cSjakllsch  * Redistribution and use in source and binary forms, with or without
8ad370c5cSjakllsch  * modification, are permitted provided that the following conditions
9ad370c5cSjakllsch  * are met:
10ad370c5cSjakllsch  * 1. Redistributions of source code must retain the above copyright
11ad370c5cSjakllsch  *    notice, this list of conditions and the following disclaimer.
12ad370c5cSjakllsch  * 2. Redistributions in binary form must reproduce the above copyright
13ad370c5cSjakllsch  *    notice, this list of conditions and the following disclaimer in the
14ad370c5cSjakllsch  *    documentation and/or other materials provided with the distribution.
15ad370c5cSjakllsch  *
16ad370c5cSjakllsch  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17ad370c5cSjakllsch  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18ad370c5cSjakllsch  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19ad370c5cSjakllsch  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20ad370c5cSjakllsch  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21ad370c5cSjakllsch  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22ad370c5cSjakllsch  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23ad370c5cSjakllsch  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24ad370c5cSjakllsch  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25ad370c5cSjakllsch  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26ad370c5cSjakllsch  * SUCH DAMAGE.
27ad370c5cSjakllsch  */
28ad370c5cSjakllsch 
29ad370c5cSjakllsch #include <sys/cdefs.h>
30*82249e7bSmlelstv __KERNEL_RCSID(0, "$NetBSD: anx_dp.c,v 1.6 2023/12/11 13:28:15 mlelstv Exp $");
31ad370c5cSjakllsch 
32ad370c5cSjakllsch #include <sys/param.h>
33ad370c5cSjakllsch #include <sys/bus.h>
34dd47db3eSriastradh #include <sys/conf.h>
35ad370c5cSjakllsch #include <sys/device.h>
36ad370c5cSjakllsch #include <sys/intr.h>
37ad370c5cSjakllsch #include <sys/kernel.h>
38dd47db3eSriastradh #include <sys/systm.h>
39ad370c5cSjakllsch 
40ad370c5cSjakllsch #include <dev/ic/anx_dp.h>
41ad370c5cSjakllsch 
42ad370c5cSjakllsch #if ANXDP_AUDIO
43ad370c5cSjakllsch #include <dev/audio/audio_dai.h>
44ad370c5cSjakllsch #endif
45ad370c5cSjakllsch 
46d7c52d51Sriastradh #include <drm/drm_atomic_state_helper.h>
47ad370c5cSjakllsch #include <drm/drm_crtc.h>
48ad370c5cSjakllsch #include <drm/drm_crtc_helper.h>
49ad370c5cSjakllsch #include <drm/drm_dp_helper.h>
50dd47db3eSriastradh #include <drm/drm_drv.h>
51ad370c5cSjakllsch #include <drm/drm_edid.h>
52ad370c5cSjakllsch 
53ad370c5cSjakllsch #define	ANXDP_DP_TX_VERSION	0x010
54ad370c5cSjakllsch #define	ANXDP_TX_SW_RESET	0x014
55ad370c5cSjakllsch #define	 RESET_DP_TX			__BIT(0)
56ad370c5cSjakllsch #define	ANXDP_FUNC_EN_1		0x018
57ad370c5cSjakllsch #define	 MASTER_VID_FUNC_EN_N		__BIT(7)
58ad370c5cSjakllsch #define	 RK_VID_CAP_FUNC_EN_N		__BIT(6)
59ad370c5cSjakllsch #define	 SLAVE_VID_FUNC_EN_N		__BIT(5)
60ad370c5cSjakllsch #define	 RK_VID_FIFO_FUNC_EN_N		__BIT(5)
61ad370c5cSjakllsch #define	 AUD_FIFO_FUNC_EN_N		__BIT(4)
62ad370c5cSjakllsch #define	 AUD_FUNC_EN_N			__BIT(3)
63ad370c5cSjakllsch #define	 HDCP_FUNC_EN_N			__BIT(2)
64ad370c5cSjakllsch #define	 CRC_FUNC_EN_N			__BIT(1)
65ad370c5cSjakllsch #define	 SW_FUNC_EN_N			__BIT(0)
66ad370c5cSjakllsch #define	ANXDP_FUNC_EN_2		0x01c
67ad370c5cSjakllsch #define	 SSC_FUNC_EN_N			__BIT(7)
68ad370c5cSjakllsch #define	 AUX_FUNC_EN_N			__BIT(2)
69ad370c5cSjakllsch #define	 SERDES_FIFO_FUNC_EN_N		__BIT(1)
70ad370c5cSjakllsch #define	 LS_CLK_DOMAIN_FUNC_EN_N	__BIT(0)
71ad370c5cSjakllsch #define	ANXDP_VIDEO_CTL_1	0x020
72ad370c5cSjakllsch #define	 VIDEO_EN			__BIT(7)
73ad370c5cSjakllsch #define	 VIDEO_MUTE			__BIT(6)
74ad370c5cSjakllsch #define	ANXDP_VIDEO_CTL_2	0x024
75ad370c5cSjakllsch #define	ANXDP_VIDEO_CTL_3	0x028
76ad370c5cSjakllsch #define	ANXDP_VIDEO_CTL_4	0x02c
77ad370c5cSjakllsch #define	ANXDP_VIDEO_CTL_8	0x03c
78ad370c5cSjakllsch #define	ANXDP_VIDEO_CTL_10	0x044
79ad370c5cSjakllsch #define	 F_SEL				__BIT(4)
80ad370c5cSjakllsch #define	 SLAVE_I_SCAN_CFG		__BIT(2)
81ad370c5cSjakllsch #define	 SLAVE_VSYNC_P_CFG		__BIT(1)
82ad370c5cSjakllsch #define	 SLAVE_HSYNC_P_CFG		__BIT(0)
83ad370c5cSjakllsch #define	ANXDP_PLL_REG_1		0x0fc
84ad370c5cSjakllsch #define	 REF_CLK_24M			__BIT(0)
85ad370c5cSjakllsch #define	RKANXDP_PD		0x12c
86ad370c5cSjakllsch #define	 DP_INC_BG			__BIT(7)
87ad370c5cSjakllsch #define	 DP_EXP_PD			__BIT(6)
88ad370c5cSjakllsch #define	 DP_PHY_PD			__BIT(5)
89ad370c5cSjakllsch #define	 RK_AUX_PD			__BIT(5)
90ad370c5cSjakllsch #define	 AUX_PD				__BIT(4)
91ad370c5cSjakllsch #define	 RK_PLL_PD			__BIT(4)
92ad370c5cSjakllsch #define	 CHx_PD(x)			__BIT(x)	/* 0<=x<=3 */
93ad370c5cSjakllsch #define  DP_ALL_PD			__BITS(7,0)
94ad370c5cSjakllsch #define	ANXDP_LANE_MAP		0x35c
95ad370c5cSjakllsch #define ANXDP_ANALOG_CTL_1	0x370
96ad370c5cSjakllsch #define	 TX_TERMINAL_CTRL_50_OHM	__BIT(4)
97ad370c5cSjakllsch #define ANXDP_ANALOG_CTL_2	0x374
98ad370c5cSjakllsch #define	 SEL_24M			__BIT(3)
99ad370c5cSjakllsch #define	 TX_DVDD_BIT_1_0625V		0x4
100ad370c5cSjakllsch #define ANXDP_ANALOG_CTL_3	0x378
101ad370c5cSjakllsch #define	 DRIVE_DVDD_BIT_1_0625V		(0x4 << 5)
102ad370c5cSjakllsch #define	 VCO_BIT_600_MICRO		(0x5 << 0)
103ad370c5cSjakllsch #define ANXDP_PLL_FILTER_CTL_1	0x37c
104ad370c5cSjakllsch #define	 PD_RING_OSC			__BIT(6)
105ad370c5cSjakllsch #define	 AUX_TERMINAL_CTRL_50_OHM	(2 << 4)
106ad370c5cSjakllsch #define	 TX_CUR1_2X			__BIT(2)
107ad370c5cSjakllsch #define	 TX_CUR_16_MA			3
108ad370c5cSjakllsch #define ANXDP_TX_AMP_TUNING_CTL	0x380
109ad370c5cSjakllsch #define	ANXDP_AUX_HW_RETRY_CTL	0x390
110ad370c5cSjakllsch #define	 AUX_BIT_PERIOD_EXPECTED_DELAY(x) __SHIFTIN((x), __BITS(10,8))
111ad370c5cSjakllsch #define	 AUX_HW_RETRY_INTERVAL_600_US	__SHIFTIN(0, __BITS(4,3))
112ad370c5cSjakllsch #define	 AUX_HW_RETRY_INTERVAL_800_US	__SHIFTIN(1, __BITS(4,3))
113ad370c5cSjakllsch #define	 AUX_HW_RETRY_INTERVAL_1000_US	__SHIFTIN(2, __BITS(4,3))
114ad370c5cSjakllsch #define	 AUX_HW_RETRY_INTERVAL_1800_US	__SHIFTIN(3, __BITS(4,3))
115ad370c5cSjakllsch #define	 AUX_HW_RETRY_COUNT_SEL(x)	__SHIFTIN((x), __BITS(2,0))
116ad370c5cSjakllsch #define	ANXDP_COMMON_INT_STA_1	0x3c4
117ad370c5cSjakllsch #define	 PLL_LOCK_CHG			__BIT(6)
118ad370c5cSjakllsch #define	ANXDP_COMMON_INT_STA_2	0x3c8
119ad370c5cSjakllsch #define	ANXDP_COMMON_INT_STA_3	0x3cc
120ad370c5cSjakllsch #define	ANXDP_COMMON_INT_STA_4	0x3d0
121ad370c5cSjakllsch #define	ANXDP_DP_INT_STA	0x3dc
122ad370c5cSjakllsch #define	 INT_HPD			__BIT(6)
123ad370c5cSjakllsch #define	 HW_TRAINING_FINISH		__BIT(5)
124ad370c5cSjakllsch #define	 RPLY_RECEIV			__BIT(1)
125ad370c5cSjakllsch #define	 AUX_ERR			__BIT(0)
126ad370c5cSjakllsch #define	ANXDP_SYS_CTL_1		0x600
127ad370c5cSjakllsch #define	 DET_STA			__BIT(2)
128ad370c5cSjakllsch #define	 FORCE_DET			__BIT(1)
129ad370c5cSjakllsch #define	 DET_CTRL			__BIT(0)
130ad370c5cSjakllsch #define	ANXDP_SYS_CTL_2		0x604
131ad370c5cSjakllsch #define	ANXDP_SYS_CTL_3		0x608
132ad370c5cSjakllsch #define	 HPD_STATUS			__BIT(6)
133ad370c5cSjakllsch #define	 F_HPD				__BIT(5)
134ad370c5cSjakllsch #define	 HPD_CTRL			__BIT(4)
135ad370c5cSjakllsch #define	 HDCP_RDY			__BIT(3)
136ad370c5cSjakllsch #define	 STRM_VALID			__BIT(2)
137ad370c5cSjakllsch #define	 F_VALID			__BIT(1)
138ad370c5cSjakllsch #define	 VALID_CTRL			__BIT(0)
139ad370c5cSjakllsch #define	ANXDP_SYS_CTL_4		0x60c
140ad370c5cSjakllsch #define	ANXDP_PKT_SEND_CTL	0x640
141ad370c5cSjakllsch #define	ANXDP_HDCP_CTL		0x648
142ad370c5cSjakllsch #define	ANXDP_LINK_BW_SET	0x680
143ad370c5cSjakllsch #define	ANXDP_LANE_COUNT_SET	0x684
144ad370c5cSjakllsch #define	ANXDP_TRAINING_PTN_SET	0x688
145ad370c5cSjakllsch #define	 SCRAMBLING_DISABLE		__BIT(5)
146ad370c5cSjakllsch #define	 SW_TRAINING_PATTERN_SET_PTN2	__SHIFTIN(2, __BITS(1,0))
147ad370c5cSjakllsch #define	 SW_TRAINING_PATTERN_SET_PTN1	__SHIFTIN(1, __BITS(1,0))
148ad370c5cSjakllsch #define	ANXDP_LNx_LINK_TRAINING_CTL(x) (0x68c + 4 * (x)) /* 0 <= x <= 3 */
149ad370c5cSjakllsch #define	 MAX_PRE_REACH			__BIT(5)
150ad370c5cSjakllsch #define  PRE_EMPHASIS_SET(x)		__SHIFTIN((x), __BITS(4,3))
151ad370c5cSjakllsch #define	 MAX_DRIVE_REACH		__BIT(2)
152ad370c5cSjakllsch #define  DRIVE_CURRENT_SET(x)		__SHIFTIN((x), __BITS(1,0))
153ad370c5cSjakllsch #define	ANXDP_DEBUG_CTL		0x6c0
154ad370c5cSjakllsch #define	 PLL_LOCK			__BIT(4)
155ad370c5cSjakllsch #define	 F_PLL_LOCK			__BIT(3)
156ad370c5cSjakllsch #define	 PLL_LOCK_CTRL			__BIT(2)
157ad370c5cSjakllsch #define	 PN_INV				__BIT(0)
158ad370c5cSjakllsch #define	ANXDP_LINK_DEBUG_CTL	0x6e0
159ad370c5cSjakllsch #define	ANXDP_PLL_CTL		0x71c
160ad370c5cSjakllsch #define	ANXDP_PHY_PD		0x720
161ad370c5cSjakllsch #define	ANXDP_PHY_TEST		0x724
162ad370c5cSjakllsch #define	 MACRO_RST			__BIT(5)
163ad370c5cSjakllsch #define ANXDP_M_AUD_GEN_FILTER_TH 0x778
164ad370c5cSjakllsch #define	ANXDP_AUX_CH_STA	0x780
165ad370c5cSjakllsch #define	 AUX_BUSY			__BIT(4)
166ad370c5cSjakllsch #define	 AUX_STATUS(x)			__SHIFTOUT((x), __BITS(3,0))
167ad370c5cSjakllsch #define	ANXDP_AUX_ERR_NUM	0x784
168ad370c5cSjakllsch #define	ANXDP_AUX_CH_DEFER_CTL	0x788
169ad370c5cSjakllsch #define	 DEFER_CTRL_EN			__BIT(7)
170ad370c5cSjakllsch #define	 DEFER_COUNT(x)			__SHIFTIN((x), __BITS(6,0))
171ad370c5cSjakllsch #define	ANXDP_AUX_RX_COMM	0x78c
172ad370c5cSjakllsch #define	 AUX_RX_COMM_I2C_DEFER		__BIT(3)
173ad370c5cSjakllsch #define	 AUX_RX_COMM_AUX_DEFER		__BIT(1)
174ad370c5cSjakllsch #define	ANXDP_BUFFER_DATA_CTL	0x790
175ad370c5cSjakllsch #define	 BUF_CLR			__BIT(7)
176ad370c5cSjakllsch #define	 BUF_DATA_COUNT(x)		__SHIFTIN((x), __BITS(4,0))
177ad370c5cSjakllsch #define	ANXDP_AUX_CH_CTL_1	0x794
178ad370c5cSjakllsch #define	 AUX_LENGTH(x)			__SHIFTIN((x) - 1, __BITS(7,4))
179ad370c5cSjakllsch #define	 AUX_TX_COMM(x)			__SHIFTOUT(x, __BITS(3,0))
180ad370c5cSjakllsch #define	 AUX_TX_COMM_DP			__BIT(3)
181ad370c5cSjakllsch #define	 AUX_TX_COMM_MOT		__BIT(2)
182ad370c5cSjakllsch #define	 AUX_TX_COMM_READ		__BIT(0)
183ad370c5cSjakllsch #define	ANXDP_AUX_ADDR_7_0	0x798
184ad370c5cSjakllsch #define	 AUX_ADDR_7_0(x)	 (((x) >> 0) & 0xff)
185ad370c5cSjakllsch #define	ANXDP_AUX_ADDR_15_8	0x79c
186ad370c5cSjakllsch #define	 AUX_ADDR_15_8(x)	 (((x) >> 8) & 0xff)
187ad370c5cSjakllsch #define	ANXDP_AUX_ADDR_19_16	0x7a0
188ad370c5cSjakllsch #define	 AUX_ADDR_19_16(x)	 (((x) >> 16) & 0xf)
189ad370c5cSjakllsch #define	ANXDP_AUX_CH_CTL_2	0x7a4
190ad370c5cSjakllsch #define	 ADDR_ONLY			__BIT(1)
191ad370c5cSjakllsch #define	 AUX_EN				__BIT(0)
192ad370c5cSjakllsch #define	ANXDP_BUF_DATA(x)	(0x7c0 + 4 * (x))
193ad370c5cSjakllsch #define	ANXDP_SOC_GENERAL_CTL	0x800
194ad370c5cSjakllsch #define	 AUDIO_MODE_SPDIF_MODE		__BIT(8)
195ad370c5cSjakllsch #define	 VIDEO_MODE_SLAVE_MODE		__BIT(1)
196ad370c5cSjakllsch #define	ANXDP_CRC_CON		0x890
197ad370c5cSjakllsch #define	ANXDP_PLL_REG_2		0x9e4
198ad370c5cSjakllsch #define	ANXDP_PLL_REG_3		0x9e8
199ad370c5cSjakllsch #define	ANXDP_PLL_REG_4		0x9ec
200ad370c5cSjakllsch #define	ANXDP_PLL_REG_5		0xa00
201ad370c5cSjakllsch 
2023973e774Sriastradh struct anxdp_link {
2033973e774Sriastradh 	uint8_t	revision;
2043973e774Sriastradh 	u_int	rate;
2053973e774Sriastradh 	u_int	num_lanes;
2063973e774Sriastradh 	bool	enhanced_framing;
2073973e774Sriastradh };
2083973e774Sriastradh 
209ad370c5cSjakllsch #if ANXDP_AUDIO
210ad370c5cSjakllsch enum anxdp_dai_mixer_ctrl {
211ad370c5cSjakllsch 	ANXDP_DAI_OUTPUT_CLASS,
212ad370c5cSjakllsch 	ANXDP_DAI_INPUT_CLASS,
213ad370c5cSjakllsch 
214ad370c5cSjakllsch 	ANXDP_DAI_OUTPUT_MASTER_VOLUME,
215ad370c5cSjakllsch 	ANXDP_DAI_INPUT_DAC_VOLUME,
216ad370c5cSjakllsch 
217ad370c5cSjakllsch 	ANXDP_DAI_MIXER_CTRL_LAST
218ad370c5cSjakllsch };
219ad370c5cSjakllsch 
220ad370c5cSjakllsch static void
anxdp_audio_init(struct anxdp_softc * sc)221ad370c5cSjakllsch anxdp_audio_init(struct anxdp_softc *sc)
222ad370c5cSjakllsch {
223ad370c5cSjakllsch }
224ad370c5cSjakllsch #endif
225ad370c5cSjakllsch 
226ad370c5cSjakllsch static inline const bool
isrockchip(struct anxdp_softc * const sc)227ad370c5cSjakllsch isrockchip(struct anxdp_softc * const sc)
228ad370c5cSjakllsch {
229ad370c5cSjakllsch 	return (sc->sc_flags & ANXDP_FLAG_ROCKCHIP) != 0;
230ad370c5cSjakllsch }
231ad370c5cSjakllsch 
232ad370c5cSjakllsch static enum drm_connector_status
anxdp_connector_detect(struct drm_connector * connector,bool force)233ad370c5cSjakllsch anxdp_connector_detect(struct drm_connector *connector, bool force)
234ad370c5cSjakllsch {
235ad370c5cSjakllsch #if 0
236ad370c5cSjakllsch 	struct anxdp_connector *anxdp_connector = to_anxdp_connector(connector);
237ad370c5cSjakllsch 	struct anxdp_softc * const sc = anxdp_connector->sc;
238ad370c5cSjakllsch 
239ad370c5cSjakllsch 	/* XXX HPD */
240ad370c5cSjakllsch #endif
241ad370c5cSjakllsch 	return connector_status_connected;
242ad370c5cSjakllsch }
243ad370c5cSjakllsch 
244ad370c5cSjakllsch static void
anxdp_connector_destroy(struct drm_connector * connector)245ad370c5cSjakllsch anxdp_connector_destroy(struct drm_connector *connector)
246ad370c5cSjakllsch {
247ad370c5cSjakllsch 	drm_connector_unregister(connector);
248ad370c5cSjakllsch 	drm_connector_cleanup(connector);
249ad370c5cSjakllsch }
250ad370c5cSjakllsch 
251ad370c5cSjakllsch static const struct drm_connector_funcs anxdp_connector_funcs = {
252ad370c5cSjakllsch 	.dpms = drm_helper_connector_dpms,
253ad370c5cSjakllsch 	.detect = anxdp_connector_detect,
254ad370c5cSjakllsch 	.fill_modes = drm_helper_probe_single_connector_modes,
255ad370c5cSjakllsch 	.destroy = anxdp_connector_destroy,
256d7c52d51Sriastradh 	.reset = drm_atomic_helper_connector_reset,
257d7c52d51Sriastradh 	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
258d7c52d51Sriastradh 	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
259ad370c5cSjakllsch };
260ad370c5cSjakllsch 
261ad370c5cSjakllsch static void
anxdp_analog_power_up_all(struct anxdp_softc * const sc)262ad370c5cSjakllsch anxdp_analog_power_up_all(struct anxdp_softc * const sc)
263ad370c5cSjakllsch {
264ad370c5cSjakllsch 	const bus_size_t pd_reg = isrockchip(sc) ? RKANXDP_PD : ANXDP_PHY_PD;
265ad370c5cSjakllsch 
266ad370c5cSjakllsch 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, pd_reg, DP_ALL_PD);
267ad370c5cSjakllsch 	delay(15);
268ad370c5cSjakllsch 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, pd_reg,
269ad370c5cSjakllsch 	    DP_ALL_PD & ~DP_INC_BG);
270ad370c5cSjakllsch 	delay(15);
271ad370c5cSjakllsch 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, pd_reg, 0);
272ad370c5cSjakllsch }
273ad370c5cSjakllsch 
274ad370c5cSjakllsch static int
anxdp_await_pll_lock(struct anxdp_softc * const sc)275ad370c5cSjakllsch anxdp_await_pll_lock(struct anxdp_softc * const sc)
276ad370c5cSjakllsch {
277ad370c5cSjakllsch 	u_int timeout;
278ad370c5cSjakllsch 
279ad370c5cSjakllsch 	for (timeout = 0; timeout < 100; timeout++) {
280ad370c5cSjakllsch 		if ((bus_space_read_4(sc->sc_bst, sc->sc_bsh, ANXDP_DEBUG_CTL) &
281ad370c5cSjakllsch 		    PLL_LOCK) != 0)
282ad370c5cSjakllsch 			return 0;
283ad370c5cSjakllsch 		delay(20);
284ad370c5cSjakllsch 	}
285ad370c5cSjakllsch 
286ad370c5cSjakllsch 	return ETIMEDOUT;
287ad370c5cSjakllsch }
288ad370c5cSjakllsch 
289ad370c5cSjakllsch static void
anxdp_init_hpd(struct anxdp_softc * const sc)290ad370c5cSjakllsch anxdp_init_hpd(struct anxdp_softc * const sc)
291ad370c5cSjakllsch {
292ad370c5cSjakllsch 	uint32_t sc3;
293ad370c5cSjakllsch 
294ad370c5cSjakllsch 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, ANXDP_COMMON_INT_STA_4, 0x7);
295ad370c5cSjakllsch 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, ANXDP_DP_INT_STA, INT_HPD);
296ad370c5cSjakllsch 
297ad370c5cSjakllsch 	sc3 = bus_space_read_4(sc->sc_bst, sc->sc_bsh, ANXDP_SYS_CTL_3);
298ad370c5cSjakllsch 	sc3 &= ~(F_HPD | HPD_CTRL);
299ad370c5cSjakllsch 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, ANXDP_SYS_CTL_3, sc3);
300ad370c5cSjakllsch 
301ad370c5cSjakllsch 	sc3 = bus_space_read_4(sc->sc_bst, sc->sc_bsh, ANXDP_SYS_CTL_3);
302ad370c5cSjakllsch 	sc3 |= F_HPD | HPD_CTRL;
303ad370c5cSjakllsch 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, ANXDP_SYS_CTL_3, sc3);
304ad370c5cSjakllsch }
305ad370c5cSjakllsch 
306ad370c5cSjakllsch static void
anxdp_init_aux(struct anxdp_softc * const sc)307ad370c5cSjakllsch anxdp_init_aux(struct anxdp_softc * const sc)
308ad370c5cSjakllsch {
309ad370c5cSjakllsch 	uint32_t fe2, pd, hrc;
310ad370c5cSjakllsch 	const bus_size_t pd_reg = isrockchip(sc) ? RKANXDP_PD : ANXDP_PHY_PD;
311ad370c5cSjakllsch 	const uint32_t pd_mask = isrockchip(sc) ? RK_AUX_PD : AUX_PD;
312ad370c5cSjakllsch 
313ad370c5cSjakllsch 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, ANXDP_DP_INT_STA,
314ad370c5cSjakllsch 	    RPLY_RECEIV | AUX_ERR);
315ad370c5cSjakllsch 
316ad370c5cSjakllsch 	pd = bus_space_read_4(sc->sc_bst, sc->sc_bsh, pd_reg);
317ad370c5cSjakllsch 	pd |= pd_mask;
318ad370c5cSjakllsch 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, pd_reg, pd);
319ad370c5cSjakllsch 
320ad370c5cSjakllsch 	delay(11);
321ad370c5cSjakllsch 
322ad370c5cSjakllsch 	pd = bus_space_read_4(sc->sc_bst, sc->sc_bsh, pd_reg);
323ad370c5cSjakllsch 	pd &= ~pd_mask;
324ad370c5cSjakllsch 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, pd_reg, pd);
325ad370c5cSjakllsch 
326ad370c5cSjakllsch 	fe2 = bus_space_read_4(sc->sc_bst, sc->sc_bsh, ANXDP_FUNC_EN_2);
327ad370c5cSjakllsch 	fe2 |= AUX_FUNC_EN_N;
328ad370c5cSjakllsch 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, ANXDP_FUNC_EN_2, fe2);
329ad370c5cSjakllsch 
330ad370c5cSjakllsch 	hrc = AUX_HW_RETRY_COUNT_SEL(0) | AUX_HW_RETRY_INTERVAL_600_US;
331ad370c5cSjakllsch 	if (!isrockchip(sc))
332ad370c5cSjakllsch 		hrc |= AUX_BIT_PERIOD_EXPECTED_DELAY(3);
333ad370c5cSjakllsch 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, ANXDP_AUX_HW_RETRY_CTL, hrc);
334ad370c5cSjakllsch 
335ad370c5cSjakllsch 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, ANXDP_AUX_CH_DEFER_CTL,
336ad370c5cSjakllsch 	    DEFER_CTRL_EN | DEFER_COUNT(1));
337ad370c5cSjakllsch 
338ad370c5cSjakllsch 	fe2 = bus_space_read_4(sc->sc_bst, sc->sc_bsh, ANXDP_FUNC_EN_2);
339ad370c5cSjakllsch 	fe2 &= ~AUX_FUNC_EN_N;
340ad370c5cSjakllsch 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, ANXDP_FUNC_EN_2, fe2);
341ad370c5cSjakllsch }
342ad370c5cSjakllsch 
343ad370c5cSjakllsch static int
anxdp_connector_get_modes(struct drm_connector * connector)344ad370c5cSjakllsch anxdp_connector_get_modes(struct drm_connector *connector)
345ad370c5cSjakllsch {
346ad370c5cSjakllsch 	struct anxdp_connector *anxdp_connector = to_anxdp_connector(connector);
347ad370c5cSjakllsch 	struct anxdp_softc * const sc = anxdp_connector->sc;
348ad370c5cSjakllsch 	struct edid *pedid = NULL;
349ad370c5cSjakllsch 	int error;
350ad370c5cSjakllsch 
351ad370c5cSjakllsch 	pedid = drm_get_edid(connector, &sc->sc_dpaux.ddc);
352ad370c5cSjakllsch 
353ad370c5cSjakllsch #if ANXDP_AUDIO
354ad370c5cSjakllsch 	if (pedid) {
355ad370c5cSjakllsch 		anxdp_connector->monitor_audio =
356ad370c5cSjakllsch 		    drm_detect_monitor_audio(pedid);
357ad370c5cSjakllsch 	} else {
358ad370c5cSjakllsch 		anxdp_connector->monitor_audio = false;
359ad370c5cSjakllsch 	}
360ad370c5cSjakllsch 
361ad370c5cSjakllsch #endif
3623973e774Sriastradh 	drm_connector_update_edid_property(connector, pedid);
363ad370c5cSjakllsch 	if (pedid == NULL)
364ad370c5cSjakllsch 		return 0;
365ad370c5cSjakllsch 
366ad370c5cSjakllsch 	error = drm_add_edid_modes(connector, pedid);
367ad370c5cSjakllsch 
368ad370c5cSjakllsch 	if (pedid != NULL)
369ad370c5cSjakllsch 		kfree(pedid);
370ad370c5cSjakllsch 
371ad370c5cSjakllsch 	return error;
372ad370c5cSjakllsch }
373ad370c5cSjakllsch 
374d7c52d51Sriastradh static struct drm_encoder *
anxdp_connector_best_encoder(struct drm_connector * connector)375d7c52d51Sriastradh anxdp_connector_best_encoder(struct drm_connector *connector)
376d7c52d51Sriastradh {
377d7c52d51Sriastradh 	struct anxdp_connector *anxdp_connector = to_anxdp_connector(connector);
378d7c52d51Sriastradh 
379d7c52d51Sriastradh 	return anxdp_connector->encoder;
380d7c52d51Sriastradh }
381d7c52d51Sriastradh 
382ad370c5cSjakllsch static const struct drm_connector_helper_funcs anxdp_connector_helper_funcs = {
383ad370c5cSjakllsch 	.get_modes = anxdp_connector_get_modes,
384d7c52d51Sriastradh 	.best_encoder = anxdp_connector_best_encoder,
385ad370c5cSjakllsch };
386ad370c5cSjakllsch 
387ad370c5cSjakllsch static int
anxdp_bridge_attach(struct drm_bridge * bridge)388ad370c5cSjakllsch anxdp_bridge_attach(struct drm_bridge *bridge)
389ad370c5cSjakllsch {
390ad370c5cSjakllsch 	struct anxdp_softc * const sc = bridge->driver_private;
391ad370c5cSjakllsch 	struct anxdp_connector *anxdp_connector = &sc->sc_connector;
392ad370c5cSjakllsch 	struct drm_connector *connector = &anxdp_connector->base;
393ad370c5cSjakllsch 	int error;
394ad370c5cSjakllsch 
395ad370c5cSjakllsch 	anxdp_connector->sc = sc;
396ad370c5cSjakllsch 
397ad370c5cSjakllsch 	connector->polled =
398ad370c5cSjakllsch 	    DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT;
399ad370c5cSjakllsch 	connector->interlace_allowed = 0;
400ad370c5cSjakllsch 	connector->doublescan_allowed = 0;
401ad370c5cSjakllsch 
402ad370c5cSjakllsch 	drm_connector_init(bridge->dev, connector, &anxdp_connector_funcs,
403ad370c5cSjakllsch 	    connector->connector_type);
404ad370c5cSjakllsch 	drm_connector_helper_add(connector, &anxdp_connector_helper_funcs);
405ad370c5cSjakllsch 
4063973e774Sriastradh 	error = drm_connector_attach_encoder(connector, bridge->encoder);
407d7c52d51Sriastradh 	if (error)
408ad370c5cSjakllsch 		return error;
409ad370c5cSjakllsch 
410ad370c5cSjakllsch 	return drm_connector_register(connector);
411ad370c5cSjakllsch }
412ad370c5cSjakllsch 
413ad370c5cSjakllsch static void
anxdp_macro_reset(struct anxdp_softc * const sc)414ad370c5cSjakllsch anxdp_macro_reset(struct anxdp_softc * const sc)
415ad370c5cSjakllsch {
416ad370c5cSjakllsch 	uint32_t val;
417ad370c5cSjakllsch 
418ad370c5cSjakllsch 	val = bus_space_read_4(sc->sc_bst, sc->sc_bsh, ANXDP_PHY_TEST);
419ad370c5cSjakllsch 	val |= MACRO_RST;
420ad370c5cSjakllsch 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, ANXDP_PHY_TEST, val);
421ad370c5cSjakllsch 	delay(10);
422ad370c5cSjakllsch 	val &= ~MACRO_RST;
423ad370c5cSjakllsch 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, ANXDP_PHY_TEST, val);
424ad370c5cSjakllsch }
425ad370c5cSjakllsch 
426ad370c5cSjakllsch static void
anxdp_link_start(struct anxdp_softc * const sc,struct anxdp_link * const link)4273973e774Sriastradh anxdp_link_start(struct anxdp_softc * const sc, struct anxdp_link * const link)
428ad370c5cSjakllsch {
429ad370c5cSjakllsch 	uint8_t training[4];
4303973e774Sriastradh 	uint8_t bw[2];
431ad370c5cSjakllsch 	uint32_t val;
432d7c52d51Sriastradh 	int ret;
433ad370c5cSjakllsch 
434d7c52d51Sriastradh 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, ANXDP_LINK_BW_SET,
435d7c52d51Sriastradh 	    drm_dp_link_rate_to_bw_code(link->rate));
436d7c52d51Sriastradh 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, ANXDP_LANE_COUNT_SET,
437d7c52d51Sriastradh 	    link->num_lanes);
4383973e774Sriastradh 
4393973e774Sriastradh 	bw[0] = drm_dp_link_rate_to_bw_code(link->rate);
4403973e774Sriastradh 	bw[1] = link->num_lanes;
4413973e774Sriastradh 	if (link->enhanced_framing)
4423973e774Sriastradh 		bw[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
443d7c52d51Sriastradh 	ret = drm_dp_dpcd_write(&sc->sc_dpaux, DP_LINK_BW_SET, bw, sizeof(bw));
444d7c52d51Sriastradh 	if (ret < 0)
445ad370c5cSjakllsch 		return;
446ad370c5cSjakllsch 
447ad370c5cSjakllsch 	for (u_int i = 0; i < link->num_lanes; i++) {
448ad370c5cSjakllsch 		val = bus_space_read_4(sc->sc_bst, sc->sc_bsh,
449ad370c5cSjakllsch 		    ANXDP_LNx_LINK_TRAINING_CTL(i));
450ad370c5cSjakllsch 		val &= ~(PRE_EMPHASIS_SET(3)|DRIVE_CURRENT_SET(3));
451ad370c5cSjakllsch 		val |= PRE_EMPHASIS_SET(0);
452ad370c5cSjakllsch 		bus_space_write_4(sc->sc_bst, sc->sc_bsh,
453ad370c5cSjakllsch 		    ANXDP_LNx_LINK_TRAINING_CTL(i), val);
454ad370c5cSjakllsch 	}
455ad370c5cSjakllsch 
456ad370c5cSjakllsch 	if (anxdp_await_pll_lock(sc) != 0) {
457ad370c5cSjakllsch 		device_printf(sc->sc_dev, "PLL lock timeout\n");
458ad370c5cSjakllsch 	}
459ad370c5cSjakllsch 
460ad370c5cSjakllsch 	for (u_int i = 0; i < link->num_lanes; i++) {
461ad370c5cSjakllsch 		training[i] = DP_TRAIN_PRE_EMPH_LEVEL_0 |
462ad370c5cSjakllsch 		    DP_TRAIN_VOLTAGE_SWING_LEVEL_0;
463ad370c5cSjakllsch 	}
464ad370c5cSjakllsch 
465ad370c5cSjakllsch 	drm_dp_dpcd_write(&sc->sc_dpaux, DP_TRAINING_LANE0_SET, training,
466ad370c5cSjakllsch 	    link->num_lanes);
467ad370c5cSjakllsch }
468ad370c5cSjakllsch 
469ad370c5cSjakllsch static void
anxdp_process_clock_recovery(struct anxdp_softc * const sc,struct anxdp_link * const link)470ad370c5cSjakllsch anxdp_process_clock_recovery(struct anxdp_softc * const sc,
4713973e774Sriastradh     struct anxdp_link * const link)
472ad370c5cSjakllsch {
473ad370c5cSjakllsch 	u_int i, tries;
474ad370c5cSjakllsch 	uint8_t link_status[DP_LINK_STATUS_SIZE];
475ad370c5cSjakllsch 	uint8_t training[4];
476ad370c5cSjakllsch 
477ad370c5cSjakllsch 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, ANXDP_TRAINING_PTN_SET,
478ad370c5cSjakllsch 	    SCRAMBLING_DISABLE | SW_TRAINING_PATTERN_SET_PTN1);
479ad370c5cSjakllsch 	drm_dp_dpcd_writeb(&sc->sc_dpaux, DP_TRAINING_PATTERN_SET,
480ad370c5cSjakllsch 	    DP_LINK_SCRAMBLING_DISABLE | DP_TRAINING_PATTERN_1);
481ad370c5cSjakllsch 
482ad370c5cSjakllsch 	tries = 0;
483ad370c5cSjakllsch again:
484ad370c5cSjakllsch 	if (tries++ >= 10) {
485ad370c5cSjakllsch 		device_printf(sc->sc_dev, "cr fail\n");
486ad370c5cSjakllsch 		return;
487ad370c5cSjakllsch 	}
488ad370c5cSjakllsch 	drm_dp_link_train_clock_recovery_delay(sc->sc_dpcd);
489ad370c5cSjakllsch 	if (DP_LINK_STATUS_SIZE !=
490ad370c5cSjakllsch 	    drm_dp_dpcd_read_link_status(&sc->sc_dpaux, link_status)) {
491ad370c5cSjakllsch 		return;
492ad370c5cSjakllsch 	}
493ad370c5cSjakllsch 	if (!drm_dp_clock_recovery_ok(link_status, link->num_lanes)) {
494ad370c5cSjakllsch 		goto cr_fail;
495ad370c5cSjakllsch 	}
496ad370c5cSjakllsch 
497ad370c5cSjakllsch 	return;
498ad370c5cSjakllsch 
499ad370c5cSjakllsch cr_fail:
500ad370c5cSjakllsch 	for (i = 0; i < link->num_lanes; i++) {
501ad370c5cSjakllsch 		uint8_t vs, pe;
502ad370c5cSjakllsch 		vs = drm_dp_get_adjust_request_voltage(link_status, i);
503ad370c5cSjakllsch 		pe = drm_dp_get_adjust_request_pre_emphasis(link_status, i);
504ad370c5cSjakllsch 		training[i] = vs | pe;
505ad370c5cSjakllsch 	}
506ad370c5cSjakllsch 	for (i = 0; i < link->num_lanes; i++) {
507ad370c5cSjakllsch 		bus_space_write_4(sc->sc_bst, sc->sc_bsh,
508ad370c5cSjakllsch 		    ANXDP_LNx_LINK_TRAINING_CTL(i), training[i]);
509ad370c5cSjakllsch 	}
510ad370c5cSjakllsch 	drm_dp_dpcd_write(&sc->sc_dpaux, DP_TRAINING_LANE0_SET, training,
511ad370c5cSjakllsch 	    link->num_lanes);
512ad370c5cSjakllsch 	goto again;
513ad370c5cSjakllsch }
514ad370c5cSjakllsch 
515ad370c5cSjakllsch static void
anxdp_process_eq(struct anxdp_softc * const sc,struct anxdp_link * const link)5163973e774Sriastradh anxdp_process_eq(struct anxdp_softc * const sc, struct anxdp_link * const link)
517ad370c5cSjakllsch {
518ad370c5cSjakllsch 	u_int i, tries;
519ad370c5cSjakllsch 	uint8_t link_status[DP_LINK_STATUS_SIZE];
520ad370c5cSjakllsch 	uint8_t training[4];
521ad370c5cSjakllsch 
522ad370c5cSjakllsch 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, ANXDP_TRAINING_PTN_SET,
523ad370c5cSjakllsch 	    SCRAMBLING_DISABLE | SW_TRAINING_PATTERN_SET_PTN2);
524ad370c5cSjakllsch 	drm_dp_dpcd_writeb(&sc->sc_dpaux, DP_TRAINING_PATTERN_SET,
525ad370c5cSjakllsch 	    DP_LINK_SCRAMBLING_DISABLE | DP_TRAINING_PATTERN_2);
526ad370c5cSjakllsch 
527ad370c5cSjakllsch 	tries = 0;
528ad370c5cSjakllsch again:
529ad370c5cSjakllsch 	if (tries++ >= 10) {
530ad370c5cSjakllsch 		device_printf(sc->sc_dev, "eq fail\n");
531ad370c5cSjakllsch 		return;
532ad370c5cSjakllsch 	}
533ad370c5cSjakllsch 	drm_dp_link_train_channel_eq_delay(sc->sc_dpcd);
534ad370c5cSjakllsch 	if (DP_LINK_STATUS_SIZE !=
535ad370c5cSjakllsch 	    drm_dp_dpcd_read_link_status(&sc->sc_dpaux, link_status)) {
536ad370c5cSjakllsch 		return;
537ad370c5cSjakllsch 	}
538ad370c5cSjakllsch 	if (!drm_dp_channel_eq_ok(link_status, link->num_lanes)) {
539ad370c5cSjakllsch 		goto eq_fail;
540ad370c5cSjakllsch 	}
541ad370c5cSjakllsch 
542ad370c5cSjakllsch 	return;
543ad370c5cSjakllsch 
544ad370c5cSjakllsch eq_fail:
545ad370c5cSjakllsch 	for (i = 0; i < link->num_lanes; i++) {
546ad370c5cSjakllsch 		uint8_t vs, pe;
547ad370c5cSjakllsch 		vs = drm_dp_get_adjust_request_voltage(link_status, i);
548ad370c5cSjakllsch 		pe = drm_dp_get_adjust_request_pre_emphasis(link_status, i);
549ad370c5cSjakllsch 		training[i] = vs | pe;
550ad370c5cSjakllsch 	}
551ad370c5cSjakllsch 	for (i = 0; i < link->num_lanes; i++) {
552ad370c5cSjakllsch 		bus_space_write_4(sc->sc_bst, sc->sc_bsh,
553ad370c5cSjakllsch 		    ANXDP_LNx_LINK_TRAINING_CTL(i), training[i]);
554ad370c5cSjakllsch 	}
555ad370c5cSjakllsch 	drm_dp_dpcd_write(&sc->sc_dpaux, DP_TRAINING_LANE0_SET, training,
556ad370c5cSjakllsch 	    link->num_lanes);
557ad370c5cSjakllsch 	goto again;
558ad370c5cSjakllsch }
559ad370c5cSjakllsch 
560ad370c5cSjakllsch static void
anxdp_train_link(struct anxdp_softc * const sc)561ad370c5cSjakllsch anxdp_train_link(struct anxdp_softc * const sc)
562ad370c5cSjakllsch {
5633973e774Sriastradh 	struct anxdp_link link;
5643973e774Sriastradh 	uint8_t values[3], power;
565d7c52d51Sriastradh 	int ret;
566ad370c5cSjakllsch 
567ad370c5cSjakllsch 	anxdp_macro_reset(sc);
568ad370c5cSjakllsch 
569d7c52d51Sriastradh 	ret = drm_dp_dpcd_read(&sc->sc_dpaux, DP_DPCD_REV, values,
570d7c52d51Sriastradh 	    sizeof(values));
571d7c52d51Sriastradh 	if (ret < 0) {
572ad370c5cSjakllsch 		device_printf(sc->sc_dev, "link probe failed\n");
573ad370c5cSjakllsch 		return;
574ad370c5cSjakllsch 	}
5753973e774Sriastradh 	memset(&link, 0, sizeof(link));
5763973e774Sriastradh 	link.revision = values[0];
5773973e774Sriastradh 	link.rate = drm_dp_bw_code_to_link_rate(values[1]);
5783973e774Sriastradh 	link.num_lanes = values[2] & DP_MAX_LANE_COUNT_MASK;
5793973e774Sriastradh 	if (values[2] & DP_ENHANCED_FRAME_CAP)
5803973e774Sriastradh 		link.enhanced_framing = true;
5813973e774Sriastradh 
5823973e774Sriastradh 	if (link.revision >= 0x11) {
5833973e774Sriastradh 		if (drm_dp_dpcd_readb(&sc->sc_dpaux, DP_SET_POWER, &power) < 0)
584ad370c5cSjakllsch 			return;
5853973e774Sriastradh 		power &= ~DP_SET_POWER_MASK;
5863973e774Sriastradh 		power |= DP_SET_POWER_D0;
5873973e774Sriastradh 		if (drm_dp_dpcd_writeb(&sc->sc_dpaux, DP_SET_POWER, power) < 0)
5883973e774Sriastradh 			return;
5893973e774Sriastradh 		delay(2000);
5903973e774Sriastradh 	}
5913973e774Sriastradh 
592ad370c5cSjakllsch 	if (DP_RECEIVER_CAP_SIZE != drm_dp_dpcd_read(&sc->sc_dpaux, DP_DPCD_REV,
593ad370c5cSjakllsch 	    sc->sc_dpcd, DP_RECEIVER_CAP_SIZE))
594ad370c5cSjakllsch 		return;
595ad370c5cSjakllsch 
596ad370c5cSjakllsch 	anxdp_link_start(sc, &link);
597ad370c5cSjakllsch 	anxdp_process_clock_recovery(sc, &link);
598ad370c5cSjakllsch 	anxdp_process_eq(sc, &link);
599ad370c5cSjakllsch 
600ad370c5cSjakllsch 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, ANXDP_TRAINING_PTN_SET, 0);
601ad370c5cSjakllsch 	drm_dp_dpcd_writeb(&sc->sc_dpaux, DP_TRAINING_PATTERN_SET,
602ad370c5cSjakllsch 	    DP_TRAINING_PATTERN_DISABLE);
603ad370c5cSjakllsch 
604ad370c5cSjakllsch }
605ad370c5cSjakllsch 
606ad370c5cSjakllsch static void
anxdp_bringup(struct anxdp_softc * const sc)607ad370c5cSjakllsch anxdp_bringup(struct anxdp_softc * const sc)
608ad370c5cSjakllsch {
609ad370c5cSjakllsch 	uint32_t val;
610ad370c5cSjakllsch 
611ad370c5cSjakllsch 	val = bus_space_read_4(sc->sc_bst, sc->sc_bsh, ANXDP_VIDEO_CTL_1);
612ad370c5cSjakllsch 	val &= ~VIDEO_EN;
613ad370c5cSjakllsch 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, ANXDP_VIDEO_CTL_1, val);
614ad370c5cSjakllsch 
615ad370c5cSjakllsch 	val = bus_space_read_4(sc->sc_bst, sc->sc_bsh, ANXDP_VIDEO_CTL_1);
616ad370c5cSjakllsch 	val &= ~VIDEO_MUTE;
617ad370c5cSjakllsch 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, ANXDP_VIDEO_CTL_1, val);
618ad370c5cSjakllsch 
619ad370c5cSjakllsch 	val = SW_FUNC_EN_N;
620ad370c5cSjakllsch 	if (isrockchip(sc)) {
621ad370c5cSjakllsch 		val |= RK_VID_CAP_FUNC_EN_N | RK_VID_FIFO_FUNC_EN_N;
622ad370c5cSjakllsch 	} else {
623ad370c5cSjakllsch 		val |= MASTER_VID_FUNC_EN_N | SLAVE_VID_FUNC_EN_N |
624ad370c5cSjakllsch 		    AUD_FIFO_FUNC_EN_N | AUD_FUNC_EN_N | HDCP_FUNC_EN_N;
625ad370c5cSjakllsch 	}
626ad370c5cSjakllsch 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, ANXDP_FUNC_EN_1, val);
627ad370c5cSjakllsch 
628ad370c5cSjakllsch 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, ANXDP_FUNC_EN_2,
629ad370c5cSjakllsch 	    SSC_FUNC_EN_N | AUX_FUNC_EN_N | SERDES_FIFO_FUNC_EN_N |
630ad370c5cSjakllsch 	    LS_CLK_DOMAIN_FUNC_EN_N);
631ad370c5cSjakllsch 
632ad370c5cSjakllsch 	delay(30);
633ad370c5cSjakllsch 
634ad370c5cSjakllsch 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, ANXDP_M_AUD_GEN_FILTER_TH, 2);
635ad370c5cSjakllsch 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, ANXDP_SOC_GENERAL_CTL, 0x101);
636ad370c5cSjakllsch 
637ad370c5cSjakllsch 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, ANXDP_TX_SW_RESET,
638ad370c5cSjakllsch 	    RESET_DP_TX);
639ad370c5cSjakllsch 
640ad370c5cSjakllsch 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, ANXDP_ANALOG_CTL_1,
641ad370c5cSjakllsch 	    TX_TERMINAL_CTRL_50_OHM);
642ad370c5cSjakllsch 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, ANXDP_ANALOG_CTL_2,
643ad370c5cSjakllsch 	    SEL_24M | TX_DVDD_BIT_1_0625V);
644ad370c5cSjakllsch 	if (isrockchip(sc)) {
645ad370c5cSjakllsch 		bus_space_write_4(sc->sc_bst, sc->sc_bsh, ANXDP_PLL_REG_1,
646ad370c5cSjakllsch 		    REF_CLK_24M);
647ad370c5cSjakllsch 		bus_space_write_4(sc->sc_bst, sc->sc_bsh, ANXDP_PLL_REG_2,
648ad370c5cSjakllsch 		    0x95);
649ad370c5cSjakllsch 		bus_space_write_4(sc->sc_bst, sc->sc_bsh, ANXDP_PLL_REG_3,
650ad370c5cSjakllsch 		    0x40);
651ad370c5cSjakllsch 		bus_space_write_4(sc->sc_bst, sc->sc_bsh, ANXDP_PLL_REG_4,
652ad370c5cSjakllsch 		    0x58);
653ad370c5cSjakllsch 		bus_space_write_4(sc->sc_bst, sc->sc_bsh, ANXDP_PLL_REG_5,
654ad370c5cSjakllsch 		    0x22);
655ad370c5cSjakllsch 	}
656ad370c5cSjakllsch 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, ANXDP_ANALOG_CTL_3,
657ad370c5cSjakllsch 	    DRIVE_DVDD_BIT_1_0625V | VCO_BIT_600_MICRO);
658ad370c5cSjakllsch 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, ANXDP_PLL_FILTER_CTL_1,
659ad370c5cSjakllsch 	    PD_RING_OSC | AUX_TERMINAL_CTRL_50_OHM | TX_CUR1_2X | TX_CUR_16_MA);
660ad370c5cSjakllsch 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, ANXDP_TX_AMP_TUNING_CTL, 0);
661ad370c5cSjakllsch 
662ad370c5cSjakllsch 	val = bus_space_read_4(sc->sc_bst, sc->sc_bsh, ANXDP_FUNC_EN_1);
663ad370c5cSjakllsch 	val &= ~SW_FUNC_EN_N;
664ad370c5cSjakllsch 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, ANXDP_FUNC_EN_1, val);
665ad370c5cSjakllsch 
666ad370c5cSjakllsch 	anxdp_analog_power_up_all(sc);
667ad370c5cSjakllsch 
668ad370c5cSjakllsch 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, ANXDP_COMMON_INT_STA_1,
669ad370c5cSjakllsch 	    PLL_LOCK_CHG);
670ad370c5cSjakllsch 
671ad370c5cSjakllsch 	val = bus_space_read_4(sc->sc_bst, sc->sc_bsh, ANXDP_DEBUG_CTL);
672ad370c5cSjakllsch 	val &= ~(F_PLL_LOCK | PLL_LOCK_CTRL);
673ad370c5cSjakllsch 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, ANXDP_DEBUG_CTL, val);
674ad370c5cSjakllsch 
675ad370c5cSjakllsch 	if (anxdp_await_pll_lock(sc) != 0) {
676ad370c5cSjakllsch 		device_printf(sc->sc_dev, "PLL lock timeout\n");
677ad370c5cSjakllsch 	}
678ad370c5cSjakllsch 
679ad370c5cSjakllsch 	val = bus_space_read_4(sc->sc_bst, sc->sc_bsh, ANXDP_FUNC_EN_2);
680ad370c5cSjakllsch 	val &= ~(SERDES_FIFO_FUNC_EN_N | LS_CLK_DOMAIN_FUNC_EN_N |
681ad370c5cSjakllsch 	    AUX_FUNC_EN_N);
682ad370c5cSjakllsch 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, ANXDP_FUNC_EN_2, val);
683ad370c5cSjakllsch 
684ad370c5cSjakllsch 	anxdp_init_hpd(sc);
685ad370c5cSjakllsch 	anxdp_init_aux(sc);
686ad370c5cSjakllsch }
687ad370c5cSjakllsch 
688ad370c5cSjakllsch static void
anxdp_bridge_enable(struct drm_bridge * bridge)689ad370c5cSjakllsch anxdp_bridge_enable(struct drm_bridge *bridge)
690ad370c5cSjakllsch {
691ad370c5cSjakllsch 	struct anxdp_softc * const sc = bridge->driver_private;
692ad370c5cSjakllsch 	uint32_t val;
693ad370c5cSjakllsch 
694ad370c5cSjakllsch 	val = bus_space_read_4(sc->sc_bst, sc->sc_bsh, ANXDP_FUNC_EN_1);
695ad370c5cSjakllsch 	if (isrockchip(sc)) {
696ad370c5cSjakllsch 		val &= ~(RK_VID_CAP_FUNC_EN_N | RK_VID_FIFO_FUNC_EN_N);
697ad370c5cSjakllsch 	} else {
698ad370c5cSjakllsch 		val &= ~(MASTER_VID_FUNC_EN_N | SLAVE_VID_FUNC_EN_N);
699ad370c5cSjakllsch 		val |= MASTER_VID_FUNC_EN_N;
700ad370c5cSjakllsch 	}
701ad370c5cSjakllsch 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, ANXDP_FUNC_EN_1, val);
702ad370c5cSjakllsch 
703ad370c5cSjakllsch 	val = bus_space_read_4(sc->sc_bst, sc->sc_bsh, ANXDP_VIDEO_CTL_10);
704ad370c5cSjakllsch 	val &= ~(SLAVE_I_SCAN_CFG|SLAVE_VSYNC_P_CFG|SLAVE_HSYNC_P_CFG);
705ad370c5cSjakllsch 	if ((sc->sc_curmode.flags & DRM_MODE_FLAG_INTERLACE) != 0)
706ad370c5cSjakllsch 		val |= SLAVE_I_SCAN_CFG;
707ad370c5cSjakllsch 	if ((sc->sc_curmode.flags & DRM_MODE_FLAG_NVSYNC) != 0)
708ad370c5cSjakllsch 		val |= SLAVE_VSYNC_P_CFG;
709ad370c5cSjakllsch 	if ((sc->sc_curmode.flags & DRM_MODE_FLAG_NHSYNC) != 0)
710ad370c5cSjakllsch 		val |= SLAVE_HSYNC_P_CFG;
711ad370c5cSjakllsch 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, ANXDP_VIDEO_CTL_10, val);
712ad370c5cSjakllsch 
713ad370c5cSjakllsch 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, ANXDP_SOC_GENERAL_CTL,
714ad370c5cSjakllsch 	    AUDIO_MODE_SPDIF_MODE | VIDEO_MODE_SLAVE_MODE);
715ad370c5cSjakllsch 
716ad370c5cSjakllsch 	anxdp_train_link(sc);
717ad370c5cSjakllsch 
718ad370c5cSjakllsch 	val = bus_space_read_4(sc->sc_bst, sc->sc_bsh, ANXDP_VIDEO_CTL_1);
719ad370c5cSjakllsch 	val |= VIDEO_EN;
720ad370c5cSjakllsch 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, ANXDP_VIDEO_CTL_1, val);
721ad370c5cSjakllsch 
722ad370c5cSjakllsch 	if (sc->sc_panel != NULL &&
723ad370c5cSjakllsch 	    sc->sc_panel->funcs != NULL &&
724ad370c5cSjakllsch 	    sc->sc_panel->funcs->enable != NULL)
725ad370c5cSjakllsch 		sc->sc_panel->funcs->enable(sc->sc_panel);
726ad370c5cSjakllsch #if ANXDP_AUDIO
727ad370c5cSjakllsch 
728ad370c5cSjakllsch 	if (sc->sc_connector.monitor_audio)
729ad370c5cSjakllsch 		anxdp_audio_init(sc);
730ad370c5cSjakllsch #endif
731ad370c5cSjakllsch }
732ad370c5cSjakllsch 
733ad370c5cSjakllsch static void
anxdp_bridge_pre_enable(struct drm_bridge * bridge)734ad370c5cSjakllsch anxdp_bridge_pre_enable(struct drm_bridge *bridge)
735ad370c5cSjakllsch {
736ad370c5cSjakllsch }
737ad370c5cSjakllsch 
738ad370c5cSjakllsch static void
anxdp_bridge_disable(struct drm_bridge * bridge)739ad370c5cSjakllsch anxdp_bridge_disable(struct drm_bridge *bridge)
740ad370c5cSjakllsch {
741ad370c5cSjakllsch }
742ad370c5cSjakllsch 
743ad370c5cSjakllsch static void
anxdp_bridge_post_disable(struct drm_bridge * bridge)744ad370c5cSjakllsch anxdp_bridge_post_disable(struct drm_bridge *bridge)
745ad370c5cSjakllsch {
746ad370c5cSjakllsch }
747ad370c5cSjakllsch 
748ad370c5cSjakllsch static void
anxdp_bridge_mode_set(struct drm_bridge * bridge,const struct drm_display_mode * mode,const struct drm_display_mode * adjusted_mode)749ad370c5cSjakllsch anxdp_bridge_mode_set(struct drm_bridge *bridge,
750d7c52d51Sriastradh     const struct drm_display_mode *mode,
751d7c52d51Sriastradh     const struct drm_display_mode *adjusted_mode)
752ad370c5cSjakllsch {
753ad370c5cSjakllsch 	struct anxdp_softc * const sc = bridge->driver_private;
754ad370c5cSjakllsch 
755ad370c5cSjakllsch 	sc->sc_curmode = *adjusted_mode;
756ad370c5cSjakllsch }
757ad370c5cSjakllsch 
758ad370c5cSjakllsch static bool
anxdp_bridge_mode_fixup(struct drm_bridge * bridge,const struct drm_display_mode * mode,struct drm_display_mode * adjusted_mode)759ad370c5cSjakllsch anxdp_bridge_mode_fixup(struct drm_bridge *bridge,
760ad370c5cSjakllsch     const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode)
761ad370c5cSjakllsch {
762ad370c5cSjakllsch 	return true;
763ad370c5cSjakllsch }
764ad370c5cSjakllsch 
765ad370c5cSjakllsch static const struct drm_bridge_funcs anxdp_bridge_funcs = {
766ad370c5cSjakllsch 	.attach = anxdp_bridge_attach,
767ad370c5cSjakllsch 	.enable = anxdp_bridge_enable,
768ad370c5cSjakllsch 	.pre_enable = anxdp_bridge_pre_enable,
769ad370c5cSjakllsch 	.disable = anxdp_bridge_disable,
770ad370c5cSjakllsch 	.post_disable = anxdp_bridge_post_disable,
771ad370c5cSjakllsch 	.mode_set = anxdp_bridge_mode_set,
772ad370c5cSjakllsch 	.mode_fixup = anxdp_bridge_mode_fixup,
773ad370c5cSjakllsch };
774ad370c5cSjakllsch 
775ad370c5cSjakllsch #if ANXDP_AUDIO
776ad370c5cSjakllsch static int
anxdp_dai_set_format(audio_dai_tag_t dai,u_int format)777ad370c5cSjakllsch anxdp_dai_set_format(audio_dai_tag_t dai, u_int format)
778ad370c5cSjakllsch {
779ad370c5cSjakllsch 	return 0;
780ad370c5cSjakllsch }
781ad370c5cSjakllsch 
782ad370c5cSjakllsch static int
anxdp_dai_add_device(audio_dai_tag_t dai,audio_dai_tag_t aux)783ad370c5cSjakllsch anxdp_dai_add_device(audio_dai_tag_t dai, audio_dai_tag_t aux)
784ad370c5cSjakllsch {
785ad370c5cSjakllsch 	/* Not supported */
786ad370c5cSjakllsch 	return 0;
787ad370c5cSjakllsch }
788ad370c5cSjakllsch 
789ad370c5cSjakllsch static void
anxdp_audio_swvol_codec(audio_filter_arg_t * arg)790ad370c5cSjakllsch anxdp_audio_swvol_codec(audio_filter_arg_t *arg)
791ad370c5cSjakllsch {
792ad370c5cSjakllsch 	struct anxdp_softc * const sc = arg->context;
793ad370c5cSjakllsch 	const aint_t *src;
794*82249e7bSmlelstv 	int16_t *dst;
795ad370c5cSjakllsch 	u_int sample_count;
796ad370c5cSjakllsch 	u_int i;
797ad370c5cSjakllsch 
798ad370c5cSjakllsch 	src = arg->src;
799ad370c5cSjakllsch 	dst = arg->dst;
800ad370c5cSjakllsch 	sample_count = arg->count * arg->srcfmt->channels;
801ad370c5cSjakllsch 	for (i = 0; i < sample_count; i++) {
802ad370c5cSjakllsch 		aint2_t v = (aint2_t)(*src++);
803ad370c5cSjakllsch 		v = v * sc->sc_swvol / 255;
804ad370c5cSjakllsch 		*dst++ = (aint_t)v;
805ad370c5cSjakllsch 	}
806ad370c5cSjakllsch }
807ad370c5cSjakllsch 
808ad370c5cSjakllsch static int
anxdp_audio_set_format(void * priv,int setmode,const audio_params_t * play,const audio_params_t * rec,audio_filter_reg_t * pfil,audio_filter_reg_t * rfil)809ad370c5cSjakllsch anxdp_audio_set_format(void *priv, int setmode,
810ad370c5cSjakllsch     const audio_params_t *play, const audio_params_t *rec,
811ad370c5cSjakllsch     audio_filter_reg_t *pfil, audio_filter_reg_t *rfil)
812ad370c5cSjakllsch {
813ad370c5cSjakllsch 	struct anxdp_softc * const sc = priv;
814ad370c5cSjakllsch 
815ad370c5cSjakllsch 	pfil->codec = anxdp_audio_swvol_codec;
816ad370c5cSjakllsch 	pfil->context = sc;
817ad370c5cSjakllsch 
818ad370c5cSjakllsch 	return 0;
819ad370c5cSjakllsch }
820ad370c5cSjakllsch 
821ad370c5cSjakllsch static int
anxdp_audio_set_port(void * priv,mixer_ctrl_t * mc)822ad370c5cSjakllsch anxdp_audio_set_port(void *priv, mixer_ctrl_t *mc)
823ad370c5cSjakllsch {
824ad370c5cSjakllsch 	struct anxdp_softc * const sc = priv;
825ad370c5cSjakllsch 
826ad370c5cSjakllsch 	switch (mc->dev) {
827ad370c5cSjakllsch 	case ANXDP_DAI_OUTPUT_MASTER_VOLUME:
828ad370c5cSjakllsch 	case ANXDP_DAI_INPUT_DAC_VOLUME:
829ad370c5cSjakllsch 		sc->sc_swvol = mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
830ad370c5cSjakllsch 		return 0;
831ad370c5cSjakllsch 	default:
832ad370c5cSjakllsch 		return ENXIO;
833ad370c5cSjakllsch 	}
834ad370c5cSjakllsch }
835ad370c5cSjakllsch 
836ad370c5cSjakllsch static int
anxdp_audio_get_port(void * priv,mixer_ctrl_t * mc)837ad370c5cSjakllsch anxdp_audio_get_port(void *priv, mixer_ctrl_t *mc)
838ad370c5cSjakllsch {
839ad370c5cSjakllsch 	struct anxdp_softc * const sc = priv;
840ad370c5cSjakllsch 
841ad370c5cSjakllsch 	switch (mc->dev) {
842ad370c5cSjakllsch 	case ANXDP_DAI_OUTPUT_MASTER_VOLUME:
843ad370c5cSjakllsch 	case ANXDP_DAI_INPUT_DAC_VOLUME:
844ad370c5cSjakllsch 		mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = sc->sc_swvol;
845ad370c5cSjakllsch 		mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = sc->sc_swvol;
846ad370c5cSjakllsch 		return 0;
847ad370c5cSjakllsch 	default:
848ad370c5cSjakllsch 		return ENXIO;
849ad370c5cSjakllsch 	}
850ad370c5cSjakllsch }
851ad370c5cSjakllsch 
852ad370c5cSjakllsch static int
anxdp_audio_query_devinfo(void * priv,mixer_devinfo_t * di)853ad370c5cSjakllsch anxdp_audio_query_devinfo(void *priv, mixer_devinfo_t *di)
854ad370c5cSjakllsch {
855ad370c5cSjakllsch 	switch (di->index) {
856ad370c5cSjakllsch 	case ANXDP_DAI_OUTPUT_CLASS:
857ad370c5cSjakllsch 		di->mixer_class = di->index;
858ad370c5cSjakllsch 		strcpy(di->label.name, AudioCoutputs);
859ad370c5cSjakllsch 		di->type = AUDIO_MIXER_CLASS;
860ad370c5cSjakllsch 		di->next = di->prev = AUDIO_MIXER_LAST;
861ad370c5cSjakllsch 		return 0;
862ad370c5cSjakllsch 
863ad370c5cSjakllsch 	case ANXDP_DAI_INPUT_CLASS:
864ad370c5cSjakllsch 		di->mixer_class = di->index;
865ad370c5cSjakllsch 		strcpy(di->label.name, AudioCinputs);
866ad370c5cSjakllsch 		di->type = AUDIO_MIXER_CLASS;
867ad370c5cSjakllsch 		di->next = di->prev = AUDIO_MIXER_LAST;
868ad370c5cSjakllsch 		return 0;
869ad370c5cSjakllsch 
870ad370c5cSjakllsch 	case ANXDP_DAI_OUTPUT_MASTER_VOLUME:
871ad370c5cSjakllsch 		di->mixer_class = ANXDP_DAI_OUTPUT_CLASS;
872ad370c5cSjakllsch 		strcpy(di->label.name, AudioNmaster);
873ad370c5cSjakllsch 		di->un.v.delta = 1;
874ad370c5cSjakllsch 		di->un.v.num_channels = 2;
875ad370c5cSjakllsch 		strcpy(di->un.v.units.name, AudioNvolume);
876ad370c5cSjakllsch 		di->type = AUDIO_MIXER_VALUE;
877ad370c5cSjakllsch 		di->next = di->prev = AUDIO_MIXER_LAST;
878ad370c5cSjakllsch 		return 0;
879ad370c5cSjakllsch 
880ad370c5cSjakllsch 	case ANXDP_DAI_INPUT_DAC_VOLUME:
881ad370c5cSjakllsch 		di->mixer_class = ANXDP_DAI_INPUT_CLASS;
882ad370c5cSjakllsch 		strcpy(di->label.name, AudioNdac);
883ad370c5cSjakllsch 		di->un.v.delta = 1;
884ad370c5cSjakllsch 		di->un.v.num_channels = 2;
885ad370c5cSjakllsch 		strcpy(di->un.v.units.name, AudioNvolume);
886ad370c5cSjakllsch 		di->type = AUDIO_MIXER_VALUE;
887ad370c5cSjakllsch 		di->next = di->prev = AUDIO_MIXER_LAST;
888ad370c5cSjakllsch 		return 0;
889ad370c5cSjakllsch 
890ad370c5cSjakllsch 	default:
891ad370c5cSjakllsch 		return ENXIO;
892ad370c5cSjakllsch 	}
893ad370c5cSjakllsch }
894ad370c5cSjakllsch 
895ad370c5cSjakllsch static const struct audio_hw_if anxdp_dai_hw_if = {
896ad370c5cSjakllsch 	.set_format = anxdp_audio_set_format,
897ad370c5cSjakllsch 	.set_port = anxdp_audio_set_port,
898ad370c5cSjakllsch 	.get_port = anxdp_audio_get_port,
899ad370c5cSjakllsch 	.query_devinfo = anxdp_audio_query_devinfo,
900ad370c5cSjakllsch };
901ad370c5cSjakllsch #endif
902ad370c5cSjakllsch 
903ad370c5cSjakllsch static ssize_t
anxdp_dp_aux_transfer(struct drm_dp_aux * dpaux,struct drm_dp_aux_msg * dpmsg)904ad370c5cSjakllsch anxdp_dp_aux_transfer(struct drm_dp_aux *dpaux, struct drm_dp_aux_msg *dpmsg)
905ad370c5cSjakllsch {
906ad370c5cSjakllsch 	struct anxdp_softc * const sc = container_of(dpaux, struct anxdp_softc,
907ad370c5cSjakllsch 	    sc_dpaux);
908ad370c5cSjakllsch 	size_t loop_timeout = 0;
909ad370c5cSjakllsch 	uint32_t val;
910ad370c5cSjakllsch 	size_t i;
911ad370c5cSjakllsch 	ssize_t ret = 0;
912ad370c5cSjakllsch 
913ad370c5cSjakllsch 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, ANXDP_BUFFER_DATA_CTL,
914ad370c5cSjakllsch 	    BUF_CLR);
915ad370c5cSjakllsch 
916ad370c5cSjakllsch 	val = AUX_LENGTH(dpmsg->size);
917ad370c5cSjakllsch 	if ((dpmsg->request & DP_AUX_I2C_MOT) != 0)
918ad370c5cSjakllsch 		val |= AUX_TX_COMM_MOT;
919ad370c5cSjakllsch 
920ad370c5cSjakllsch 	switch (dpmsg->request & ~DP_AUX_I2C_MOT) {
921ad370c5cSjakllsch 	case DP_AUX_I2C_WRITE:
922ad370c5cSjakllsch 		break;
923ad370c5cSjakllsch 	case DP_AUX_I2C_READ:
924ad370c5cSjakllsch 		val |= AUX_TX_COMM_READ;
925ad370c5cSjakllsch 		break;
926ad370c5cSjakllsch 	case DP_AUX_NATIVE_WRITE:
927ad370c5cSjakllsch 		val |= AUX_TX_COMM_DP;
928ad370c5cSjakllsch 		break;
929ad370c5cSjakllsch 	case DP_AUX_NATIVE_READ:
930ad370c5cSjakllsch 		val |= AUX_TX_COMM_READ | AUX_TX_COMM_DP;
931ad370c5cSjakllsch 		break;
932ad370c5cSjakllsch 	}
933ad370c5cSjakllsch 
934ad370c5cSjakllsch 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, ANXDP_AUX_CH_CTL_1, val);
935ad370c5cSjakllsch 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, ANXDP_AUX_ADDR_7_0,
936ad370c5cSjakllsch 	    AUX_ADDR_7_0(dpmsg->address));
937ad370c5cSjakllsch 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, ANXDP_AUX_ADDR_15_8,
938ad370c5cSjakllsch 	    AUX_ADDR_15_8(dpmsg->address));
939ad370c5cSjakllsch 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, ANXDP_AUX_ADDR_19_16,
940ad370c5cSjakllsch 	    AUX_ADDR_19_16(dpmsg->address));
941ad370c5cSjakllsch 
942ad370c5cSjakllsch 	if (!(dpmsg->request & DP_AUX_I2C_READ)) {
943ad370c5cSjakllsch 		for (i = 0; i < dpmsg->size; i++) {
944ad370c5cSjakllsch 			bus_space_write_4(sc->sc_bst, sc->sc_bsh,
945ad370c5cSjakllsch 			    ANXDP_BUF_DATA(i),
946ad370c5cSjakllsch 			    ((const uint8_t *)(dpmsg->buffer))[i]);
947ad370c5cSjakllsch 			ret++;
948ad370c5cSjakllsch 		}
949ad370c5cSjakllsch 	}
950ad370c5cSjakllsch 
951ad370c5cSjakllsch 
952ad370c5cSjakllsch 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, ANXDP_AUX_CH_CTL_2,
953ad370c5cSjakllsch 	    AUX_EN | ((dpmsg->size == 0) ? ADDR_ONLY : 0));
954ad370c5cSjakllsch 
955ad370c5cSjakllsch 	loop_timeout = 0;
956ad370c5cSjakllsch 	val = bus_space_read_4(sc->sc_bst, sc->sc_bsh, ANXDP_AUX_CH_CTL_2);
957ad370c5cSjakllsch 	while ((val & AUX_EN) != 0) {
958ad370c5cSjakllsch 		if (++loop_timeout > 20000) {
959ad370c5cSjakllsch 			ret = -ETIMEDOUT;
960ad370c5cSjakllsch 			goto out;
961ad370c5cSjakllsch 		}
962ad370c5cSjakllsch 		delay(25);
963ad370c5cSjakllsch 		val = bus_space_read_4(sc->sc_bst, sc->sc_bsh,
964ad370c5cSjakllsch 		    ANXDP_AUX_CH_CTL_2);
965ad370c5cSjakllsch 	}
966ad370c5cSjakllsch 
967ad370c5cSjakllsch 	loop_timeout = 0;
968ad370c5cSjakllsch 	val = bus_space_read_4(sc->sc_bst, sc->sc_bsh, ANXDP_DP_INT_STA);
969ad370c5cSjakllsch 	while (!(val & RPLY_RECEIV)) {
970ad370c5cSjakllsch 		if (++loop_timeout > 2000) {
971ad370c5cSjakllsch 			ret = -ETIMEDOUT;
972ad370c5cSjakllsch 			goto out;
973ad370c5cSjakllsch 		}
974ad370c5cSjakllsch 		delay(10);
975ad370c5cSjakllsch 		val = bus_space_read_4(sc->sc_bst, sc->sc_bsh,
976ad370c5cSjakllsch 		    ANXDP_DP_INT_STA);
977ad370c5cSjakllsch 	}
978ad370c5cSjakllsch 
979ad370c5cSjakllsch 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, ANXDP_DP_INT_STA,
980ad370c5cSjakllsch 	    RPLY_RECEIV);
981ad370c5cSjakllsch 
982ad370c5cSjakllsch 	val = bus_space_read_4(sc->sc_bst, sc->sc_bsh, ANXDP_DP_INT_STA);
983ad370c5cSjakllsch 	if ((val & AUX_ERR) != 0) {
984ad370c5cSjakllsch 		bus_space_write_4(sc->sc_bst, sc->sc_bsh, ANXDP_DP_INT_STA,
985ad370c5cSjakllsch 		    AUX_ERR);
986ad370c5cSjakllsch 		ret = -EREMOTEIO;
987ad370c5cSjakllsch 		goto out;
988ad370c5cSjakllsch 	}
989ad370c5cSjakllsch 
990ad370c5cSjakllsch 	val = bus_space_read_4(sc->sc_bst, sc->sc_bsh, ANXDP_AUX_CH_STA);
991ad370c5cSjakllsch 	if (AUX_STATUS(val) != 0) {
992ad370c5cSjakllsch 		ret = -EREMOTEIO;
993ad370c5cSjakllsch 		goto out;
994ad370c5cSjakllsch 	}
995ad370c5cSjakllsch 
996ad370c5cSjakllsch 	if ((dpmsg->request & DP_AUX_I2C_READ)) {
997ad370c5cSjakllsch 		for (i = 0; i < dpmsg->size; i++) {
998ad370c5cSjakllsch 			val = bus_space_read_4(sc->sc_bst, sc->sc_bsh,
999ad370c5cSjakllsch 			    ANXDP_BUF_DATA(i));
1000ad370c5cSjakllsch 			((uint8_t *)(dpmsg->buffer))[i] = val & 0xffU;
1001ad370c5cSjakllsch 			ret++;
1002ad370c5cSjakllsch 		}
1003ad370c5cSjakllsch 	}
1004ad370c5cSjakllsch 
1005ad370c5cSjakllsch 	val = bus_space_read_4(sc->sc_bst, sc->sc_bsh, ANXDP_AUX_RX_COMM);
1006ad370c5cSjakllsch 	if (val == AUX_RX_COMM_AUX_DEFER)
1007ad370c5cSjakllsch 		dpmsg->reply = DP_AUX_NATIVE_REPLY_DEFER;
1008ad370c5cSjakllsch 	else if (val == AUX_RX_COMM_I2C_DEFER)
1009ad370c5cSjakllsch 		dpmsg->reply = DP_AUX_I2C_REPLY_DEFER;
1010ad370c5cSjakllsch 	else if ((dpmsg->request & ~DP_AUX_I2C_MOT) == DP_AUX_I2C_WRITE ||
1011ad370c5cSjakllsch 		 (dpmsg->request & ~DP_AUX_I2C_MOT) == DP_AUX_I2C_READ)
1012ad370c5cSjakllsch 		dpmsg->reply = DP_AUX_I2C_REPLY_ACK;
1013ad370c5cSjakllsch 	else if ((dpmsg->request & ~DP_AUX_I2C_MOT) == DP_AUX_NATIVE_WRITE ||
1014ad370c5cSjakllsch 		 (dpmsg->request & ~DP_AUX_I2C_MOT) == DP_AUX_NATIVE_READ)
1015ad370c5cSjakllsch 		dpmsg->reply = DP_AUX_NATIVE_REPLY_ACK;
1016ad370c5cSjakllsch 
1017ad370c5cSjakllsch out:
1018ad370c5cSjakllsch 	if (ret < 0)
1019ad370c5cSjakllsch 		anxdp_init_aux(sc);
1020ad370c5cSjakllsch 
1021ad370c5cSjakllsch 	return ret;
1022ad370c5cSjakllsch }
1023ad370c5cSjakllsch 
1024ad370c5cSjakllsch int
anxdp_attach(struct anxdp_softc * sc)1025ad370c5cSjakllsch anxdp_attach(struct anxdp_softc *sc)
1026ad370c5cSjakllsch {
1027ad370c5cSjakllsch #if ANXDP_AUDIO
1028ad370c5cSjakllsch 	sc->sc_swvol = 255;
1029ad370c5cSjakllsch 
1030ad370c5cSjakllsch 	/*
1031ad370c5cSjakllsch 	 * Initialize audio DAI
1032ad370c5cSjakllsch 	 */
1033ad370c5cSjakllsch 	sc->sc_dai.dai_set_format = anxdp_dai_set_format;
1034ad370c5cSjakllsch 	sc->sc_dai.dai_add_device = anxdp_dai_add_device;
1035ad370c5cSjakllsch 	sc->sc_dai.dai_hw_if = &anxdp_dai_hw_if;
1036ad370c5cSjakllsch 	sc->sc_dai.dai_dev = sc->sc_dev;
1037ad370c5cSjakllsch 	sc->sc_dai.dai_priv = sc;
1038ad370c5cSjakllsch #endif
1039ad370c5cSjakllsch 
1040ad370c5cSjakllsch 	sc->sc_dpaux.name = "DP Aux";
1041ad370c5cSjakllsch 	sc->sc_dpaux.transfer = anxdp_dp_aux_transfer;
1042ad370c5cSjakllsch 	sc->sc_dpaux.dev = sc->sc_dev;
1043ad370c5cSjakllsch 	if (drm_dp_aux_register(&sc->sc_dpaux) != 0) {
1044ad370c5cSjakllsch 		device_printf(sc->sc_dev, "registering DP Aux failed\n");
1045ad370c5cSjakllsch 	}
1046ad370c5cSjakllsch 
1047ad370c5cSjakllsch 	anxdp_bringup(sc);
1048ad370c5cSjakllsch 
1049ad370c5cSjakllsch 	return 0;
1050ad370c5cSjakllsch }
1051ad370c5cSjakllsch 
1052ad370c5cSjakllsch int
anxdp_bind(struct anxdp_softc * sc,struct drm_encoder * encoder)1053ad370c5cSjakllsch anxdp_bind(struct anxdp_softc *sc, struct drm_encoder *encoder)
1054ad370c5cSjakllsch {
1055ad370c5cSjakllsch 	int error;
1056ad370c5cSjakllsch 
1057d7c52d51Sriastradh 	sc->sc_connector.encoder = encoder;
1058d7c52d51Sriastradh 
1059ad370c5cSjakllsch 	sc->sc_bridge.driver_private = sc;
1060ad370c5cSjakllsch 	sc->sc_bridge.funcs = &anxdp_bridge_funcs;
1061ad370c5cSjakllsch 
10623973e774Sriastradh 	error = drm_bridge_attach(encoder, &sc->sc_bridge, NULL);
1063d7c52d51Sriastradh 	if (error)
1064ad370c5cSjakllsch 		return EIO;
1065ad370c5cSjakllsch 
1066d7c52d51Sriastradh 	if (sc->sc_panel != NULL &&
1067d7c52d51Sriastradh 	    sc->sc_panel->funcs != NULL &&
1068d7c52d51Sriastradh 	    sc->sc_panel->funcs->prepare != NULL)
1069ad370c5cSjakllsch 		sc->sc_panel->funcs->prepare(sc->sc_panel);
1070ad370c5cSjakllsch 
1071ad370c5cSjakllsch 	return 0;
1072ad370c5cSjakllsch }
1073ad370c5cSjakllsch 
1074ad370c5cSjakllsch void anxdp0_dump(void);
1075ad370c5cSjakllsch 
1076ad370c5cSjakllsch void
anxdp0_dump(void)1077ad370c5cSjakllsch anxdp0_dump(void)
1078ad370c5cSjakllsch {
1079ad370c5cSjakllsch 	extern struct cfdriver anxdp_cd;
1080ad370c5cSjakllsch 	struct anxdp_softc * const sc = device_lookup_private(&anxdp_cd, 0);
1081ad370c5cSjakllsch 	size_t i;
1082ad370c5cSjakllsch 
1083ad370c5cSjakllsch 	if (sc == NULL)
1084ad370c5cSjakllsch 		return;
1085ad370c5cSjakllsch 
1086ad370c5cSjakllsch 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, ANXDP_SYS_CTL_1,
1087ad370c5cSjakllsch 	    bus_space_read_4(sc->sc_bst, sc->sc_bsh, ANXDP_SYS_CTL_1));
1088ad370c5cSjakllsch 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, ANXDP_SYS_CTL_2,
1089ad370c5cSjakllsch 	    bus_space_read_4(sc->sc_bst, sc->sc_bsh, ANXDP_SYS_CTL_2));
1090ad370c5cSjakllsch 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, ANXDP_SYS_CTL_3,
1091ad370c5cSjakllsch 	    bus_space_read_4(sc->sc_bst, sc->sc_bsh, ANXDP_SYS_CTL_3));
1092ad370c5cSjakllsch 	for (i = 0x000; i < 0xb00; i += 4)
1093ad370c5cSjakllsch 		device_printf(sc->sc_dev, "%03zx 0x%08x\n", i,
1094ad370c5cSjakllsch 		    bus_space_read_4(sc->sc_bst, sc->sc_bsh, i));
1095ad370c5cSjakllsch }
1096