Home | History | Annotate | Line # | Download | only in rockchip
rk_vop.c revision 1.5
      1  1.5  jakllsch /* $NetBSD: rk_vop.c,v 1.5 2019/12/17 18:30:51 jakllsch 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.5  jakllsch __KERNEL_RCSID(0, "$NetBSD: rk_vop.c,v 1.5 2019/12/17 18:30:51 jakllsch 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 #include <sys/sysctl.h>
     40  1.1  jmcneill 
     41  1.1  jmcneill #include <drm/drmP.h>
     42  1.1  jmcneill #include <drm/drm_crtc.h>
     43  1.1  jmcneill #include <drm/drm_crtc_helper.h>
     44  1.1  jmcneill #include <drm/drm_plane_helper.h>
     45  1.1  jmcneill 
     46  1.1  jmcneill #include <dev/fdt/fdtvar.h>
     47  1.1  jmcneill #include <dev/fdt/fdt_port.h>
     48  1.1  jmcneill 
     49  1.1  jmcneill #include <arm/rockchip/rk_drm.h>
     50  1.1  jmcneill 
     51  1.1  jmcneill #define	VOP_REG_CFG_DONE		0x0000
     52  1.1  jmcneill #define	 REG_LOAD_EN			__BIT(0)
     53  1.1  jmcneill #define	VOP_SYS_CTRL			0x0008
     54  1.1  jmcneill #define	 VOP_STANDBY_EN			__BIT(22)
     55  1.1  jmcneill #define	 MIPI_OUT_EN			__BIT(15)
     56  1.1  jmcneill #define	 EDP_OUT_EN			__BIT(14)
     57  1.1  jmcneill #define	 HDMI_OUT_EN			__BIT(13)
     58  1.1  jmcneill #define	 RGB_OUT_EN			__BIT(12)
     59  1.1  jmcneill #define	VOP_DSP_CTRL0			0x0010
     60  1.1  jmcneill #define	 DSP_OUT_MODE			__BITS(3,0)
     61  1.1  jmcneill #define	  DSP_OUT_MODE_RGB888		0
     62  1.1  jmcneill #define	  DSP_OUT_MODE_RGBaaa		15
     63  1.1  jmcneill #define	VOP_DSP_CTRL1			0x0014
     64  1.1  jmcneill #define	VOP_WIN0_CTRL			0x0030
     65  1.1  jmcneill #define	 WIN0_LB_MODE			__BITS(7,5)
     66  1.1  jmcneill #define	  WIN0_LB_MODE_RGB_3840X2	2
     67  1.1  jmcneill #define	  WIN0_LB_MODE_RGB_2560X4	3
     68  1.1  jmcneill #define	  WIN0_LB_MODE_RGB_1920X5	4
     69  1.1  jmcneill #define	  WIN0_LB_MODE_RGB_1280X8	5
     70  1.1  jmcneill #define	 WIN0_DATA_FMT			__BITS(3,1)
     71  1.1  jmcneill #define	  WIN0_DATA_FMT_ARGB888		0
     72  1.1  jmcneill #define	 WIN0_EN			__BIT(0)
     73  1.1  jmcneill #define	VOP_WIN0_COLOR_KEY		0x0038
     74  1.1  jmcneill #define	VOP_WIN0_VIR			0x003c
     75  1.1  jmcneill #define	 WIN0_VIR_STRIDE		__BITS(13,0)
     76  1.1  jmcneill #define	VOP_WIN0_YRGB_MST		0x0040
     77  1.1  jmcneill #define	VOP_WIN0_ACT_INFO		0x0048
     78  1.1  jmcneill #define	 WIN0_ACT_HEIGHT		__BITS(28,16)
     79  1.1  jmcneill #define	 WIN0_ACT_WIDTH			__BITS(12,0)
     80  1.1  jmcneill #define	VOP_WIN0_DSP_INFO		0x004c
     81  1.1  jmcneill #define	 WIN0_DSP_HEIGHT		__BITS(27,16)
     82  1.1  jmcneill #define	 WIN0_DSP_WIDTH			__BITS(11,0)
     83  1.1  jmcneill #define	VOP_WIN0_DSP_ST			0x0050
     84  1.1  jmcneill #define	 WIN0_DSP_YST			__BITS(28,16)
     85  1.1  jmcneill #define	 WIN0_DSP_XST			__BITS(12,0)
     86  1.1  jmcneill #define	VOP_POST_DSP_HACT_INFO		0x0170
     87  1.1  jmcneill #define	 DSP_HACT_ST_POST		__BITS(28,16)
     88  1.1  jmcneill #define	 DSP_HACT_END_POST		__BITS(12,0)
     89  1.1  jmcneill #define	VOP_POST_DSP_VACT_INFO		0x0174
     90  1.1  jmcneill #define	 DSP_VACT_ST_POST		__BITS(28,16)
     91  1.1  jmcneill #define	 DSP_VACT_END_POST		__BITS(12,0)
     92  1.1  jmcneill #define	VOP_DSP_HTOTAL_HS_END		0x0188
     93  1.2  jmcneill #define	 DSP_HS_END			__BITS(28,16)
     94  1.2  jmcneill #define	 DSP_HTOTAL			__BITS(12,0)
     95  1.1  jmcneill #define	VOP_DSP_HACT_ST_END		0x018c
     96  1.1  jmcneill #define	 DSP_HACT_ST			__BITS(28,16)
     97  1.1  jmcneill #define	 DSP_HACT_END			__BITS(12,0)
     98  1.1  jmcneill #define	VOP_DSP_VTOTAL_VS_END		0x0190
     99  1.2  jmcneill #define	 DSP_VS_END			__BITS(28,16)
    100  1.2  jmcneill #define	 DSP_VTOTAL			__BITS(12,0)
    101  1.1  jmcneill #define	VOP_DSP_VACT_ST_END		0x0194
    102  1.1  jmcneill #define	 DSP_VACT_ST			__BITS(28,16)
    103  1.1  jmcneill #define	 DSP_VACT_END			__BITS(12,0)
    104  1.1  jmcneill 
    105  1.1  jmcneill /*
    106  1.1  jmcneill  * Polarity fields are in different locations depending on SoC and output type,
    107  1.1  jmcneill  * but always in the same order.
    108  1.1  jmcneill  */
    109  1.1  jmcneill #define	DSP_DCLK_POL			__BIT(3)
    110  1.1  jmcneill #define	DSP_DEN_POL			__BIT(2)
    111  1.1  jmcneill #define	DSP_VSYNC_POL			__BIT(1)
    112  1.1  jmcneill #define	DSP_HSYNC_POL			__BIT(0)
    113  1.1  jmcneill 
    114  1.1  jmcneill enum vop_ep_type {
    115  1.1  jmcneill 	VOP_EP_MIPI,
    116  1.1  jmcneill 	VOP_EP_EDP,
    117  1.1  jmcneill 	VOP_EP_HDMI,
    118  1.1  jmcneill 	VOP_EP_MIPI1,
    119  1.1  jmcneill 	VOP_EP_DP,
    120  1.1  jmcneill 	VOP_NEP
    121  1.1  jmcneill };
    122  1.1  jmcneill 
    123  1.1  jmcneill struct rk_vop_softc;
    124  1.1  jmcneill struct rk_vop_config;
    125  1.1  jmcneill 
    126  1.1  jmcneill struct rk_vop_crtc {
    127  1.1  jmcneill 	struct drm_crtc		base;
    128  1.1  jmcneill 	struct rk_vop_softc	*sc;
    129  1.1  jmcneill };
    130  1.1  jmcneill 
    131  1.1  jmcneill struct rk_vop_softc {
    132  1.1  jmcneill 	device_t		sc_dev;
    133  1.1  jmcneill 	bus_space_tag_t		sc_bst;
    134  1.1  jmcneill 	bus_space_handle_t	sc_bsh;
    135  1.1  jmcneill 	int			sc_phandle;
    136  1.1  jmcneill 
    137  1.1  jmcneill 	struct clk		*sc_dclk;
    138  1.1  jmcneill 
    139  1.1  jmcneill 	struct rk_vop_crtc	sc_crtc;
    140  1.1  jmcneill 
    141  1.1  jmcneill 	struct fdt_device_ports	sc_ports;
    142  1.1  jmcneill 
    143  1.1  jmcneill 	struct rk_vop_config	*sc_conf;
    144  1.1  jmcneill };
    145  1.1  jmcneill 
    146  1.1  jmcneill #define	to_rk_vop_crtc(x)	container_of(x, struct rk_vop_crtc, base)
    147  1.1  jmcneill 
    148  1.1  jmcneill #define	RD4(sc, reg)				\
    149  1.1  jmcneill 	bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg))
    150  1.1  jmcneill #define	WR4(sc, reg, val)			\
    151  1.1  jmcneill 	bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val))
    152  1.1  jmcneill 
    153  1.1  jmcneill struct rk_vop_config {
    154  1.1  jmcneill 	const char		*descr;
    155  1.1  jmcneill 	u_int			out_mode;
    156  1.1  jmcneill 	void			(*init)(struct rk_vop_softc *);
    157  1.1  jmcneill 	void			(*set_polarity)(struct rk_vop_softc *,
    158  1.1  jmcneill 						enum vop_ep_type, uint32_t);
    159  1.1  jmcneill };
    160  1.1  jmcneill 
    161  1.1  jmcneill #define	RK3399_VOP_MIPI_POL	__BITS(31,28)
    162  1.1  jmcneill #define	RK3399_VOP_EDP_POL	__BITS(27,24)
    163  1.1  jmcneill #define	RK3399_VOP_HDMI_POL	__BITS(23,20)
    164  1.1  jmcneill #define	RK3399_VOP_DP_POL	__BITS(19,16)
    165  1.1  jmcneill 
    166  1.1  jmcneill #define	RK3399_VOP_SYS_CTRL_ENABLE	__BIT(11)
    167  1.1  jmcneill 
    168  1.1  jmcneill static void
    169  1.1  jmcneill rk3399_vop_set_polarity(struct rk_vop_softc *sc, enum vop_ep_type ep_type, uint32_t pol)
    170  1.1  jmcneill {
    171  1.1  jmcneill 	uint32_t mask, val;
    172  1.1  jmcneill 
    173  1.1  jmcneill 	switch (ep_type) {
    174  1.1  jmcneill 	case VOP_EP_MIPI:
    175  1.1  jmcneill 	case VOP_EP_MIPI1:
    176  1.1  jmcneill 		mask = RK3399_VOP_MIPI_POL;
    177  1.1  jmcneill 		break;
    178  1.1  jmcneill 	case VOP_EP_EDP:
    179  1.1  jmcneill 		mask = RK3399_VOP_EDP_POL;
    180  1.1  jmcneill 		break;
    181  1.1  jmcneill 	case VOP_EP_HDMI:
    182  1.1  jmcneill 		mask = RK3399_VOP_HDMI_POL;
    183  1.1  jmcneill 		break;
    184  1.1  jmcneill 	case VOP_EP_DP:
    185  1.1  jmcneill 		mask = RK3399_VOP_DP_POL;
    186  1.1  jmcneill 		break;
    187  1.1  jmcneill 	default:
    188  1.1  jmcneill 		return;
    189  1.1  jmcneill 	}
    190  1.1  jmcneill 
    191  1.1  jmcneill 	val = RD4(sc, VOP_DSP_CTRL1);
    192  1.1  jmcneill 	val &= ~mask;
    193  1.1  jmcneill 	val |= __SHIFTIN(pol, mask);
    194  1.1  jmcneill 	WR4(sc, VOP_DSP_CTRL1, val);
    195  1.1  jmcneill }
    196  1.1  jmcneill 
    197  1.1  jmcneill static void
    198  1.1  jmcneill rk3399_vop_init(struct rk_vop_softc *sc)
    199  1.1  jmcneill {
    200  1.1  jmcneill 	uint32_t val;
    201  1.1  jmcneill 
    202  1.1  jmcneill 	val = RD4(sc, VOP_SYS_CTRL);
    203  1.1  jmcneill 	val |= RK3399_VOP_SYS_CTRL_ENABLE;
    204  1.1  jmcneill 	WR4(sc, VOP_SYS_CTRL, val);
    205  1.1  jmcneill }
    206  1.1  jmcneill 
    207  1.1  jmcneill static const struct rk_vop_config rk3399_vop_lit_config = {
    208  1.1  jmcneill 	.descr = "RK3399 VOPL",
    209  1.1  jmcneill 	.out_mode = DSP_OUT_MODE_RGB888,
    210  1.1  jmcneill 	.init = rk3399_vop_init,
    211  1.1  jmcneill 	.set_polarity = rk3399_vop_set_polarity,
    212  1.1  jmcneill };
    213  1.1  jmcneill 
    214  1.1  jmcneill static const struct rk_vop_config rk3399_vop_big_config = {
    215  1.1  jmcneill 	.descr = "RK3399 VOPB",
    216  1.1  jmcneill 	.out_mode = DSP_OUT_MODE_RGBaaa,
    217  1.1  jmcneill 	.init = rk3399_vop_init,
    218  1.1  jmcneill 	.set_polarity = rk3399_vop_set_polarity,
    219  1.1  jmcneill };
    220  1.1  jmcneill 
    221  1.1  jmcneill static const struct of_compat_data compat_data[] = {
    222  1.1  jmcneill 	{ "rockchip,rk3399-vop-big",		(uintptr_t)&rk3399_vop_big_config },
    223  1.1  jmcneill 	{ "rockchip,rk3399-vop-lit",		(uintptr_t)&rk3399_vop_lit_config },
    224  1.1  jmcneill 	{ NULL }
    225  1.1  jmcneill };
    226  1.1  jmcneill 
    227  1.1  jmcneill static int
    228  1.1  jmcneill rk_vop_mode_do_set_base(struct drm_crtc *crtc, struct drm_framebuffer *fb,
    229  1.1  jmcneill     int x, int y, int atomic)
    230  1.1  jmcneill {
    231  1.1  jmcneill 	struct rk_vop_crtc *mixer_crtc = to_rk_vop_crtc(crtc);
    232  1.1  jmcneill 	struct rk_vop_softc * const sc = mixer_crtc->sc;
    233  1.1  jmcneill 	struct rk_drm_framebuffer *sfb = atomic?
    234  1.1  jmcneill 	    to_rk_drm_framebuffer(fb) :
    235  1.1  jmcneill 	    to_rk_drm_framebuffer(crtc->primary->fb);
    236  1.1  jmcneill 
    237  1.1  jmcneill 	uint64_t paddr = (uint64_t)sfb->obj->dmamap->dm_segs[0].ds_addr;
    238  1.1  jmcneill 
    239  1.5  jakllsch 	paddr += y * sfb->base.pitches[0];
    240  1.5  jakllsch 	paddr += x * drm_format_plane_cpp(sfb->base.pixel_format, 0);
    241  1.5  jakllsch 
    242  1.1  jmcneill 	KASSERT((paddr & ~0xffffffff) == 0);
    243  1.1  jmcneill 
    244  1.5  jakllsch 	const uint32_t vir = __SHIFTIN(sfb->base.pitches[0] / 4,
    245  1.5  jakllsch 	    WIN0_VIR_STRIDE);
    246  1.5  jakllsch 	WR4(sc, VOP_WIN0_VIR, vir);
    247  1.5  jakllsch 
    248  1.1  jmcneill 	/* Framebuffer start address */
    249  1.1  jmcneill 	WR4(sc, VOP_WIN0_YRGB_MST, (uint32_t)paddr);
    250  1.1  jmcneill 
    251  1.1  jmcneill 	return 0;
    252  1.1  jmcneill }
    253  1.1  jmcneill 
    254  1.1  jmcneill static void
    255  1.1  jmcneill rk_vop_destroy(struct drm_crtc *crtc)
    256  1.1  jmcneill {
    257  1.1  jmcneill 	drm_crtc_cleanup(crtc);
    258  1.1  jmcneill }
    259  1.1  jmcneill 
    260  1.1  jmcneill static const struct drm_crtc_funcs rk_vop_crtc_funcs = {
    261  1.1  jmcneill 	.set_config = drm_crtc_helper_set_config,
    262  1.1  jmcneill 	.destroy = rk_vop_destroy,
    263  1.1  jmcneill };
    264  1.1  jmcneill 
    265  1.1  jmcneill static void
    266  1.1  jmcneill rk_vop_dpms(struct drm_crtc *crtc, int mode)
    267  1.1  jmcneill {
    268  1.1  jmcneill }
    269  1.1  jmcneill 
    270  1.1  jmcneill static bool
    271  1.1  jmcneill rk_vop_mode_fixup(struct drm_crtc *crtc,
    272  1.1  jmcneill     const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode)
    273  1.1  jmcneill {
    274  1.1  jmcneill 	return true;
    275  1.1  jmcneill }
    276  1.1  jmcneill 
    277  1.1  jmcneill static int
    278  1.1  jmcneill rk_vop_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode,
    279  1.1  jmcneill     struct drm_display_mode *adjusted_mode, int x, int y,
    280  1.1  jmcneill     struct drm_framebuffer *old_fb)
    281  1.1  jmcneill {
    282  1.1  jmcneill 	struct rk_vop_crtc *mixer_crtc = to_rk_vop_crtc(crtc);
    283  1.1  jmcneill 	struct rk_vop_softc * const sc = mixer_crtc->sc;
    284  1.1  jmcneill 	uint32_t val;
    285  1.1  jmcneill 	u_int lb_mode;
    286  1.1  jmcneill 	int error;
    287  1.4  jakllsch 	u_int pol;
    288  1.4  jakllsch 	int connector_type = 0;
    289  1.4  jakllsch 	struct drm_connector * connector;
    290  1.1  jmcneill 
    291  1.1  jmcneill 	const u_int hactive = adjusted_mode->hdisplay;
    292  1.1  jmcneill 	const u_int hsync_len = adjusted_mode->hsync_end - adjusted_mode->hsync_start;
    293  1.1  jmcneill 	const u_int hback_porch = adjusted_mode->htotal - adjusted_mode->hsync_end;
    294  1.4  jakllsch 	const u_int hfront_porch = adjusted_mode->hsync_start - adjusted_mode->hdisplay;
    295  1.1  jmcneill 
    296  1.1  jmcneill 	const u_int vactive = adjusted_mode->vdisplay;
    297  1.1  jmcneill 	const u_int vsync_len = adjusted_mode->vsync_end - adjusted_mode->vsync_start;
    298  1.1  jmcneill 	const u_int vback_porch = adjusted_mode->vtotal - adjusted_mode->vsync_end;
    299  1.4  jakllsch 	const u_int vfront_porch = adjusted_mode->vsync_start - adjusted_mode->vdisplay;
    300  1.1  jmcneill 
    301  1.1  jmcneill 	error = clk_set_rate(sc->sc_dclk, adjusted_mode->clock * 1000);
    302  1.1  jmcneill 	if (error != 0)
    303  1.1  jmcneill 		DRM_ERROR("couldn't set pixel clock: %d\n", error);
    304  1.1  jmcneill 
    305  1.1  jmcneill 	val = __SHIFTIN(hactive - 1, WIN0_ACT_WIDTH) |
    306  1.1  jmcneill 	      __SHIFTIN(vactive - 1, WIN0_ACT_HEIGHT);
    307  1.1  jmcneill 	WR4(sc, VOP_WIN0_ACT_INFO, val);
    308  1.1  jmcneill 
    309  1.1  jmcneill 	val = __SHIFTIN(hactive - 1, WIN0_DSP_WIDTH) |
    310  1.1  jmcneill 	      __SHIFTIN(vactive - 1, WIN0_DSP_HEIGHT);
    311  1.1  jmcneill 	WR4(sc, VOP_WIN0_DSP_INFO, val);
    312  1.1  jmcneill 
    313  1.2  jmcneill 	val = __SHIFTIN(hsync_len + hback_porch, WIN0_DSP_XST) |
    314  1.2  jmcneill 	      __SHIFTIN(vsync_len + vback_porch, WIN0_DSP_YST);
    315  1.1  jmcneill 	WR4(sc, VOP_WIN0_DSP_ST, val);
    316  1.1  jmcneill 
    317  1.1  jmcneill 	WR4(sc, VOP_WIN0_COLOR_KEY, 0);
    318  1.1  jmcneill 
    319  1.1  jmcneill 	if (adjusted_mode->hdisplay > 2560)
    320  1.1  jmcneill 		lb_mode = WIN0_LB_MODE_RGB_3840X2;
    321  1.1  jmcneill 	else if (adjusted_mode->hdisplay > 1920)
    322  1.1  jmcneill 		lb_mode = WIN0_LB_MODE_RGB_2560X4;
    323  1.1  jmcneill 	else if (adjusted_mode->hdisplay > 1280)
    324  1.1  jmcneill 		lb_mode = WIN0_LB_MODE_RGB_1920X5;
    325  1.1  jmcneill 	else
    326  1.1  jmcneill 		lb_mode = WIN0_LB_MODE_RGB_1280X8;
    327  1.1  jmcneill 
    328  1.1  jmcneill 	val = __SHIFTIN(lb_mode, WIN0_LB_MODE) |
    329  1.1  jmcneill 	      __SHIFTIN(WIN0_DATA_FMT_ARGB888, WIN0_DATA_FMT) |
    330  1.1  jmcneill 	      WIN0_EN;
    331  1.1  jmcneill 	WR4(sc, VOP_WIN0_CTRL, val);
    332  1.1  jmcneill 
    333  1.1  jmcneill 	rk_vop_mode_do_set_base(crtc, old_fb, x, y, 0);
    334  1.1  jmcneill 
    335  1.4  jakllsch 	pol = DSP_DCLK_POL;
    336  1.4  jakllsch 	if ((adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) != 0)
    337  1.4  jakllsch 		pol |= DSP_HSYNC_POL;
    338  1.4  jakllsch 	if ((adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) != 0)
    339  1.4  jakllsch 		pol |= DSP_VSYNC_POL;
    340  1.4  jakllsch 
    341  1.4  jakllsch 	drm_for_each_connector(connector, crtc->dev) {
    342  1.4  jakllsch 		if ((connector->encoder) == NULL)
    343  1.4  jakllsch 			continue;
    344  1.4  jakllsch 		if (connector->encoder->crtc == crtc) {
    345  1.4  jakllsch 			connector_type = connector->connector_type;
    346  1.4  jakllsch 			break;
    347  1.4  jakllsch 		}
    348  1.4  jakllsch 	}
    349  1.4  jakllsch 
    350  1.4  jakllsch 	switch (connector_type) {
    351  1.4  jakllsch 	case DRM_MODE_CONNECTOR_HDMIA:
    352  1.4  jakllsch 		sc->sc_conf->set_polarity(sc, VOP_EP_HDMI, pol);
    353  1.4  jakllsch 		break;
    354  1.4  jakllsch 	case DRM_MODE_CONNECTOR_eDP:
    355  1.4  jakllsch 		sc->sc_conf->set_polarity(sc, VOP_EP_EDP, pol);
    356  1.4  jakllsch 		break;
    357  1.4  jakllsch 	}
    358  1.4  jakllsch 
    359  1.4  jakllsch 	val = RD4(sc, VOP_SYS_CTRL);
    360  1.4  jakllsch 	val &= ~VOP_STANDBY_EN;
    361  1.4  jakllsch 	val &= ~(MIPI_OUT_EN|EDP_OUT_EN|HDMI_OUT_EN|RGB_OUT_EN);
    362  1.4  jakllsch 
    363  1.4  jakllsch 	switch (connector_type) {
    364  1.4  jakllsch 	case DRM_MODE_CONNECTOR_HDMIA:
    365  1.4  jakllsch 		val |= HDMI_OUT_EN;
    366  1.4  jakllsch 		break;
    367  1.4  jakllsch 	case DRM_MODE_CONNECTOR_eDP:
    368  1.4  jakllsch 		val |= EDP_OUT_EN;
    369  1.4  jakllsch 		break;
    370  1.4  jakllsch 	}
    371  1.4  jakllsch 	WR4(sc, VOP_SYS_CTRL, val);
    372  1.4  jakllsch 
    373  1.4  jakllsch 	val = RD4(sc, VOP_DSP_CTRL0);
    374  1.4  jakllsch 	val &= ~DSP_OUT_MODE;
    375  1.4  jakllsch 	val |= __SHIFTIN(sc->sc_conf->out_mode, DSP_OUT_MODE);
    376  1.4  jakllsch 	WR4(sc, VOP_DSP_CTRL0, val);
    377  1.4  jakllsch 
    378  1.4  jakllsch 	val = __SHIFTIN(hsync_len + hback_porch, DSP_HACT_ST_POST) |
    379  1.4  jakllsch 	      __SHIFTIN(hsync_len + hback_porch + hactive, DSP_HACT_END_POST);
    380  1.4  jakllsch 	WR4(sc, VOP_POST_DSP_HACT_INFO, val);
    381  1.4  jakllsch 
    382  1.4  jakllsch 	val = __SHIFTIN(hsync_len + hback_porch, DSP_HACT_ST) |
    383  1.4  jakllsch 	      __SHIFTIN(hsync_len + hback_porch + hactive, DSP_HACT_END);
    384  1.4  jakllsch 	WR4(sc, VOP_DSP_HACT_ST_END, val);
    385  1.4  jakllsch 
    386  1.4  jakllsch 	val = __SHIFTIN(hsync_len, DSP_HTOTAL) |
    387  1.4  jakllsch 	      __SHIFTIN(hsync_len + hback_porch + hactive + hfront_porch, DSP_HS_END);
    388  1.4  jakllsch 	WR4(sc, VOP_DSP_HTOTAL_HS_END, val);
    389  1.4  jakllsch 
    390  1.4  jakllsch 	val = __SHIFTIN(vsync_len + vback_porch, DSP_VACT_ST_POST) |
    391  1.4  jakllsch 	      __SHIFTIN(vsync_len + vback_porch + vactive, DSP_VACT_END_POST);
    392  1.4  jakllsch 	WR4(sc, VOP_POST_DSP_VACT_INFO, val);
    393  1.4  jakllsch 
    394  1.4  jakllsch 	val = __SHIFTIN(vsync_len + vback_porch, DSP_VACT_ST) |
    395  1.4  jakllsch 	      __SHIFTIN(vsync_len + vback_porch + vactive, DSP_VACT_END);
    396  1.4  jakllsch 	WR4(sc, VOP_DSP_VACT_ST_END, val);
    397  1.4  jakllsch 
    398  1.4  jakllsch 	val = __SHIFTIN(vsync_len, DSP_VTOTAL) |
    399  1.4  jakllsch 	      __SHIFTIN(vsync_len + vback_porch + vactive + vfront_porch, DSP_VS_END);
    400  1.4  jakllsch 	WR4(sc, VOP_DSP_VTOTAL_VS_END, val);
    401  1.4  jakllsch 
    402  1.1  jmcneill 	return 0;
    403  1.1  jmcneill }
    404  1.1  jmcneill 
    405  1.1  jmcneill static int
    406  1.1  jmcneill rk_vop_mode_set_base(struct drm_crtc *crtc, int x, int y,
    407  1.1  jmcneill     struct drm_framebuffer *old_fb)
    408  1.1  jmcneill {
    409  1.1  jmcneill 	struct rk_vop_crtc *mixer_crtc = to_rk_vop_crtc(crtc);
    410  1.1  jmcneill 	struct rk_vop_softc * const sc = mixer_crtc->sc;
    411  1.1  jmcneill 
    412  1.1  jmcneill 	rk_vop_mode_do_set_base(crtc, old_fb, x, y, 0);
    413  1.1  jmcneill 
    414  1.1  jmcneill 	/* Commit settings */
    415  1.1  jmcneill 	WR4(sc, VOP_REG_CFG_DONE, REG_LOAD_EN);
    416  1.1  jmcneill 
    417  1.1  jmcneill 	return 0;
    418  1.1  jmcneill }
    419  1.1  jmcneill 
    420  1.1  jmcneill static int
    421  1.1  jmcneill rk_vop_mode_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb,
    422  1.1  jmcneill     int x, int y, enum mode_set_atomic state)
    423  1.1  jmcneill {
    424  1.1  jmcneill 	struct rk_vop_crtc *mixer_crtc = to_rk_vop_crtc(crtc);
    425  1.1  jmcneill 	struct rk_vop_softc * const sc = mixer_crtc->sc;
    426  1.1  jmcneill 
    427  1.1  jmcneill 	rk_vop_mode_do_set_base(crtc, fb, x, y, 1);
    428  1.1  jmcneill 
    429  1.1  jmcneill 	/* Commit settings */
    430  1.1  jmcneill 	WR4(sc, VOP_REG_CFG_DONE, REG_LOAD_EN);
    431  1.1  jmcneill 
    432  1.1  jmcneill 	return 0;
    433  1.1  jmcneill }
    434  1.1  jmcneill 
    435  1.1  jmcneill static void
    436  1.1  jmcneill rk_vop_disable(struct drm_crtc *crtc)
    437  1.1  jmcneill {
    438  1.1  jmcneill }
    439  1.1  jmcneill 
    440  1.1  jmcneill static void
    441  1.1  jmcneill rk_vop_prepare(struct drm_crtc *crtc)
    442  1.1  jmcneill {
    443  1.1  jmcneill }
    444  1.1  jmcneill 
    445  1.1  jmcneill static void
    446  1.1  jmcneill rk_vop_commit(struct drm_crtc *crtc)
    447  1.1  jmcneill {
    448  1.1  jmcneill 	struct rk_vop_crtc *mixer_crtc = to_rk_vop_crtc(crtc);
    449  1.1  jmcneill 	struct rk_vop_softc * const sc = mixer_crtc->sc;
    450  1.1  jmcneill 
    451  1.1  jmcneill 	/* Commit settings */
    452  1.1  jmcneill 	WR4(sc, VOP_REG_CFG_DONE, REG_LOAD_EN);
    453  1.1  jmcneill }
    454  1.1  jmcneill 
    455  1.1  jmcneill static const struct drm_crtc_helper_funcs rk_vop_crtc_helper_funcs = {
    456  1.1  jmcneill 	.dpms = rk_vop_dpms,
    457  1.1  jmcneill 	.mode_fixup = rk_vop_mode_fixup,
    458  1.1  jmcneill 	.mode_set = rk_vop_mode_set,
    459  1.1  jmcneill 	.mode_set_base = rk_vop_mode_set_base,
    460  1.1  jmcneill 	.mode_set_base_atomic = rk_vop_mode_set_base_atomic,
    461  1.1  jmcneill 	.disable = rk_vop_disable,
    462  1.1  jmcneill 	.prepare = rk_vop_prepare,
    463  1.1  jmcneill 	.commit = rk_vop_commit,
    464  1.1  jmcneill };
    465  1.1  jmcneill 
    466  1.1  jmcneill static int
    467  1.1  jmcneill rk_vop_ep_activate(device_t dev, struct fdt_endpoint *ep, bool activate)
    468  1.1  jmcneill {
    469  1.1  jmcneill 	struct rk_vop_softc * const sc = device_private(dev);
    470  1.1  jmcneill 	struct drm_device *ddev;
    471  1.1  jmcneill 
    472  1.1  jmcneill 	if (!activate)
    473  1.1  jmcneill 		return EINVAL;
    474  1.1  jmcneill 
    475  1.1  jmcneill 	ddev = rk_drm_port_device(&sc->sc_ports);
    476  1.1  jmcneill 	if (ddev == NULL) {
    477  1.1  jmcneill 		DRM_ERROR("couldn't find DRM device\n");
    478  1.1  jmcneill 		return ENXIO;
    479  1.1  jmcneill 	}
    480  1.1  jmcneill 
    481  1.1  jmcneill 	if (sc->sc_crtc.sc == NULL) {
    482  1.1  jmcneill 		sc->sc_crtc.sc = sc;
    483  1.1  jmcneill 
    484  1.1  jmcneill 		drm_crtc_init(ddev, &sc->sc_crtc.base, &rk_vop_crtc_funcs);
    485  1.1  jmcneill 		drm_crtc_helper_add(&sc->sc_crtc.base, &rk_vop_crtc_helper_funcs);
    486  1.1  jmcneill 
    487  1.1  jmcneill 		aprint_debug_dev(dev, "using CRTC %d for %s\n",
    488  1.1  jmcneill 		    drm_crtc_index(&sc->sc_crtc.base), sc->sc_conf->descr);
    489  1.1  jmcneill 	}
    490  1.1  jmcneill 
    491  1.1  jmcneill 	const u_int ep_index = fdt_endpoint_index(ep);
    492  1.4  jakllsch 	if (ep_index >= VOP_NEP) {
    493  1.3       mrg 		DRM_ERROR("endpoint index %d out of range\n", ep_index);
    494  1.3       mrg 		return ENXIO;
    495  1.1  jmcneill 	}
    496  1.1  jmcneill 
    497  1.1  jmcneill 	return fdt_endpoint_activate(ep, activate);
    498  1.1  jmcneill }
    499  1.1  jmcneill 
    500  1.1  jmcneill static void *
    501  1.1  jmcneill rk_vop_ep_get_data(device_t dev, struct fdt_endpoint *ep)
    502  1.1  jmcneill {
    503  1.1  jmcneill 	struct rk_vop_softc * const sc = device_private(dev);
    504  1.1  jmcneill 
    505  1.4  jakllsch 	return &sc->sc_crtc.base;
    506  1.1  jmcneill }
    507  1.1  jmcneill 
    508  1.1  jmcneill static int
    509  1.1  jmcneill rk_vop_match(device_t parent, cfdata_t cf, void *aux)
    510  1.1  jmcneill {
    511  1.1  jmcneill 	struct fdt_attach_args * const faa = aux;
    512  1.1  jmcneill 
    513  1.1  jmcneill 	return of_match_compat_data(faa->faa_phandle, compat_data);
    514  1.1  jmcneill }
    515  1.1  jmcneill 
    516  1.1  jmcneill static void
    517  1.1  jmcneill rk_vop_attach(device_t parent, device_t self, void *aux)
    518  1.1  jmcneill {
    519  1.1  jmcneill 	struct rk_vop_softc * const sc = device_private(self);
    520  1.1  jmcneill 	struct fdt_attach_args * const faa = aux;
    521  1.1  jmcneill 	const int phandle = faa->faa_phandle;
    522  1.1  jmcneill 	const char * const reset_names[] = { "axi", "ahb", "dclk" };
    523  1.1  jmcneill 	const char * const clock_names[] = { "aclk_vop", "hclk_vop" };
    524  1.1  jmcneill 	struct fdtbus_reset *rst;
    525  1.1  jmcneill 	bus_addr_t addr;
    526  1.1  jmcneill 	bus_size_t size;
    527  1.1  jmcneill 	u_int n;
    528  1.1  jmcneill 
    529  1.1  jmcneill 	if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) {
    530  1.1  jmcneill 		aprint_error(": couldn't get registers\n");
    531  1.1  jmcneill 		return;
    532  1.1  jmcneill 	}
    533  1.1  jmcneill 
    534  1.1  jmcneill 	fdtbus_clock_assign(phandle);
    535  1.1  jmcneill 
    536  1.1  jmcneill 	for (n = 0; n < __arraycount(reset_names); n++) {
    537  1.1  jmcneill 		rst = fdtbus_reset_get(phandle, reset_names[n]);
    538  1.1  jmcneill 		if (rst == NULL || fdtbus_reset_deassert(rst) != 0) {
    539  1.1  jmcneill 			aprint_error(": couldn't de-assert reset %s\n", reset_names[n]);
    540  1.1  jmcneill 			return;
    541  1.1  jmcneill 		}
    542  1.1  jmcneill 	}
    543  1.1  jmcneill 	for (n = 0; n < __arraycount(clock_names); n++) {
    544  1.1  jmcneill 		if (fdtbus_clock_enable(phandle, clock_names[n], true) != 0) {
    545  1.1  jmcneill 			aprint_error(": couldn't enable clock %s\n", clock_names[n]);
    546  1.1  jmcneill 			return;
    547  1.1  jmcneill 		}
    548  1.1  jmcneill 	}
    549  1.1  jmcneill 	sc->sc_dclk = fdtbus_clock_get(phandle, "dclk_vop");
    550  1.1  jmcneill 	if (sc->sc_dclk == NULL || clk_enable(sc->sc_dclk) != 0) {
    551  1.1  jmcneill 		aprint_error(": couldn't enable clock %s\n", "dclk_vop");
    552  1.1  jmcneill 		return;
    553  1.1  jmcneill 	}
    554  1.1  jmcneill 
    555  1.1  jmcneill 	sc->sc_dev = self;
    556  1.1  jmcneill 	sc->sc_bst = faa->faa_bst;
    557  1.1  jmcneill 	if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh) != 0) {
    558  1.1  jmcneill 		aprint_error(": couldn't map registers\n");
    559  1.1  jmcneill 		return;
    560  1.1  jmcneill 	}
    561  1.1  jmcneill 	sc->sc_phandle = faa->faa_phandle;
    562  1.1  jmcneill 	sc->sc_conf = (void *)of_search_compatible(phandle, compat_data)->data;
    563  1.1  jmcneill 
    564  1.1  jmcneill 	aprint_naive("\n");
    565  1.1  jmcneill 	aprint_normal(": %s\n", sc->sc_conf->descr);
    566  1.1  jmcneill 
    567  1.1  jmcneill 	if (sc->sc_conf->init != NULL)
    568  1.1  jmcneill 		sc->sc_conf->init(sc);
    569  1.1  jmcneill 
    570  1.1  jmcneill 	sc->sc_ports.dp_ep_activate = rk_vop_ep_activate;
    571  1.1  jmcneill 	sc->sc_ports.dp_ep_get_data = rk_vop_ep_get_data;
    572  1.4  jakllsch 	fdt_ports_register(&sc->sc_ports, self, phandle, EP_DRM_CRTC);
    573  1.1  jmcneill 
    574  1.1  jmcneill 	const int port_phandle = of_find_firstchild_byname(phandle, "port");
    575  1.1  jmcneill 	if (port_phandle > 0)
    576  1.1  jmcneill 		rk_drm_register_port(port_phandle, &sc->sc_ports);
    577  1.1  jmcneill }
    578  1.1  jmcneill 
    579  1.1  jmcneill CFATTACH_DECL_NEW(rk_vop, sizeof(struct rk_vop_softc),
    580  1.1  jmcneill 	rk_vop_match, rk_vop_attach, NULL, NULL);
    581