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