Home | History | Annotate | Line # | Download | only in rockchip
rk_dwhdmi.c revision 1.4.10.1
      1  1.4.10.1   thorpej /* $NetBSD: rk_dwhdmi.c,v 1.4.10.1 2021/04/03 22:28:18 thorpej Exp $ */
      2       1.1  jmcneill 
      3       1.1  jmcneill /*-
      4       1.1  jmcneill  * Copyright (c) 2019 Jared D. McNeill <jmcneill (at) invisible.ca>
      5       1.1  jmcneill  * All rights reserved.
      6       1.1  jmcneill  *
      7       1.1  jmcneill  * Redistribution and use in source and binary forms, with or without
      8       1.1  jmcneill  * modification, are permitted provided that the following conditions
      9       1.1  jmcneill  * are met:
     10       1.1  jmcneill  * 1. Redistributions of source code must retain the above copyright
     11       1.1  jmcneill  *    notice, this list of conditions and the following disclaimer.
     12       1.1  jmcneill  * 2. Redistributions in binary form must reproduce the above copyright
     13       1.1  jmcneill  *    notice, this list of conditions and the following disclaimer in the
     14       1.1  jmcneill  *    documentation and/or other materials provided with the distribution.
     15       1.1  jmcneill  *
     16       1.1  jmcneill  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     17       1.1  jmcneill  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     18       1.1  jmcneill  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     19       1.1  jmcneill  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     20       1.1  jmcneill  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
     21       1.1  jmcneill  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     22       1.1  jmcneill  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
     23       1.1  jmcneill  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     24       1.1  jmcneill  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     25       1.1  jmcneill  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     26       1.1  jmcneill  * SUCH DAMAGE.
     27       1.1  jmcneill  */
     28       1.1  jmcneill 
     29       1.1  jmcneill #include <sys/cdefs.h>
     30  1.4.10.1   thorpej __KERNEL_RCSID(0, "$NetBSD: rk_dwhdmi.c,v 1.4.10.1 2021/04/03 22:28:18 thorpej Exp $");
     31       1.1  jmcneill 
     32       1.1  jmcneill #include <sys/param.h>
     33       1.1  jmcneill #include <sys/bus.h>
     34       1.1  jmcneill #include <sys/device.h>
     35       1.1  jmcneill #include <sys/intr.h>
     36       1.1  jmcneill #include <sys/systm.h>
     37       1.1  jmcneill #include <sys/kernel.h>
     38       1.1  jmcneill #include <sys/conf.h>
     39       1.1  jmcneill 
     40       1.1  jmcneill #include <drm/drmP.h>
     41       1.4  jakllsch #include <drm/drm_crtc_helper.h>
     42       1.1  jmcneill 
     43       1.1  jmcneill #include <dev/fdt/fdtvar.h>
     44       1.1  jmcneill #include <dev/fdt/fdt_port.h>
     45       1.1  jmcneill #include <dev/fdt/syscon.h>
     46       1.1  jmcneill 
     47       1.1  jmcneill #include <dev/ic/dw_hdmi.h>
     48       1.1  jmcneill 
     49       1.1  jmcneill #define	RK3399_GRF_SOC_CON20		0x6250
     50       1.1  jmcneill #define	 HDMI_LCDC_SEL			__BIT(6)
     51       1.1  jmcneill 
     52       1.1  jmcneill static const struct dwhdmi_mpll_config rk_dwhdmi_mpll_config[] = {
     53       1.1  jmcneill 	{ 40000,	0x00b3, 0x0000, 0x0018 },
     54       1.1  jmcneill 	{ 65000,	0x0072, 0x0001, 0x0028 },
     55       1.1  jmcneill 	{ 66000,	0x013e, 0x0003, 0x0038 },
     56       1.1  jmcneill 	{ 83500,	0x0072, 0x0001, 0x0028 },
     57       1.1  jmcneill 	{ 146250,	0x0051, 0x0002, 0x0038 },
     58       1.1  jmcneill 	{ 148500,	0x0051, 0x0003, 0x0000 },
     59       1.1  jmcneill 	{ 272000,	0x0040, 0x0003, 0x0000 },
     60       1.1  jmcneill 	{ 340000,	0x0040, 0x0003, 0x0000 },
     61       1.1  jmcneill 	{ 0,		0x0051, 0x0003, 0x0000 },
     62       1.1  jmcneill };
     63       1.1  jmcneill 
     64       1.1  jmcneill static const struct dwhdmi_phy_config rk_dwhdmi_phy_config[] = {
     65       1.1  jmcneill 	{ 74250,	0x8009, 0x0004, 0x0272 },
     66       1.1  jmcneill 	{ 148500,	0x802b, 0x0004, 0x028d },
     67       1.1  jmcneill 	{ 297000,	0x8039, 0x0005, 0x028d },
     68       1.2  jmcneill 	{ 594000,	0x8039, 0x0000, 0x019d },
     69       1.1  jmcneill 	{ 0,		0x0000, 0x0000, 0x0000 }
     70       1.1  jmcneill };
     71       1.1  jmcneill 
     72       1.1  jmcneill enum {
     73       1.1  jmcneill 	DWHDMI_PORT_INPUT = 0,
     74       1.1  jmcneill 	DWHDMI_PORT_OUTPUT = 1,
     75       1.1  jmcneill };
     76       1.1  jmcneill 
     77  1.4.10.1   thorpej static const struct device_compatible_entry compat_data[] = {
     78  1.4.10.1   thorpej 	{ .compat = "rockchip,rk3399-dw-hdmi" },
     79  1.4.10.1   thorpej 	DEVICE_COMPAT_EOL
     80       1.1  jmcneill };
     81       1.1  jmcneill 
     82       1.1  jmcneill struct rk_dwhdmi_softc {
     83       1.1  jmcneill 	struct dwhdmi_softc	sc_base;
     84       1.1  jmcneill 	int			sc_phandle;
     85       1.1  jmcneill 	struct clk		*sc_clk_vpll;
     86       1.1  jmcneill 
     87       1.1  jmcneill 	struct fdt_device_ports	sc_ports;
     88       1.1  jmcneill 	struct drm_display_mode	sc_curmode;
     89       1.4  jakllsch 	struct drm_encoder	sc_encoder;
     90       1.1  jmcneill 	struct syscon		*sc_grf;
     91       1.1  jmcneill 
     92       1.1  jmcneill 	bool			sc_activated;
     93       1.1  jmcneill };
     94       1.1  jmcneill 
     95       1.1  jmcneill #define	to_rk_dwhdmi_softc(x)	container_of(x, struct rk_dwhdmi_softc, sc_base)
     96       1.4  jakllsch #define	to_rk_dwhdmi_encoder(x)	container_of(x, struct rk_dwhdmi_softc, sc_encoder)
     97       1.1  jmcneill 
     98       1.1  jmcneill static void
     99       1.1  jmcneill rk_dwhdmi_select_input(struct rk_dwhdmi_softc *sc, u_int crtc_index)
    100       1.1  jmcneill {
    101       1.1  jmcneill 	const uint32_t write_mask = HDMI_LCDC_SEL << 16;
    102       1.1  jmcneill 	const uint32_t write_val = crtc_index == 0 ? HDMI_LCDC_SEL : 0;
    103       1.1  jmcneill 
    104       1.1  jmcneill 	syscon_lock(sc->sc_grf);
    105       1.1  jmcneill 	syscon_write_4(sc->sc_grf, RK3399_GRF_SOC_CON20, write_mask | write_val);
    106       1.1  jmcneill 	syscon_unlock(sc->sc_grf);
    107       1.1  jmcneill }
    108       1.1  jmcneill 
    109       1.4  jakllsch static bool
    110       1.4  jakllsch rk_dwhdmi_encoder_mode_fixup(struct drm_encoder *encoder,
    111       1.4  jakllsch     const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode)
    112       1.4  jakllsch {
    113       1.4  jakllsch 	return true;
    114       1.4  jakllsch }
    115       1.4  jakllsch 
    116       1.4  jakllsch static void
    117       1.4  jakllsch rk_dwhdmi_encoder_mode_set(struct drm_encoder *encoder,
    118       1.4  jakllsch     struct drm_display_mode *mode, struct drm_display_mode *adjusted)
    119       1.4  jakllsch {
    120       1.4  jakllsch }
    121       1.4  jakllsch 
    122       1.4  jakllsch static void
    123       1.4  jakllsch rk_dwhdmi_encoder_enable(struct drm_encoder *encoder)
    124       1.4  jakllsch {
    125       1.4  jakllsch }
    126       1.4  jakllsch 
    127       1.4  jakllsch static void
    128       1.4  jakllsch rk_dwhdmi_encoder_disable(struct drm_encoder *encoder)
    129       1.4  jakllsch {
    130       1.4  jakllsch }
    131       1.4  jakllsch 
    132       1.4  jakllsch static void
    133       1.4  jakllsch rk_dwhdmi_encoder_prepare(struct drm_encoder *encoder)
    134       1.4  jakllsch {
    135       1.4  jakllsch 	struct rk_dwhdmi_softc * const sc = to_rk_dwhdmi_encoder(encoder);
    136       1.4  jakllsch 	const u_int crtc_index = drm_crtc_index(encoder->crtc);
    137       1.4  jakllsch 
    138       1.4  jakllsch 	rk_dwhdmi_select_input(sc, crtc_index);
    139       1.4  jakllsch }
    140       1.4  jakllsch 
    141       1.4  jakllsch static void
    142       1.4  jakllsch rk_dwhdmi_encoder_commit(struct drm_encoder *encoder)
    143       1.4  jakllsch {
    144       1.4  jakllsch }
    145       1.4  jakllsch 
    146       1.4  jakllsch static const struct drm_encoder_funcs rk_dwhdmi_encoder_funcs = {
    147       1.4  jakllsch 	.destroy = drm_encoder_cleanup,
    148       1.4  jakllsch };
    149       1.4  jakllsch 
    150       1.4  jakllsch static const struct drm_encoder_helper_funcs rk_dwhdmi_encoder_helper_funcs = {
    151       1.4  jakllsch 	.prepare = rk_dwhdmi_encoder_prepare,
    152       1.4  jakllsch 	.mode_fixup = rk_dwhdmi_encoder_mode_fixup,
    153       1.4  jakllsch 	.mode_set = rk_dwhdmi_encoder_mode_set,
    154       1.4  jakllsch 	.enable = rk_dwhdmi_encoder_enable,
    155       1.4  jakllsch 	.disable = rk_dwhdmi_encoder_disable,
    156       1.4  jakllsch 	.commit = rk_dwhdmi_encoder_commit,
    157       1.4  jakllsch };
    158       1.4  jakllsch 
    159       1.1  jmcneill static int
    160       1.1  jmcneill rk_dwhdmi_ep_activate(device_t dev, struct fdt_endpoint *ep, bool activate)
    161       1.1  jmcneill {
    162       1.1  jmcneill 	struct rk_dwhdmi_softc * const sc = device_private(dev);
    163       1.1  jmcneill 	struct fdt_endpoint *in_ep = fdt_endpoint_remote(ep);
    164       1.1  jmcneill 	struct fdt_endpoint *out_ep, *out_rep;
    165       1.4  jakllsch 	struct drm_crtc *crtc;
    166       1.1  jmcneill 	int error;
    167       1.1  jmcneill 
    168       1.4  jakllsch 	if (sc->sc_activated != false) {
    169       1.4  jakllsch 		return 0;
    170       1.4  jakllsch 	}
    171       1.4  jakllsch 
    172       1.1  jmcneill 	if (!activate)
    173       1.1  jmcneill 		return EINVAL;
    174       1.1  jmcneill 
    175       1.1  jmcneill 	if (fdt_endpoint_port_index(ep) != DWHDMI_PORT_INPUT)
    176       1.1  jmcneill 		return EINVAL;
    177       1.1  jmcneill 
    178       1.1  jmcneill 	switch (fdt_endpoint_type(in_ep)) {
    179       1.4  jakllsch 	case EP_DRM_CRTC:
    180       1.4  jakllsch 		crtc = fdt_endpoint_get_data(in_ep);
    181       1.1  jmcneill 		break;
    182       1.1  jmcneill 	default:
    183       1.4  jakllsch 		crtc = NULL;
    184       1.1  jmcneill 		break;
    185       1.1  jmcneill 	}
    186       1.1  jmcneill 
    187       1.4  jakllsch 	if (crtc == NULL)
    188       1.1  jmcneill 		return EINVAL;
    189       1.1  jmcneill 
    190       1.4  jakllsch 	sc->sc_encoder.possible_crtcs = 3; // 1U << drm_crtc_index(crtc); /* XXX */
    191       1.4  jakllsch 	drm_encoder_init(crtc->dev, &sc->sc_encoder, &rk_dwhdmi_encoder_funcs,
    192       1.4  jakllsch 	    DRM_MODE_ENCODER_TMDS);
    193       1.4  jakllsch 	drm_encoder_helper_add(&sc->sc_encoder, &rk_dwhdmi_encoder_helper_funcs);
    194       1.4  jakllsch 
    195       1.4  jakllsch 	sc->sc_base.sc_connector.base.connector_type = DRM_MODE_CONNECTOR_HDMIA;
    196       1.4  jakllsch 	error = dwhdmi_bind(&sc->sc_base, &sc->sc_encoder);
    197       1.4  jakllsch 	if (error != 0)
    198       1.4  jakllsch 		return error;
    199       1.4  jakllsch 	sc->sc_activated = true;
    200       1.1  jmcneill 
    201       1.1  jmcneill 	out_ep = fdt_endpoint_get_from_index(&sc->sc_ports, DWHDMI_PORT_OUTPUT, 0);
    202       1.1  jmcneill 	if (out_ep != NULL) {
    203       1.1  jmcneill 		/* Ignore downstream connectors, we have our own. */
    204       1.1  jmcneill 		out_rep = fdt_endpoint_remote(out_ep);
    205       1.1  jmcneill 		if (out_rep != NULL && fdt_endpoint_type(out_rep) == EP_DRM_CONNECTOR)
    206       1.1  jmcneill 			return 0;
    207       1.1  jmcneill 
    208       1.1  jmcneill 		error = fdt_endpoint_activate(out_ep, activate);
    209       1.1  jmcneill 		if (error != 0)
    210       1.1  jmcneill 			return error;
    211       1.1  jmcneill 	}
    212       1.1  jmcneill 
    213       1.1  jmcneill 	return 0;
    214       1.1  jmcneill }
    215       1.1  jmcneill 
    216       1.1  jmcneill static void *
    217       1.1  jmcneill rk_dwhdmi_ep_get_data(device_t dev, struct fdt_endpoint *ep)
    218       1.1  jmcneill {
    219       1.1  jmcneill 	struct rk_dwhdmi_softc * const sc = device_private(dev);
    220       1.1  jmcneill 
    221       1.4  jakllsch 	return &sc->sc_encoder;
    222       1.1  jmcneill }
    223       1.1  jmcneill 
    224       1.1  jmcneill static void
    225       1.1  jmcneill rk_dwhdmi_enable(struct dwhdmi_softc *dsc)
    226       1.1  jmcneill {
    227       1.1  jmcneill 
    228       1.1  jmcneill 	dwhdmi_phy_enable(dsc);
    229       1.1  jmcneill }
    230       1.1  jmcneill 
    231       1.1  jmcneill static void
    232       1.1  jmcneill rk_dwhdmi_mode_set(struct dwhdmi_softc *dsc,
    233       1.1  jmcneill     struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode)
    234       1.1  jmcneill {
    235       1.1  jmcneill 	struct rk_dwhdmi_softc * const sc = to_rk_dwhdmi_softc(dsc);
    236       1.1  jmcneill 	int error;
    237       1.1  jmcneill 
    238       1.1  jmcneill 	if (sc->sc_clk_vpll != NULL) {
    239       1.1  jmcneill 		error = clk_set_rate(sc->sc_clk_vpll, adjusted_mode->clock * 1000);
    240       1.1  jmcneill 		if (error != 0)
    241       1.1  jmcneill 			device_printf(dsc->sc_dev, "couldn't set pixel clock to %u Hz: %d\n",
    242       1.1  jmcneill 			    adjusted_mode->clock * 1000, error);
    243       1.1  jmcneill 	}
    244       1.1  jmcneill 
    245       1.1  jmcneill 	dwhdmi_phy_mode_set(dsc, mode, adjusted_mode);
    246       1.1  jmcneill }
    247       1.1  jmcneill 
    248       1.3  jmcneill static audio_dai_tag_t
    249       1.3  jmcneill rk_dwhdmi_dai_get_tag(device_t dev, const void *data, size_t len)
    250       1.3  jmcneill {
    251       1.3  jmcneill 	struct rk_dwhdmi_softc * const sc = device_private(dev);
    252       1.3  jmcneill 
    253       1.3  jmcneill 	if (len != 4)
    254       1.3  jmcneill 		return NULL;
    255       1.3  jmcneill 
    256       1.3  jmcneill 	return &sc->sc_base.sc_dai;
    257       1.3  jmcneill }
    258       1.3  jmcneill 
    259       1.3  jmcneill static struct fdtbus_dai_controller_func rk_dwhdmi_dai_funcs = {
    260       1.3  jmcneill 	.get_tag = rk_dwhdmi_dai_get_tag
    261       1.3  jmcneill };
    262       1.3  jmcneill 
    263       1.1  jmcneill static int
    264       1.1  jmcneill rk_dwhdmi_match(device_t parent, cfdata_t cf, void *aux)
    265       1.1  jmcneill {
    266       1.1  jmcneill 	struct fdt_attach_args * const faa = aux;
    267       1.1  jmcneill 
    268  1.4.10.1   thorpej 	return of_compatible_match(faa->faa_phandle, compat_data);
    269       1.1  jmcneill }
    270       1.1  jmcneill 
    271       1.1  jmcneill static void
    272       1.1  jmcneill rk_dwhdmi_attach(device_t parent, device_t self, void *aux)
    273       1.1  jmcneill {
    274       1.1  jmcneill 	struct rk_dwhdmi_softc * const sc = device_private(self);
    275       1.1  jmcneill 	struct fdt_attach_args * const faa = aux;
    276       1.1  jmcneill 	const int phandle = faa->faa_phandle;
    277       1.1  jmcneill 	bus_addr_t addr;
    278       1.1  jmcneill 	bus_size_t size;
    279       1.1  jmcneill 
    280       1.1  jmcneill 	if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) {
    281       1.1  jmcneill 		aprint_error(": couldn't get registers\n");
    282       1.1  jmcneill 		return;
    283       1.1  jmcneill 	}
    284       1.1  jmcneill 
    285       1.1  jmcneill 	/* Required */
    286       1.1  jmcneill 	if (fdtbus_clock_enable(phandle, "iahb", true) != 0) {
    287       1.1  jmcneill 		aprint_error(": couldn't enable iahb clock\n");
    288       1.1  jmcneill 		return;
    289       1.1  jmcneill 	}
    290       1.1  jmcneill 
    291       1.1  jmcneill 	/* Required */
    292       1.1  jmcneill 	if (fdtbus_clock_enable(phandle, "isfr", true) != 0) {
    293       1.1  jmcneill 		aprint_error(": couldn't enable isfr clock\n");
    294       1.1  jmcneill 		return;
    295       1.1  jmcneill 	}
    296       1.1  jmcneill 
    297       1.1  jmcneill 	/* Optional */
    298       1.1  jmcneill 	sc->sc_clk_vpll = fdtbus_clock_get(phandle, "vpll");
    299       1.1  jmcneill 	if (sc->sc_clk_vpll != NULL && clk_enable(sc->sc_clk_vpll) != 0) {
    300       1.1  jmcneill 		aprint_error(": couldn't enable vpll clock\n");
    301       1.1  jmcneill 		return;
    302       1.1  jmcneill 	}
    303       1.1  jmcneill 
    304       1.1  jmcneill 	/* Optional */
    305       1.1  jmcneill 	if (fdtbus_clock_enable(phandle, "grf", false) != 0) {
    306       1.1  jmcneill 		aprint_error(": couldn't enable grf clock\n");
    307       1.1  jmcneill 		return;
    308       1.1  jmcneill 	}
    309       1.1  jmcneill 
    310       1.1  jmcneill 	/* Optional */
    311       1.1  jmcneill 	if (fdtbus_clock_enable(phandle, "cec", false) != 0) {
    312       1.1  jmcneill 		aprint_error(": couldn't enable cec clock\n");
    313       1.1  jmcneill 		return;
    314       1.1  jmcneill 	}
    315       1.1  jmcneill 
    316       1.1  jmcneill 	sc->sc_base.sc_dev = self;
    317       1.1  jmcneill 	if (of_getprop_uint32(phandle, "reg-io-width", &sc->sc_base.sc_reg_width) != 0)
    318       1.1  jmcneill 		sc->sc_base.sc_reg_width = 4;
    319       1.1  jmcneill 	sc->sc_base.sc_bst = faa->faa_bst;
    320       1.1  jmcneill 	if (bus_space_map(sc->sc_base.sc_bst, addr, size, 0, &sc->sc_base.sc_bsh) != 0) {
    321       1.1  jmcneill 		aprint_error(": couldn't map registers\n");
    322       1.1  jmcneill 		return;
    323       1.1  jmcneill 	}
    324       1.1  jmcneill 	sc->sc_phandle = faa->faa_phandle;
    325       1.1  jmcneill 	sc->sc_grf = fdtbus_syscon_acquire(phandle, "rockchip,grf");
    326       1.1  jmcneill 	if (sc->sc_grf == NULL) {
    327       1.1  jmcneill 		aprint_error(": couldn't get grf syscon\n");
    328       1.1  jmcneill 		return;
    329       1.1  jmcneill 	}
    330       1.1  jmcneill 
    331       1.1  jmcneill 	aprint_naive("\n");
    332       1.1  jmcneill 	aprint_normal(": HDMI TX\n");
    333       1.1  jmcneill 
    334       1.1  jmcneill 	sc->sc_base.sc_ic = fdtbus_i2c_acquire(phandle, "ddc-i2c-bus");
    335       1.1  jmcneill 	if (of_hasprop(phandle, "ddc-i2c-bus") && sc->sc_base.sc_ic == NULL) {
    336       1.1  jmcneill 		aprint_error_dev(self, "couldn't find external I2C master\n");
    337       1.1  jmcneill 		return;
    338       1.1  jmcneill 	}
    339       1.1  jmcneill 
    340       1.1  jmcneill 	sc->sc_base.sc_flags |= DWHDMI_USE_INTERNAL_PHY;
    341       1.1  jmcneill 	sc->sc_base.sc_detect = dwhdmi_phy_detect;
    342       1.1  jmcneill 	sc->sc_base.sc_enable = rk_dwhdmi_enable;
    343       1.1  jmcneill 	sc->sc_base.sc_disable = dwhdmi_phy_disable;
    344       1.1  jmcneill 	sc->sc_base.sc_mode_set = rk_dwhdmi_mode_set;
    345       1.1  jmcneill 	sc->sc_base.sc_mpll_config = rk_dwhdmi_mpll_config;
    346       1.1  jmcneill 	sc->sc_base.sc_phy_config = rk_dwhdmi_phy_config;
    347       1.1  jmcneill 
    348       1.1  jmcneill 	if (dwhdmi_attach(&sc->sc_base) != 0) {
    349       1.1  jmcneill 		aprint_error_dev(self, "failed to attach driver\n");
    350       1.1  jmcneill 		return;
    351       1.1  jmcneill 	}
    352       1.1  jmcneill 
    353       1.1  jmcneill 	sc->sc_ports.dp_ep_activate = rk_dwhdmi_ep_activate;
    354       1.1  jmcneill 	sc->sc_ports.dp_ep_get_data = rk_dwhdmi_ep_get_data;
    355       1.4  jakllsch 	fdt_ports_register(&sc->sc_ports, self, phandle, EP_DRM_ENCODER);
    356       1.3  jmcneill 
    357       1.3  jmcneill 	fdtbus_register_dai_controller(self, phandle, &rk_dwhdmi_dai_funcs);
    358       1.1  jmcneill }
    359       1.1  jmcneill 
    360       1.1  jmcneill CFATTACH_DECL_NEW(rk_dwhdmi, sizeof(struct rk_dwhdmi_softc),
    361       1.1  jmcneill 	rk_dwhdmi_match, rk_dwhdmi_attach, NULL, NULL);
    362