1*67b4eb14Sriastradh /* $NetBSD: anxedp.c,v 1.8 2021/12/19 11:01:10 riastradh Exp $ */
2f7483fa6Sjmcneill
3f7483fa6Sjmcneill /*-
4f7483fa6Sjmcneill * Copyright (c) 2019 Jared D. McNeill <jmcneill@invisible.ca>
5f7483fa6Sjmcneill * All rights reserved.
6f7483fa6Sjmcneill *
7f7483fa6Sjmcneill * Redistribution and use in source and binary forms, with or without
8f7483fa6Sjmcneill * modification, are permitted provided that the following conditions
9f7483fa6Sjmcneill * are met:
10f7483fa6Sjmcneill * 1. Redistributions of source code must retain the above copyright
11f7483fa6Sjmcneill * notice, this list of conditions and the following disclaimer.
12f7483fa6Sjmcneill * 2. Redistributions in binary form must reproduce the above copyright
13f7483fa6Sjmcneill * notice, this list of conditions and the following disclaimer in the
14f7483fa6Sjmcneill * documentation and/or other materials provided with the distribution.
15f7483fa6Sjmcneill *
16f7483fa6Sjmcneill * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17f7483fa6Sjmcneill * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18f7483fa6Sjmcneill * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19f7483fa6Sjmcneill * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20f7483fa6Sjmcneill * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21f7483fa6Sjmcneill * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22f7483fa6Sjmcneill * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23f7483fa6Sjmcneill * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24f7483fa6Sjmcneill * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25f7483fa6Sjmcneill * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26f7483fa6Sjmcneill * SUCH DAMAGE.
27f7483fa6Sjmcneill */
28f7483fa6Sjmcneill
29f7483fa6Sjmcneill #include <sys/cdefs.h>
30*67b4eb14Sriastradh __KERNEL_RCSID(0, "$NetBSD: anxedp.c,v 1.8 2021/12/19 11:01:10 riastradh Exp $");
31f7483fa6Sjmcneill
32f7483fa6Sjmcneill #include <sys/param.h>
33f7483fa6Sjmcneill #include <sys/bus.h>
34*67b4eb14Sriastradh #include <sys/conf.h>
35f7483fa6Sjmcneill #include <sys/device.h>
36f7483fa6Sjmcneill #include <sys/intr.h>
37f7483fa6Sjmcneill #include <sys/kernel.h>
38*67b4eb14Sriastradh #include <sys/systm.h>
39f7483fa6Sjmcneill
40f7483fa6Sjmcneill #include <dev/ic/dw_hdmi.h>
41f7483fa6Sjmcneill
42f7483fa6Sjmcneill #include <dev/i2c/ddcreg.h>
43*67b4eb14Sriastradh #include <dev/i2c/ddcvar.h>
44*67b4eb14Sriastradh #include <dev/i2c/i2cvar.h>
45f7483fa6Sjmcneill #include <dev/videomode/edidvar.h>
46f7483fa6Sjmcneill
47f7483fa6Sjmcneill #include <dev/fdt/fdt_port.h>
48*67b4eb14Sriastradh #include <dev/fdt/fdtvar.h>
49f7483fa6Sjmcneill
50c7fa00edSriastradh #include <drm/drm_connector.h>
51f7483fa6Sjmcneill #include <drm/drm_crtc.h>
52f7483fa6Sjmcneill #include <drm/drm_crtc_helper.h>
53*67b4eb14Sriastradh #include <drm/drm_drv.h>
54f7483fa6Sjmcneill #include <drm/drm_edid.h>
55c7fa00edSriastradh #include <drm/drm_probe_helper.h>
56f7483fa6Sjmcneill
57f7483fa6Sjmcneill #define ANX_DP_AUX_CH_CTL_1 0xe5
58f7483fa6Sjmcneill #define ANX_AUX_LENGTH __BITS(7,4)
59f7483fa6Sjmcneill #define ANX_AUX_TX_COMM __BITS(3,0)
60f7483fa6Sjmcneill #define ANX_AUX_TX_COMM_MOT 4
61f7483fa6Sjmcneill #define ANX_AUX_TX_COMM_READ 1
62f7483fa6Sjmcneill #define ANX_DP_AUX_ADDR(n) (0xe6 + (n))
63f7483fa6Sjmcneill #define ANX_DP_AUX_CH_CTL_2 0xe9
64f7483fa6Sjmcneill #define ANX_ADDR_ONLY __BIT(1)
65f7483fa6Sjmcneill #define ANX_AUX_EN __BIT(0)
66f7483fa6Sjmcneill #define ANX_BUF_DATA(n) (0xf0 + (n))
67f7483fa6Sjmcneill
68f7483fa6Sjmcneill #define ANX_DP_INT_STA 0xf7
69f7483fa6Sjmcneill #define ANX_RPLY_RECEIV __BIT(1)
70f7483fa6Sjmcneill
71f7483fa6Sjmcneill static const struct device_compatible_entry compat_data[] = {
723f1bcda8Sthorpej { .compat = "analogix,anx6345" },
7301632a17Sthorpej DEVICE_COMPAT_EOL
74f7483fa6Sjmcneill };
75f7483fa6Sjmcneill
76f7483fa6Sjmcneill struct anxedp_softc;
77f7483fa6Sjmcneill
78f7483fa6Sjmcneill struct anxedp_connector {
79f7483fa6Sjmcneill struct drm_connector base;
80f7483fa6Sjmcneill struct anxedp_softc *sc;
81f7483fa6Sjmcneill };
82f7483fa6Sjmcneill
83f7483fa6Sjmcneill struct anxedp_softc {
84f7483fa6Sjmcneill device_t sc_dev;
85f7483fa6Sjmcneill i2c_tag_t sc_i2c;
86f7483fa6Sjmcneill i2c_addr_t sc_addr;
87f7483fa6Sjmcneill int sc_phandle;
88f7483fa6Sjmcneill
89f7483fa6Sjmcneill struct anxedp_connector sc_connector;
90f7483fa6Sjmcneill struct drm_bridge sc_bridge;
91f7483fa6Sjmcneill
92f7483fa6Sjmcneill struct fdt_device_ports sc_ports;
93f7483fa6Sjmcneill struct drm_display_mode sc_curmode;
94f7483fa6Sjmcneill };
95f7483fa6Sjmcneill
96f7483fa6Sjmcneill #define to_anxedp_connector(x) container_of(x, struct anxedp_connector, base)
97f7483fa6Sjmcneill
98f7483fa6Sjmcneill static uint8_t
anxedp_read(struct anxedp_softc * sc,u_int off,uint8_t reg)99f7483fa6Sjmcneill anxedp_read(struct anxedp_softc *sc, u_int off, uint8_t reg)
100f7483fa6Sjmcneill {
101f7483fa6Sjmcneill uint8_t val;
102f7483fa6Sjmcneill
103e5b8f484Sthorpej if (iic_smbus_read_byte(sc->sc_i2c, sc->sc_addr + off, reg, &val, 0) != 0)
104f7483fa6Sjmcneill val = 0xff;
105f7483fa6Sjmcneill
106f7483fa6Sjmcneill return val;
107f7483fa6Sjmcneill }
108f7483fa6Sjmcneill
109f7483fa6Sjmcneill static void
anxedp_write(struct anxedp_softc * sc,u_int off,uint8_t reg,uint8_t val)110f7483fa6Sjmcneill anxedp_write(struct anxedp_softc *sc, u_int off, uint8_t reg, uint8_t val)
111f7483fa6Sjmcneill {
112e5b8f484Sthorpej (void)iic_smbus_write_byte(sc->sc_i2c, sc->sc_addr + off, reg, val, 0);
113f7483fa6Sjmcneill }
114f7483fa6Sjmcneill
115c129e06eSjmcneill static int
anxedp_connector_dpms(struct drm_connector * connector,int mode)116c129e06eSjmcneill anxedp_connector_dpms(struct drm_connector *connector, int mode)
117c129e06eSjmcneill {
118c129e06eSjmcneill int error;
119c129e06eSjmcneill
120c129e06eSjmcneill if (mode != DRM_MODE_DPMS_ON)
121c129e06eSjmcneill pmf_event_inject(NULL, PMFE_DISPLAY_OFF);
122c129e06eSjmcneill
123c129e06eSjmcneill error = drm_helper_connector_dpms(connector, mode);
124c129e06eSjmcneill
125c129e06eSjmcneill if (mode == DRM_MODE_DPMS_ON)
126c129e06eSjmcneill pmf_event_inject(NULL, PMFE_DISPLAY_ON);
127c129e06eSjmcneill
128c129e06eSjmcneill return error;
129c129e06eSjmcneill }
130c129e06eSjmcneill
131f7483fa6Sjmcneill static enum drm_connector_status
anxedp_connector_detect(struct drm_connector * connector,bool force)132f7483fa6Sjmcneill anxedp_connector_detect(struct drm_connector *connector, bool force)
133f7483fa6Sjmcneill {
134f7483fa6Sjmcneill return connector_status_connected;
135f7483fa6Sjmcneill }
136f7483fa6Sjmcneill
137f7483fa6Sjmcneill static void
anxedp_connector_destroy(struct drm_connector * connector)138f7483fa6Sjmcneill anxedp_connector_destroy(struct drm_connector *connector)
139f7483fa6Sjmcneill {
140f7483fa6Sjmcneill drm_connector_unregister(connector);
141f7483fa6Sjmcneill drm_connector_cleanup(connector);
142f7483fa6Sjmcneill }
143f7483fa6Sjmcneill
144f7483fa6Sjmcneill static const struct drm_connector_funcs anxedp_connector_funcs = {
145c129e06eSjmcneill .dpms = anxedp_connector_dpms,
146f7483fa6Sjmcneill .detect = anxedp_connector_detect,
147f7483fa6Sjmcneill .fill_modes = drm_helper_probe_single_connector_modes,
148f7483fa6Sjmcneill .destroy = anxedp_connector_destroy,
149f7483fa6Sjmcneill };
150f7483fa6Sjmcneill
151f7483fa6Sjmcneill static int
anxedp_aux_wait(struct anxedp_softc * sc)152f7483fa6Sjmcneill anxedp_aux_wait(struct anxedp_softc *sc)
153f7483fa6Sjmcneill {
154f7483fa6Sjmcneill uint8_t val;
155f7483fa6Sjmcneill int retry;
156f7483fa6Sjmcneill
157f7483fa6Sjmcneill for (retry = 1000; retry > 0; retry--) {
158f7483fa6Sjmcneill val = anxedp_read(sc, 0, ANX_DP_AUX_CH_CTL_2);
159f7483fa6Sjmcneill if ((val & ANX_AUX_EN) == 0)
160f7483fa6Sjmcneill break;
161f7483fa6Sjmcneill delay(100);
162f7483fa6Sjmcneill }
163f7483fa6Sjmcneill if (retry == 0) {
164f7483fa6Sjmcneill device_printf(sc->sc_dev, "aux transfer timeout\n");
165f7483fa6Sjmcneill return ETIMEDOUT;
166f7483fa6Sjmcneill }
167f7483fa6Sjmcneill
168f7483fa6Sjmcneill for (retry = 1000; retry > 0; retry--) {
169f7483fa6Sjmcneill val = anxedp_read(sc, 1, ANX_DP_INT_STA);
170f7483fa6Sjmcneill if ((val & ANX_RPLY_RECEIV) != 0) {
171f7483fa6Sjmcneill anxedp_write(sc, 1, ANX_DP_INT_STA, val);
172f7483fa6Sjmcneill break;
173f7483fa6Sjmcneill }
174f7483fa6Sjmcneill delay(100);
175f7483fa6Sjmcneill }
176f7483fa6Sjmcneill if (retry == 0) {
177f7483fa6Sjmcneill device_printf(sc->sc_dev, "aux transfer timeout\n");
178f7483fa6Sjmcneill return ETIMEDOUT;
179f7483fa6Sjmcneill }
180f7483fa6Sjmcneill
181f7483fa6Sjmcneill return 0;
182f7483fa6Sjmcneill }
183f7483fa6Sjmcneill
184f7483fa6Sjmcneill static int
anxedp_aux_transfer(struct anxedp_softc * sc,uint8_t comm,uint32_t addr,uint8_t * buf,int buflen)185f7483fa6Sjmcneill anxedp_aux_transfer(struct anxedp_softc *sc, uint8_t comm, uint32_t addr,
186f7483fa6Sjmcneill uint8_t *buf, int buflen)
187f7483fa6Sjmcneill {
188f7483fa6Sjmcneill uint8_t ctrl[2];
189f7483fa6Sjmcneill int n, error;
190f7483fa6Sjmcneill
191f7483fa6Sjmcneill ctrl[0] = __SHIFTIN(comm, ANX_AUX_TX_COMM);
192f7483fa6Sjmcneill if (buflen > 0)
193f7483fa6Sjmcneill ctrl[0] |= __SHIFTIN(buflen - 1, ANX_AUX_LENGTH);
194f7483fa6Sjmcneill ctrl[1] = ANX_AUX_EN;
195f7483fa6Sjmcneill if (buflen == 0)
196f7483fa6Sjmcneill ctrl[1] |= ANX_ADDR_ONLY;
197f7483fa6Sjmcneill
198f7483fa6Sjmcneill if (comm != ANX_AUX_TX_COMM_READ) {
199f7483fa6Sjmcneill for (n = 0; n < buflen; n++)
200f7483fa6Sjmcneill anxedp_write(sc, 0, ANX_BUF_DATA(n), buf[n]);
201f7483fa6Sjmcneill }
202f7483fa6Sjmcneill
203f7483fa6Sjmcneill anxedp_write(sc, 0, ANX_DP_AUX_ADDR(0), addr & 0xff);
204f7483fa6Sjmcneill anxedp_write(sc, 0, ANX_DP_AUX_ADDR(1), (addr >> 8) & 0xff);
205f7483fa6Sjmcneill anxedp_write(sc, 0, ANX_DP_AUX_ADDR(2), (addr >> 16) & 0xf);
206f7483fa6Sjmcneill anxedp_write(sc, 0, ANX_DP_AUX_CH_CTL_1, ctrl[0]);
207f7483fa6Sjmcneill anxedp_write(sc, 0, ANX_DP_AUX_CH_CTL_2, ctrl[1]);
208f7483fa6Sjmcneill
209f7483fa6Sjmcneill error = anxedp_aux_wait(sc);
210f7483fa6Sjmcneill if (error != 0)
211f7483fa6Sjmcneill return error;
212f7483fa6Sjmcneill
213f7483fa6Sjmcneill if (comm == ANX_AUX_TX_COMM_READ) {
214f7483fa6Sjmcneill for (n = 0; n < buflen; n++)
215f7483fa6Sjmcneill buf[n] = anxedp_read(sc, 0, ANX_BUF_DATA(n));
216f7483fa6Sjmcneill }
217f7483fa6Sjmcneill
218f7483fa6Sjmcneill return 0;
219f7483fa6Sjmcneill }
220f7483fa6Sjmcneill
221f7483fa6Sjmcneill static int
anxedp_read_edid(struct anxedp_softc * sc,uint8_t * edid,int edidlen)222f7483fa6Sjmcneill anxedp_read_edid(struct anxedp_softc *sc, uint8_t *edid, int edidlen)
223f7483fa6Sjmcneill {
224f7483fa6Sjmcneill int error;
225f7483fa6Sjmcneill uint8_t n;
226f7483fa6Sjmcneill
227f7483fa6Sjmcneill for (n = 0; n < edidlen; n += 16) {
228f7483fa6Sjmcneill const int xferlen = MIN(edidlen - n, 16);
229f7483fa6Sjmcneill
230f7483fa6Sjmcneill error = anxedp_aux_transfer(sc, ANX_AUX_TX_COMM_MOT, DDC_ADDR, &n, 1);
231f7483fa6Sjmcneill if (error != 0)
232f7483fa6Sjmcneill return error;
233f7483fa6Sjmcneill
234f7483fa6Sjmcneill error = anxedp_aux_transfer(sc, ANX_AUX_TX_COMM_READ, DDC_ADDR, &edid[n], xferlen);
235f7483fa6Sjmcneill if (error != 0)
236f7483fa6Sjmcneill return error;
237f7483fa6Sjmcneill }
238f7483fa6Sjmcneill
239f7483fa6Sjmcneill return 0;
240f7483fa6Sjmcneill }
241f7483fa6Sjmcneill
242f7483fa6Sjmcneill static int
anxedp_connector_get_modes(struct drm_connector * connector)243f7483fa6Sjmcneill anxedp_connector_get_modes(struct drm_connector *connector)
244f7483fa6Sjmcneill {
245f7483fa6Sjmcneill struct anxedp_connector *anxedp_connector = to_anxedp_connector(connector);
246f7483fa6Sjmcneill struct anxedp_softc * const sc = anxedp_connector->sc;
247f7483fa6Sjmcneill char edid[EDID_LENGTH];
248f7483fa6Sjmcneill struct edid *pedid = NULL;
249f7483fa6Sjmcneill int error;
250f7483fa6Sjmcneill
251e5b8f484Sthorpej iic_acquire_bus(sc->sc_i2c, 0);
252f7483fa6Sjmcneill error = anxedp_read_edid(sc, edid, sizeof(edid));
253e5b8f484Sthorpej iic_release_bus(sc->sc_i2c, 0);
254f7483fa6Sjmcneill if (error == 0)
255f7483fa6Sjmcneill pedid = (struct edid *)edid;
256f7483fa6Sjmcneill
257c7fa00edSriastradh drm_connector_update_edid_property(connector, pedid);
258f7483fa6Sjmcneill if (pedid == NULL)
259f7483fa6Sjmcneill return 0;
260f7483fa6Sjmcneill
261c7fa00edSriastradh return drm_add_edid_modes(connector, pedid);
262f7483fa6Sjmcneill }
263f7483fa6Sjmcneill
264f7483fa6Sjmcneill static const struct drm_connector_helper_funcs anxedp_connector_helper_funcs = {
265f7483fa6Sjmcneill .get_modes = anxedp_connector_get_modes,
266f7483fa6Sjmcneill };
267f7483fa6Sjmcneill
268f7483fa6Sjmcneill static int
anxedp_bridge_attach(struct drm_bridge * bridge)269f7483fa6Sjmcneill anxedp_bridge_attach(struct drm_bridge *bridge)
270f7483fa6Sjmcneill {
271f7483fa6Sjmcneill struct anxedp_softc * const sc = bridge->driver_private;
272f7483fa6Sjmcneill struct anxedp_connector *anxedp_connector = &sc->sc_connector;
273f7483fa6Sjmcneill struct drm_connector *connector = &anxedp_connector->base;
274f7483fa6Sjmcneill int error;
275f7483fa6Sjmcneill
276f7483fa6Sjmcneill anxedp_connector->sc = sc;
277f7483fa6Sjmcneill
278f7483fa6Sjmcneill connector->polled = DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT;
279f7483fa6Sjmcneill connector->interlace_allowed = 0;
280f7483fa6Sjmcneill connector->doublescan_allowed = 0;
281f7483fa6Sjmcneill
282f7483fa6Sjmcneill drm_connector_init(bridge->dev, connector, &anxedp_connector_funcs,
283f7483fa6Sjmcneill connector->connector_type);
284f7483fa6Sjmcneill drm_connector_helper_add(connector, &anxedp_connector_helper_funcs);
285f7483fa6Sjmcneill
286c7fa00edSriastradh error = drm_connector_attach_encoder(connector, bridge->encoder);
287f7483fa6Sjmcneill if (error != 0)
288f7483fa6Sjmcneill return error;
289f7483fa6Sjmcneill
290f7483fa6Sjmcneill return drm_connector_register(connector);
291f7483fa6Sjmcneill }
292f7483fa6Sjmcneill
293f7483fa6Sjmcneill static void
anxedp_bridge_enable(struct drm_bridge * bridge)294f7483fa6Sjmcneill anxedp_bridge_enable(struct drm_bridge *bridge)
295f7483fa6Sjmcneill {
296f7483fa6Sjmcneill }
297f7483fa6Sjmcneill
298f7483fa6Sjmcneill static void
anxedp_bridge_pre_enable(struct drm_bridge * bridge)299f7483fa6Sjmcneill anxedp_bridge_pre_enable(struct drm_bridge *bridge)
300f7483fa6Sjmcneill {
301f7483fa6Sjmcneill }
302f7483fa6Sjmcneill
303f7483fa6Sjmcneill static void
anxedp_bridge_disable(struct drm_bridge * bridge)304f7483fa6Sjmcneill anxedp_bridge_disable(struct drm_bridge *bridge)
305f7483fa6Sjmcneill {
306f7483fa6Sjmcneill }
307f7483fa6Sjmcneill
308f7483fa6Sjmcneill static void
anxedp_bridge_post_disable(struct drm_bridge * bridge)309f7483fa6Sjmcneill anxedp_bridge_post_disable(struct drm_bridge *bridge)
310f7483fa6Sjmcneill {
311f7483fa6Sjmcneill }
312f7483fa6Sjmcneill
313f7483fa6Sjmcneill static void
anxedp_bridge_mode_set(struct drm_bridge * bridge,const struct drm_display_mode * mode,const struct drm_display_mode * adjusted_mode)314f7483fa6Sjmcneill anxedp_bridge_mode_set(struct drm_bridge *bridge,
315c7fa00edSriastradh const struct drm_display_mode *mode,
316c7fa00edSriastradh const struct drm_display_mode *adjusted_mode)
317f7483fa6Sjmcneill {
318f7483fa6Sjmcneill struct anxedp_softc * const sc = bridge->driver_private;
319f7483fa6Sjmcneill
320f7483fa6Sjmcneill sc->sc_curmode = *adjusted_mode;
321f7483fa6Sjmcneill }
322f7483fa6Sjmcneill
323f7483fa6Sjmcneill static bool
anxedp_bridge_mode_fixup(struct drm_bridge * bridge,const struct drm_display_mode * mode,struct drm_display_mode * adjusted_mode)324f7483fa6Sjmcneill anxedp_bridge_mode_fixup(struct drm_bridge *bridge,
325f7483fa6Sjmcneill const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode)
326f7483fa6Sjmcneill {
327f7483fa6Sjmcneill return true;
328f7483fa6Sjmcneill }
329f7483fa6Sjmcneill
330f7483fa6Sjmcneill static const struct drm_bridge_funcs anxedp_bridge_funcs = {
331f7483fa6Sjmcneill .attach = anxedp_bridge_attach,
332f7483fa6Sjmcneill .enable = anxedp_bridge_enable,
333f7483fa6Sjmcneill .pre_enable = anxedp_bridge_pre_enable,
334f7483fa6Sjmcneill .disable = anxedp_bridge_disable,
335f7483fa6Sjmcneill .post_disable = anxedp_bridge_post_disable,
336f7483fa6Sjmcneill .mode_set = anxedp_bridge_mode_set,
337f7483fa6Sjmcneill .mode_fixup = anxedp_bridge_mode_fixup,
338f7483fa6Sjmcneill };
339f7483fa6Sjmcneill
340f7483fa6Sjmcneill static int
anxedp_ep_activate(device_t dev,struct fdt_endpoint * ep,bool activate)341f7483fa6Sjmcneill anxedp_ep_activate(device_t dev, struct fdt_endpoint *ep, bool activate)
342f7483fa6Sjmcneill {
343f7483fa6Sjmcneill struct anxedp_softc * const sc = device_private(dev);
344f7483fa6Sjmcneill struct fdt_endpoint *in_ep = fdt_endpoint_remote(ep);
345f7483fa6Sjmcneill struct drm_encoder *encoder;
346f7483fa6Sjmcneill struct drm_bridge *bridge;
347f7483fa6Sjmcneill int error;
348f7483fa6Sjmcneill
349f7483fa6Sjmcneill if (!activate)
350f7483fa6Sjmcneill return EINVAL;
351f7483fa6Sjmcneill
352f7483fa6Sjmcneill if (fdt_endpoint_port_index(ep) != 0)
353f7483fa6Sjmcneill return EINVAL;
354f7483fa6Sjmcneill
355f7483fa6Sjmcneill switch (fdt_endpoint_type(in_ep)) {
356f7483fa6Sjmcneill case EP_DRM_ENCODER:
357f7483fa6Sjmcneill encoder = fdt_endpoint_get_data(in_ep);
358f7483fa6Sjmcneill break;
359f7483fa6Sjmcneill case EP_DRM_BRIDGE:
360f7483fa6Sjmcneill bridge = fdt_endpoint_get_data(in_ep);
361f7483fa6Sjmcneill encoder = bridge->encoder;
362f7483fa6Sjmcneill break;
363f7483fa6Sjmcneill default:
364f7483fa6Sjmcneill encoder = NULL;
365f7483fa6Sjmcneill break;
366f7483fa6Sjmcneill }
367f7483fa6Sjmcneill
368f7483fa6Sjmcneill if (encoder == NULL)
369f7483fa6Sjmcneill return EINVAL;
370f7483fa6Sjmcneill
371f7483fa6Sjmcneill sc->sc_connector.base.connector_type = DRM_MODE_CONNECTOR_eDP;
372f7483fa6Sjmcneill
373f7483fa6Sjmcneill sc->sc_bridge.driver_private = sc;
374f7483fa6Sjmcneill sc->sc_bridge.funcs = &anxedp_bridge_funcs;
375f7483fa6Sjmcneill sc->sc_bridge.encoder = encoder;
376f7483fa6Sjmcneill
377c7fa00edSriastradh error = drm_bridge_attach(encoder, &sc->sc_bridge, NULL);
378f7483fa6Sjmcneill if (error != 0)
379f7483fa6Sjmcneill return EIO;
380f7483fa6Sjmcneill
381f7483fa6Sjmcneill return 0;
382f7483fa6Sjmcneill }
383f7483fa6Sjmcneill
384f7483fa6Sjmcneill static void *
anxedp_ep_get_data(device_t dev,struct fdt_endpoint * ep)385f7483fa6Sjmcneill anxedp_ep_get_data(device_t dev, struct fdt_endpoint *ep)
386f7483fa6Sjmcneill {
387f7483fa6Sjmcneill struct anxedp_softc * const sc = device_private(dev);
388f7483fa6Sjmcneill
389f7483fa6Sjmcneill return &sc->sc_bridge;
390f7483fa6Sjmcneill }
391f7483fa6Sjmcneill
392f7483fa6Sjmcneill static int
anxedp_match(device_t parent,cfdata_t match,void * aux)393f7483fa6Sjmcneill anxedp_match(device_t parent, cfdata_t match, void *aux)
394f7483fa6Sjmcneill {
395f7483fa6Sjmcneill struct i2c_attach_args *ia = aux;
396f7483fa6Sjmcneill int match_result;
397f7483fa6Sjmcneill
398f7483fa6Sjmcneill if (iic_use_direct_match(ia, match, compat_data, &match_result))
399f7483fa6Sjmcneill return match_result;
400f7483fa6Sjmcneill
401f7483fa6Sjmcneill /* This device is direct-config only */
402f7483fa6Sjmcneill
403f7483fa6Sjmcneill return 0;
404f7483fa6Sjmcneill }
405f7483fa6Sjmcneill
406f7483fa6Sjmcneill static void
anxedp_attach(device_t parent,device_t self,void * aux)407f7483fa6Sjmcneill anxedp_attach(device_t parent, device_t self, void *aux)
408f7483fa6Sjmcneill {
409f7483fa6Sjmcneill struct anxedp_softc * const sc = device_private(self);
410f7483fa6Sjmcneill struct i2c_attach_args * const ia = aux;
411f7483fa6Sjmcneill
412f7483fa6Sjmcneill sc->sc_dev = self;
413f7483fa6Sjmcneill sc->sc_i2c = ia->ia_tag;
414f7483fa6Sjmcneill sc->sc_addr = ia->ia_addr;
415f7483fa6Sjmcneill sc->sc_phandle = ia->ia_cookie;
416f7483fa6Sjmcneill
417f7483fa6Sjmcneill aprint_naive("\n");
418f7483fa6Sjmcneill aprint_normal(": eDP TX\n");
419f7483fa6Sjmcneill
420f7483fa6Sjmcneill sc->sc_ports.dp_ep_activate = anxedp_ep_activate;
421f7483fa6Sjmcneill sc->sc_ports.dp_ep_get_data = anxedp_ep_get_data;
422f7483fa6Sjmcneill fdt_ports_register(&sc->sc_ports, self, sc->sc_phandle, EP_DRM_BRIDGE);
423f7483fa6Sjmcneill }
424f7483fa6Sjmcneill
425f7483fa6Sjmcneill CFATTACH_DECL_NEW(anxedp, sizeof(struct anxedp_softc),
426f7483fa6Sjmcneill anxedp_match, anxedp_attach, NULL, NULL);
427