1a0a23564SMichal Meloun /*- 2a0a23564SMichal Meloun * Copyright (c) 2015 Michal Meloun 3a0a23564SMichal Meloun * All rights reserved. 4a0a23564SMichal Meloun * 5a0a23564SMichal Meloun * Redistribution and use in source and binary forms, with or without 6a0a23564SMichal Meloun * modification, are permitted provided that the following conditions 7a0a23564SMichal Meloun * are met: 8a0a23564SMichal Meloun * 1. Redistributions of source code must retain the above copyright 9a0a23564SMichal Meloun * notice, this list of conditions and the following disclaimer. 10a0a23564SMichal Meloun * 2. Redistributions in binary form must reproduce the above copyright 11a0a23564SMichal Meloun * notice, this list of conditions and the following disclaimer in the 12a0a23564SMichal Meloun * documentation and/or other materials provided with the distribution. 13a0a23564SMichal Meloun * 14a0a23564SMichal Meloun * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15a0a23564SMichal Meloun * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16a0a23564SMichal Meloun * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17a0a23564SMichal Meloun * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18a0a23564SMichal Meloun * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19a0a23564SMichal Meloun * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20a0a23564SMichal Meloun * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21a0a23564SMichal Meloun * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22a0a23564SMichal Meloun * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23a0a23564SMichal Meloun * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24a0a23564SMichal Meloun * SUCH DAMAGE. 25a0a23564SMichal Meloun */ 26a0a23564SMichal Meloun 27a0a23564SMichal Meloun #include <sys/param.h> 28a0a23564SMichal Meloun #include <sys/systm.h> 29a0a23564SMichal Meloun #include <sys/bus.h> 30a0a23564SMichal Meloun #include <sys/gpio.h> 31a0a23564SMichal Meloun #include <sys/kernel.h> 32a0a23564SMichal Meloun #include <sys/module.h> 33a0a23564SMichal Meloun #include <sys/malloc.h> 34a0a23564SMichal Meloun #include <sys/rman.h> 35a0a23564SMichal Meloun #include <sys/sysctl.h> 36a0a23564SMichal Meloun 37a0a23564SMichal Meloun #include <machine/bus.h> 38a0a23564SMichal Meloun 39be82b3a0SEmmanuel Vadot #include <dev/clk/clk.h> 401f469a9fSEmmanuel Vadot #include <dev/hwreset/hwreset.h> 41a0a23564SMichal Meloun #include <dev/drm2/drmP.h> 42a0a23564SMichal Meloun #include <dev/drm2/drm_crtc_helper.h> 43a0a23564SMichal Meloun #include <dev/drm2/drm_fb_helper.h> 44a0a23564SMichal Meloun #include <dev/drm2/drm_fixed.h> 45a0a23564SMichal Meloun #include <dev/ofw/ofw_bus.h> 46a0a23564SMichal Meloun #include <dev/ofw/ofw_bus_subr.h> 47a0a23564SMichal Meloun 48a0a23564SMichal Meloun #include <arm/nvidia/drm2/tegra_dc_reg.h> 49a0a23564SMichal Meloun #include <arm/nvidia/drm2/tegra_drm.h> 50a0a23564SMichal Meloun #include <arm/nvidia/tegra_pmc.h> 51a0a23564SMichal Meloun 52a0a23564SMichal Meloun #include "tegra_drm_if.h" 53a0a23564SMichal Meloun #include "tegra_dc_if.h" 54a0a23564SMichal Meloun 55a0a23564SMichal Meloun #define WR4(_sc, _r, _v) bus_write_4((_sc)->mem_res, 4 * (_r), (_v)) 56a0a23564SMichal Meloun #define RD4(_sc, _r) bus_read_4((_sc)->mem_res, 4 * (_r)) 57a0a23564SMichal Meloun 58a0a23564SMichal Meloun #define LOCK(_sc) mtx_lock(&(_sc)->mtx) 59a0a23564SMichal Meloun #define UNLOCK(_sc) mtx_unlock(&(_sc)->mtx) 60a0a23564SMichal Meloun #define SLEEP(_sc, timeout) \ 61a0a23564SMichal Meloun mtx_sleep(sc, &sc->mtx, 0, "tegra_dc_wait", timeout); 62a0a23564SMichal Meloun #define LOCK_INIT(_sc) \ 63a0a23564SMichal Meloun mtx_init(&_sc->mtx, device_get_nameunit(_sc->dev), "tegra_dc", MTX_DEF) 64a0a23564SMichal Meloun #define LOCK_DESTROY(_sc) mtx_destroy(&_sc->mtx) 65a0a23564SMichal Meloun #define ASSERT_LOCKED(_sc) mtx_assert(&_sc->mtx, MA_OWNED) 66a0a23564SMichal Meloun #define ASSERT_UNLOCKED(_sc) mtx_assert(&_sc->mtx, MA_NOTOWNED) 67a0a23564SMichal Meloun 68a0a23564SMichal Meloun #define SYNCPT_VBLANK0 26 69a0a23564SMichal Meloun #define SYNCPT_VBLANK1 27 70a0a23564SMichal Meloun 71a0a23564SMichal Meloun #define DC_MAX_PLANES 2 /* Maximum planes */ 72a0a23564SMichal Meloun 73a0a23564SMichal Meloun /* DRM Formats supported by DC */ 74a0a23564SMichal Meloun /* XXXX expand me */ 75a0a23564SMichal Meloun static uint32_t dc_plane_formats[] = { 76a0a23564SMichal Meloun DRM_FORMAT_XBGR8888, 77a0a23564SMichal Meloun DRM_FORMAT_XRGB8888, 78a0a23564SMichal Meloun DRM_FORMAT_RGB565, 79a0a23564SMichal Meloun DRM_FORMAT_UYVY, 80a0a23564SMichal Meloun DRM_FORMAT_YUYV, 81a0a23564SMichal Meloun DRM_FORMAT_YUV420, 82a0a23564SMichal Meloun DRM_FORMAT_YUV422, 83a0a23564SMichal Meloun }; 84a0a23564SMichal Meloun 85a0a23564SMichal Meloun /* Complete description of one window (plane) */ 86a0a23564SMichal Meloun struct dc_window { 87a0a23564SMichal Meloun /* Source (in framebuffer) rectangle, in pixels */ 88a0a23564SMichal Meloun u_int src_x; 89a0a23564SMichal Meloun u_int src_y; 90a0a23564SMichal Meloun u_int src_w; 91a0a23564SMichal Meloun u_int src_h; 92a0a23564SMichal Meloun 93a0a23564SMichal Meloun /* Destination (on display) rectangle, in pixels */ 94a0a23564SMichal Meloun u_int dst_x; 95a0a23564SMichal Meloun u_int dst_y; 96a0a23564SMichal Meloun u_int dst_w; 97a0a23564SMichal Meloun u_int dst_h; 98a0a23564SMichal Meloun 99a0a23564SMichal Meloun /* Parsed pixel format */ 100a0a23564SMichal Meloun u_int bits_per_pixel; 101a0a23564SMichal Meloun bool is_yuv; /* any YUV mode */ 102a0a23564SMichal Meloun bool is_yuv_planar; /* planar YUV mode */ 103a0a23564SMichal Meloun uint32_t color_mode; /* DC_WIN_COLOR_DEPTH */ 104a0a23564SMichal Meloun uint32_t swap; /* DC_WIN_BYTE_SWAP */ 105a0a23564SMichal Meloun uint32_t surface_kind; /* DC_WINBUF_SURFACE_KIND */ 106a0a23564SMichal Meloun uint32_t block_height; /* DC_WINBUF_SURFACE_KIND */ 107a0a23564SMichal Meloun 108a0a23564SMichal Meloun /* Parsed flipping, rotation is not supported for pitched modes */ 109a0a23564SMichal Meloun bool flip_x; /* inverted X-axis */ 110a0a23564SMichal Meloun bool flip_y; /* inverted Y-axis */ 111a0a23564SMichal Meloun bool transpose_xy; /* swap X and Y-axis */ 112a0a23564SMichal Meloun 113a0a23564SMichal Meloun /* Color planes base addresses and strides */ 114a0a23564SMichal Meloun bus_size_t base[3]; 115a0a23564SMichal Meloun uint32_t stride[3]; /* stride[2] isn't used by HW */ 116a0a23564SMichal Meloun }; 117a0a23564SMichal Meloun 118a0a23564SMichal Meloun struct dc_softc { 119a0a23564SMichal Meloun device_t dev; 120a0a23564SMichal Meloun struct resource *mem_res; 121a0a23564SMichal Meloun struct resource *irq_res; 122a0a23564SMichal Meloun void *irq_ih; 123a0a23564SMichal Meloun struct mtx mtx; 124a0a23564SMichal Meloun 125a0a23564SMichal Meloun clk_t clk_parent; 126a0a23564SMichal Meloun clk_t clk_dc; 127a0a23564SMichal Meloun hwreset_t hwreset_dc; 128a0a23564SMichal Meloun 129a0a23564SMichal Meloun int pitch_align; 130a0a23564SMichal Meloun 131a0a23564SMichal Meloun struct tegra_crtc tegra_crtc; 132a0a23564SMichal Meloun struct drm_pending_vblank_event *event; 133a0a23564SMichal Meloun struct drm_gem_object *cursor_gem; 134a0a23564SMichal Meloun }; 135a0a23564SMichal Meloun 136a0a23564SMichal Meloun static struct ofw_compat_data compat_data[] = { 137a0a23564SMichal Meloun {"nvidia,tegra124-dc", 1}, 138a0a23564SMichal Meloun {NULL, 0}, 139a0a23564SMichal Meloun }; 140a0a23564SMichal Meloun 141a0a23564SMichal Meloun /* Convert standard drm pixel format to tegra windows parameters. */ 142a0a23564SMichal Meloun static int 143a0a23564SMichal Meloun dc_parse_drm_format(struct tegra_fb *fb, struct dc_window *win) 144a0a23564SMichal Meloun { 145a0a23564SMichal Meloun struct tegra_bo *bo; 146a0a23564SMichal Meloun uint32_t cm; 147a0a23564SMichal Meloun uint32_t sw; 148a0a23564SMichal Meloun bool is_yuv, is_yuv_planar; 149a0a23564SMichal Meloun int nplanes, i; 150a0a23564SMichal Meloun 151a0a23564SMichal Meloun switch (fb->drm_fb.pixel_format) { 152a0a23564SMichal Meloun case DRM_FORMAT_XBGR8888: 153a0a23564SMichal Meloun sw = BYTE_SWAP(NOSWAP); 154a0a23564SMichal Meloun cm = WIN_COLOR_DEPTH_R8G8B8A8; 155a0a23564SMichal Meloun is_yuv = false; 156a0a23564SMichal Meloun is_yuv_planar = false; 157a0a23564SMichal Meloun break; 158a0a23564SMichal Meloun 159a0a23564SMichal Meloun case DRM_FORMAT_XRGB8888: 160a0a23564SMichal Meloun sw = BYTE_SWAP(NOSWAP); 161a0a23564SMichal Meloun cm = WIN_COLOR_DEPTH_B8G8R8A8; 162a0a23564SMichal Meloun is_yuv = false; 163a0a23564SMichal Meloun is_yuv_planar = false; 164a0a23564SMichal Meloun break; 165a0a23564SMichal Meloun 166a0a23564SMichal Meloun case DRM_FORMAT_RGB565: 167a0a23564SMichal Meloun sw = BYTE_SWAP(NOSWAP); 168a0a23564SMichal Meloun cm = WIN_COLOR_DEPTH_B5G6R5; 169a0a23564SMichal Meloun is_yuv = false; 170a0a23564SMichal Meloun is_yuv_planar = false; 171a0a23564SMichal Meloun break; 172a0a23564SMichal Meloun 173a0a23564SMichal Meloun case DRM_FORMAT_UYVY: 174a0a23564SMichal Meloun sw = BYTE_SWAP(NOSWAP); 175a0a23564SMichal Meloun cm = WIN_COLOR_DEPTH_YCbCr422; 176a0a23564SMichal Meloun is_yuv = true; 177a0a23564SMichal Meloun is_yuv_planar = false; 178a0a23564SMichal Meloun break; 179a0a23564SMichal Meloun 180a0a23564SMichal Meloun case DRM_FORMAT_YUYV: 181a0a23564SMichal Meloun sw = BYTE_SWAP(SWAP2); 182a0a23564SMichal Meloun cm = WIN_COLOR_DEPTH_YCbCr422; 183a0a23564SMichal Meloun is_yuv = true; 184a0a23564SMichal Meloun is_yuv_planar = false; 185a0a23564SMichal Meloun break; 186a0a23564SMichal Meloun 187a0a23564SMichal Meloun case DRM_FORMAT_YUV420: 188a0a23564SMichal Meloun sw = BYTE_SWAP(NOSWAP); 189a0a23564SMichal Meloun cm = WIN_COLOR_DEPTH_YCbCr420P; 190a0a23564SMichal Meloun is_yuv = true; 191a0a23564SMichal Meloun is_yuv_planar = true; 192a0a23564SMichal Meloun break; 193a0a23564SMichal Meloun 194a0a23564SMichal Meloun case DRM_FORMAT_YUV422: 195a0a23564SMichal Meloun sw = BYTE_SWAP(NOSWAP); 196a0a23564SMichal Meloun cm = WIN_COLOR_DEPTH_YCbCr422P; 197a0a23564SMichal Meloun is_yuv = true; 198a0a23564SMichal Meloun is_yuv_planar = true; 199a0a23564SMichal Meloun break; 200a0a23564SMichal Meloun 201a0a23564SMichal Meloun default: 202a0a23564SMichal Meloun /* Unsupported format */ 203a0a23564SMichal Meloun return (-EINVAL); 204a0a23564SMichal Meloun } 205a0a23564SMichal Meloun 206a0a23564SMichal Meloun /* Basic check of arguments. */ 207a0a23564SMichal Meloun switch (fb->rotation) { 208a0a23564SMichal Meloun case 0: 209a0a23564SMichal Meloun case 180: 210a0a23564SMichal Meloun break; 211a0a23564SMichal Meloun 212a0a23564SMichal Meloun case 90: /* Rotation is supported only */ 213a0a23564SMichal Meloun case 270: /* for block linear surfaces */ 214a0a23564SMichal Meloun if (!fb->block_linear) 215a0a23564SMichal Meloun return (-EINVAL); 216a0a23564SMichal Meloun break; 217a0a23564SMichal Meloun 218a0a23564SMichal Meloun default: 219a0a23564SMichal Meloun return (-EINVAL); 220a0a23564SMichal Meloun } 221a0a23564SMichal Meloun /* XXX Add more checks (sizes, scaling...) */ 222a0a23564SMichal Meloun 223a0a23564SMichal Meloun if (win == NULL) 224a0a23564SMichal Meloun return (0); 225a0a23564SMichal Meloun 226a0a23564SMichal Meloun win->surface_kind = 227a0a23564SMichal Meloun fb->block_linear ? SURFACE_KIND_BL_16B2: SURFACE_KIND_PITCH; 228a0a23564SMichal Meloun win->block_height = fb->block_height; 229a0a23564SMichal Meloun switch (fb->rotation) { 230a0a23564SMichal Meloun case 0: /* (0,0,0) */ 231a0a23564SMichal Meloun win->transpose_xy = false; 232a0a23564SMichal Meloun win->flip_x = false; 233a0a23564SMichal Meloun win->flip_y = false; 234a0a23564SMichal Meloun break; 235a0a23564SMichal Meloun 236a0a23564SMichal Meloun case 90: /* (1,0,1) */ 237a0a23564SMichal Meloun win->transpose_xy = true; 238a0a23564SMichal Meloun win->flip_x = false; 239a0a23564SMichal Meloun win->flip_y = true; 240a0a23564SMichal Meloun break; 241a0a23564SMichal Meloun 242a0a23564SMichal Meloun case 180: /* (0,1,1) */ 243a0a23564SMichal Meloun win->transpose_xy = false; 244a0a23564SMichal Meloun win->flip_x = true; 245a0a23564SMichal Meloun win->flip_y = true; 246a0a23564SMichal Meloun break; 247a0a23564SMichal Meloun 248a0a23564SMichal Meloun case 270: /* (1,1,0) */ 249a0a23564SMichal Meloun win->transpose_xy = true; 250a0a23564SMichal Meloun win->flip_x = true; 251a0a23564SMichal Meloun win->flip_y = false; 252a0a23564SMichal Meloun break; 253a0a23564SMichal Meloun } 254a0a23564SMichal Meloun win->flip_x ^= fb->flip_x; 255a0a23564SMichal Meloun win->flip_y ^= fb->flip_y; 256a0a23564SMichal Meloun 257a0a23564SMichal Meloun win->color_mode = cm; 258a0a23564SMichal Meloun win->swap = sw; 259a0a23564SMichal Meloun win->bits_per_pixel = fb->drm_fb.bits_per_pixel; 260a0a23564SMichal Meloun win->is_yuv = is_yuv; 261a0a23564SMichal Meloun win->is_yuv_planar = is_yuv_planar; 262a0a23564SMichal Meloun 263a0a23564SMichal Meloun nplanes = drm_format_num_planes(fb->drm_fb.pixel_format); 264a0a23564SMichal Meloun for (i = 0; i < nplanes; i++) { 265a0a23564SMichal Meloun bo = fb->planes[i]; 266a0a23564SMichal Meloun win->base[i] = bo->pbase + fb->drm_fb.offsets[i]; 267a0a23564SMichal Meloun win->stride[i] = fb->drm_fb.pitches[i]; 268a0a23564SMichal Meloun } 269a0a23564SMichal Meloun return (0); 270a0a23564SMichal Meloun } 271a0a23564SMichal Meloun 272a0a23564SMichal Meloun /* 273a0a23564SMichal Meloun * Scaling functions. 274a0a23564SMichal Meloun * 275a0a23564SMichal Meloun * It's unclear if we want/must program the fractional portion 276a0a23564SMichal Meloun * (aka bias) of init_dda registers, mainly when mirrored axis 277a0a23564SMichal Meloun * modes are used. 278a0a23564SMichal Meloun * For now, we use 1.0 as recommended by TRM. 279a0a23564SMichal Meloun */ 280a0a23564SMichal Meloun static inline uint32_t 281a0a23564SMichal Meloun dc_scaling_init(uint32_t start) 282a0a23564SMichal Meloun { 283a0a23564SMichal Meloun 284a0a23564SMichal Meloun return (1 << 12); 285a0a23564SMichal Meloun } 286a0a23564SMichal Meloun 287a0a23564SMichal Meloun static inline uint32_t 288a0a23564SMichal Meloun dc_scaling_incr(uint32_t src, uint32_t dst, uint32_t maxscale) 289a0a23564SMichal Meloun { 290a0a23564SMichal Meloun uint32_t val; 291a0a23564SMichal Meloun 292a0a23564SMichal Meloun val = (src - 1) << 12 ; /* 4.12 fixed float */ 293a0a23564SMichal Meloun val /= (dst - 1); 294a0a23564SMichal Meloun if (val > (maxscale << 12)) 295a0a23564SMichal Meloun val = maxscale << 12; 296a0a23564SMichal Meloun return val; 297a0a23564SMichal Meloun } 298a0a23564SMichal Meloun 299a0a23564SMichal Meloun /* ------------------------------------------------------------------- 300a0a23564SMichal Meloun * 301a0a23564SMichal Meloun * HW Access. 302a0a23564SMichal Meloun * 303a0a23564SMichal Meloun */ 304a0a23564SMichal Meloun 305a0a23564SMichal Meloun /* 306a0a23564SMichal Meloun * Setup pixel clock. 307a0a23564SMichal Meloun * Minimal frequency is pixel clock, but output is free to select 308a0a23564SMichal Meloun * any higher. 309a0a23564SMichal Meloun */ 310a0a23564SMichal Meloun static int 311a0a23564SMichal Meloun dc_setup_clk(struct dc_softc *sc, struct drm_crtc *crtc, 312a0a23564SMichal Meloun struct drm_display_mode *mode, uint32_t *div) 313a0a23564SMichal Meloun { 314a0a23564SMichal Meloun uint64_t pclk, freq; 315a0a23564SMichal Meloun struct tegra_drm_encoder *output; 316a0a23564SMichal Meloun struct drm_encoder *encoder; 317a0a23564SMichal Meloun long rv; 318a0a23564SMichal Meloun 319a0a23564SMichal Meloun pclk = mode->clock * 1000; 320a0a23564SMichal Meloun 321a0a23564SMichal Meloun /* Find attached encoder */ 322a0a23564SMichal Meloun output = NULL; 323a0a23564SMichal Meloun list_for_each_entry(encoder, &crtc->dev->mode_config.encoder_list, 324a0a23564SMichal Meloun head) { 325a0a23564SMichal Meloun if (encoder->crtc == crtc) { 326a0a23564SMichal Meloun output = container_of(encoder, struct tegra_drm_encoder, 327a0a23564SMichal Meloun encoder); 328a0a23564SMichal Meloun break; 329a0a23564SMichal Meloun } 330a0a23564SMichal Meloun } 331a0a23564SMichal Meloun if (output == NULL) 332a0a23564SMichal Meloun return (-ENODEV); 333a0a23564SMichal Meloun 334a0a23564SMichal Meloun if (output->setup_clock == NULL) 335a0a23564SMichal Meloun panic("Output have not setup_clock function.\n"); 336a0a23564SMichal Meloun rv = output->setup_clock(output, sc->clk_dc, pclk); 337a0a23564SMichal Meloun if (rv != 0) { 338a0a23564SMichal Meloun device_printf(sc->dev, "Cannot setup pixel clock: %llu\n", 339a0a23564SMichal Meloun pclk); 340a0a23564SMichal Meloun return (rv); 341a0a23564SMichal Meloun } 342a0a23564SMichal Meloun 343a0a23564SMichal Meloun rv = clk_get_freq(sc->clk_dc, &freq); 344a0a23564SMichal Meloun *div = (freq * 2 / pclk) - 2; 345a0a23564SMichal Meloun 346a0a23564SMichal Meloun DRM_DEBUG_KMS("frequency: %llu, DC divider: %u\n", freq, *div); 347a0a23564SMichal Meloun 348a0a23564SMichal Meloun return 0; 349a0a23564SMichal Meloun } 350a0a23564SMichal Meloun 351a0a23564SMichal Meloun static void 352a0a23564SMichal Meloun dc_setup_window(struct dc_softc *sc, unsigned int index, struct dc_window *win) 353a0a23564SMichal Meloun { 354a0a23564SMichal Meloun uint32_t h_offset, v_offset, h_size, v_size, bpp; 355a0a23564SMichal Meloun uint32_t h_init_dda, v_init_dda, h_incr_dda, v_incr_dda; 356a0a23564SMichal Meloun uint32_t val; 357a0a23564SMichal Meloun 358a0a23564SMichal Meloun #ifdef DMR_DEBUG_WINDOW 359a0a23564SMichal Meloun printf("%s window: %d\n", __func__, index); 360a0a23564SMichal Meloun printf(" src: x: %d, y: %d, w: %d, h: %d\n", 361a0a23564SMichal Meloun win->src_x, win->src_y, win->src_w, win->src_h); 362a0a23564SMichal Meloun printf(" dst: x: %d, y: %d, w: %d, h: %d\n", 363a0a23564SMichal Meloun win->dst_x, win->dst_y, win->dst_w, win->dst_h); 364a0a23564SMichal Meloun printf(" bpp: %d, color_mode: %d, swap: %d\n", 365a0a23564SMichal Meloun win->bits_per_pixel, win->color_mode, win->swap); 366a0a23564SMichal Meloun #endif 367a0a23564SMichal Meloun 368a0a23564SMichal Meloun if (win->is_yuv) 369a0a23564SMichal Meloun bpp = win->is_yuv_planar ? 1 : 2; 370a0a23564SMichal Meloun else 371a0a23564SMichal Meloun bpp = (win->bits_per_pixel + 7) / 8; 372a0a23564SMichal Meloun 373a0a23564SMichal Meloun if (!win->transpose_xy) { 374a0a23564SMichal Meloun h_size = win->src_w * bpp; 375a0a23564SMichal Meloun v_size = win->src_h; 376a0a23564SMichal Meloun } else { 377a0a23564SMichal Meloun h_size = win->src_h * bpp; 378a0a23564SMichal Meloun v_size = win->src_w; 379a0a23564SMichal Meloun } 380a0a23564SMichal Meloun 381aeb665b5SEd Maste h_offset = win->src_x * bpp; 382a0a23564SMichal Meloun v_offset = win->src_y; 383a0a23564SMichal Meloun if (win->flip_x) { 384a0a23564SMichal Meloun h_offset += win->src_w * bpp - 1; 385a0a23564SMichal Meloun } 386a0a23564SMichal Meloun if (win->flip_y) 387a0a23564SMichal Meloun v_offset += win->src_h - 1; 388a0a23564SMichal Meloun 389a0a23564SMichal Meloun /* Adjust offsets for planar yuv modes */ 390a0a23564SMichal Meloun if (win->is_yuv_planar) { 391a0a23564SMichal Meloun h_offset &= ~1; 392a0a23564SMichal Meloun if (win->flip_x ) 393a0a23564SMichal Meloun h_offset |= 1; 394a0a23564SMichal Meloun v_offset &= ~1; 395a0a23564SMichal Meloun if (win->flip_y ) 396a0a23564SMichal Meloun v_offset |= 1; 397a0a23564SMichal Meloun } 398a0a23564SMichal Meloun 399a0a23564SMichal Meloun /* Setup scaling. */ 400a0a23564SMichal Meloun if (!win->transpose_xy) { 401a0a23564SMichal Meloun h_init_dda = dc_scaling_init(win->src_x); 402a0a23564SMichal Meloun v_init_dda = dc_scaling_init(win->src_y); 403a0a23564SMichal Meloun h_incr_dda = dc_scaling_incr(win->src_w, win->dst_w, 4); 404a0a23564SMichal Meloun v_incr_dda = dc_scaling_incr(win->src_h, win->dst_h, 15); 405a0a23564SMichal Meloun } else { 406a0a23564SMichal Meloun h_init_dda = dc_scaling_init(win->src_y); 407a0a23564SMichal Meloun v_init_dda = dc_scaling_init(win->src_x); 408a0a23564SMichal Meloun h_incr_dda = dc_scaling_incr(win->src_h, win->dst_h, 4); 409a0a23564SMichal Meloun v_incr_dda = dc_scaling_incr(win->src_w, win->dst_w, 15); 410a0a23564SMichal Meloun } 411a0a23564SMichal Meloun #ifdef DMR_DEBUG_WINDOW 412a0a23564SMichal Meloun printf("\n"); 413a0a23564SMichal Meloun printf(" bpp: %d, size: h: %d v: %d, offset: h:%d v: %d\n", 414a0a23564SMichal Meloun bpp, h_size, v_size, h_offset, v_offset); 415a0a23564SMichal Meloun printf(" init_dda: h: %d v: %d, incr_dda: h: %d v: %d\n", 416a0a23564SMichal Meloun h_init_dda, v_init_dda, h_incr_dda, v_incr_dda); 417a0a23564SMichal Meloun #endif 418a0a23564SMichal Meloun 419a0a23564SMichal Meloun LOCK(sc); 420a0a23564SMichal Meloun 421a0a23564SMichal Meloun /* Select target window */ 422a0a23564SMichal Meloun val = WINDOW_A_SELECT << index; 423a0a23564SMichal Meloun WR4(sc, DC_CMD_DISPLAY_WINDOW_HEADER, val); 424a0a23564SMichal Meloun 425a0a23564SMichal Meloun /* Sizes */ 426a0a23564SMichal Meloun WR4(sc, DC_WIN_POSITION, WIN_POSITION(win->dst_x, win->dst_y)); 427a0a23564SMichal Meloun WR4(sc, DC_WIN_SIZE, WIN_SIZE(win->dst_w, win->dst_h)); 428a0a23564SMichal Meloun WR4(sc, DC_WIN_PRESCALED_SIZE, WIN_PRESCALED_SIZE(h_size, v_size)); 429a0a23564SMichal Meloun 430a0a23564SMichal Meloun /* DDA */ 431a0a23564SMichal Meloun WR4(sc, DC_WIN_DDA_INCREMENT, 432a0a23564SMichal Meloun WIN_DDA_INCREMENT(h_incr_dda, v_incr_dda)); 433a0a23564SMichal Meloun WR4(sc, DC_WIN_H_INITIAL_DDA, h_init_dda); 434a0a23564SMichal Meloun WR4(sc, DC_WIN_V_INITIAL_DDA, v_init_dda); 435a0a23564SMichal Meloun 436a0a23564SMichal Meloun /* Color planes base addresses and strides */ 437a0a23564SMichal Meloun WR4(sc, DC_WINBUF_START_ADDR, win->base[0]); 438a0a23564SMichal Meloun if (win->is_yuv_planar) { 439a0a23564SMichal Meloun WR4(sc, DC_WINBUF_START_ADDR_U, win->base[1]); 440a0a23564SMichal Meloun WR4(sc, DC_WINBUF_START_ADDR_V, win->base[2]); 441a0a23564SMichal Meloun WR4(sc, DC_WIN_LINE_STRIDE, 442a0a23564SMichal Meloun win->stride[1] << 16 | win->stride[0]); 443a0a23564SMichal Meloun } else { 444a0a23564SMichal Meloun WR4(sc, DC_WIN_LINE_STRIDE, win->stride[0]); 445a0a23564SMichal Meloun } 446a0a23564SMichal Meloun 447a0a23564SMichal Meloun /* Offsets for rotation and axis flip */ 448a0a23564SMichal Meloun WR4(sc, DC_WINBUF_ADDR_H_OFFSET, h_offset); 449a0a23564SMichal Meloun WR4(sc, DC_WINBUF_ADDR_V_OFFSET, v_offset); 450a0a23564SMichal Meloun 451a0a23564SMichal Meloun /* Color format */ 452a0a23564SMichal Meloun WR4(sc, DC_WIN_COLOR_DEPTH, win->color_mode); 453a0a23564SMichal Meloun WR4(sc, DC_WIN_BYTE_SWAP, win->swap); 454a0a23564SMichal Meloun 455a0a23564SMichal Meloun /* Tiling */ 456a0a23564SMichal Meloun val = win->surface_kind; 457a0a23564SMichal Meloun if (win->surface_kind == SURFACE_KIND_BL_16B2) 458a0a23564SMichal Meloun val |= SURFACE_KIND_BLOCK_HEIGHT(win->block_height); 459a0a23564SMichal Meloun WR4(sc, DC_WINBUF_SURFACE_KIND, val); 460a0a23564SMichal Meloun 461a0a23564SMichal Meloun /* Color space coefs for YUV modes */ 462a0a23564SMichal Meloun if (win->is_yuv) { 463a0a23564SMichal Meloun WR4(sc, DC_WINC_CSC_YOF, 0x00f0); 464a0a23564SMichal Meloun WR4(sc, DC_WINC_CSC_KYRGB, 0x012a); 465a0a23564SMichal Meloun WR4(sc, DC_WINC_CSC_KUR, 0x0000); 466a0a23564SMichal Meloun WR4(sc, DC_WINC_CSC_KVR, 0x0198); 467a0a23564SMichal Meloun WR4(sc, DC_WINC_CSC_KUG, 0x039b); 468a0a23564SMichal Meloun WR4(sc, DC_WINC_CSC_KVG, 0x032f); 469a0a23564SMichal Meloun WR4(sc, DC_WINC_CSC_KUB, 0x0204); 470a0a23564SMichal Meloun WR4(sc, DC_WINC_CSC_KVB, 0x0000); 471a0a23564SMichal Meloun } 472a0a23564SMichal Meloun 473a0a23564SMichal Meloun val = WIN_ENABLE; 474a0a23564SMichal Meloun if (win->is_yuv) 475a0a23564SMichal Meloun val |= CSC_ENABLE; 476a0a23564SMichal Meloun else if (win->bits_per_pixel < 24) 477a0a23564SMichal Meloun val |= COLOR_EXPAND; 478a0a23564SMichal Meloun if (win->flip_y) 479a0a23564SMichal Meloun val |= V_DIRECTION; 480a0a23564SMichal Meloun if (win->flip_x) 481a0a23564SMichal Meloun val |= H_DIRECTION; 482a0a23564SMichal Meloun if (win->transpose_xy) 483a0a23564SMichal Meloun val |= SCAN_COLUMN; 484a0a23564SMichal Meloun WR4(sc, DC_WINC_WIN_OPTIONS, val); 485a0a23564SMichal Meloun 486a0a23564SMichal Meloun #ifdef DMR_DEBUG_WINDOW 487a0a23564SMichal Meloun /* Set underflow debug mode -> highlight missing pixels. */ 488a0a23564SMichal Meloun WR4(sc, DC_WINBUF_UFLOW_CTRL, UFLOW_CTR_ENABLE); 489a0a23564SMichal Meloun WR4(sc, DC_WINBUF_UFLOW_DBG_PIXEL, 0xFFFF0000); 490a0a23564SMichal Meloun #endif 491a0a23564SMichal Meloun 492a0a23564SMichal Meloun UNLOCK(sc); 493a0a23564SMichal Meloun } 494a0a23564SMichal Meloun 495a0a23564SMichal Meloun /* ------------------------------------------------------------------- 496a0a23564SMichal Meloun * 497a0a23564SMichal Meloun * Plane functions. 498a0a23564SMichal Meloun * 499a0a23564SMichal Meloun */ 500a0a23564SMichal Meloun static int 501a0a23564SMichal Meloun dc_plane_update(struct drm_plane *drm_plane, struct drm_crtc *drm_crtc, 502a0a23564SMichal Meloun struct drm_framebuffer *drm_fb, 503a0a23564SMichal Meloun int crtc_x, int crtc_y, unsigned int crtc_w, unsigned int crtc_h, 504a0a23564SMichal Meloun uint32_t src_x, uint32_t src_y, uint32_t src_w, uint32_t src_h) 505a0a23564SMichal Meloun { 506a0a23564SMichal Meloun struct tegra_plane *plane; 507a0a23564SMichal Meloun struct tegra_crtc *crtc; 508a0a23564SMichal Meloun struct tegra_fb *fb; 509a0a23564SMichal Meloun struct dc_softc *sc; 510a0a23564SMichal Meloun struct dc_window win; 511a0a23564SMichal Meloun int rv; 512a0a23564SMichal Meloun 513a0a23564SMichal Meloun plane = container_of(drm_plane, struct tegra_plane, drm_plane); 514a0a23564SMichal Meloun fb = container_of(drm_fb, struct tegra_fb, drm_fb); 515a0a23564SMichal Meloun crtc = container_of(drm_crtc, struct tegra_crtc, drm_crtc); 516a0a23564SMichal Meloun sc = device_get_softc(crtc->dev); 517a0a23564SMichal Meloun 518a0a23564SMichal Meloun memset(&win, 0, sizeof(win)); 519a0a23564SMichal Meloun win.src_x = src_x >> 16; 520a0a23564SMichal Meloun win.src_y = src_y >> 16; 521a0a23564SMichal Meloun win.src_w = src_w >> 16; 522a0a23564SMichal Meloun win.src_h = src_h >> 16; 523a0a23564SMichal Meloun win.dst_x = crtc_x; 524a0a23564SMichal Meloun win.dst_y = crtc_y; 525a0a23564SMichal Meloun win.dst_w = crtc_w; 526a0a23564SMichal Meloun win.dst_h = crtc_h; 527a0a23564SMichal Meloun 528a0a23564SMichal Meloun rv = dc_parse_drm_format(fb, &win); 529a0a23564SMichal Meloun if (rv != 0) { 530a0a23564SMichal Meloun DRM_WARNING("unsupported pixel format %d\n", 531a0a23564SMichal Meloun fb->drm_fb.pixel_format); 532a0a23564SMichal Meloun return (rv); 533a0a23564SMichal Meloun } 534a0a23564SMichal Meloun 535a0a23564SMichal Meloun dc_setup_window(sc, plane->index, &win); 536a0a23564SMichal Meloun 537a0a23564SMichal Meloun WR4(sc, DC_CMD_STATE_CONTROL, WIN_A_UPDATE << plane->index); 538a0a23564SMichal Meloun WR4(sc, DC_CMD_STATE_CONTROL, WIN_A_ACT_REQ << plane->index); 539a0a23564SMichal Meloun 540a0a23564SMichal Meloun return (0); 541a0a23564SMichal Meloun } 542a0a23564SMichal Meloun 543a0a23564SMichal Meloun static int 544a0a23564SMichal Meloun dc_plane_disable(struct drm_plane *drm_plane) 545a0a23564SMichal Meloun { 546a0a23564SMichal Meloun struct tegra_plane *plane; 547a0a23564SMichal Meloun struct tegra_crtc *crtc; 548a0a23564SMichal Meloun struct dc_softc *sc; 549a0a23564SMichal Meloun uint32_t val, idx; 550a0a23564SMichal Meloun 551a0a23564SMichal Meloun if (drm_plane->crtc == NULL) 552a0a23564SMichal Meloun return (0); 553a0a23564SMichal Meloun plane = container_of(drm_plane, struct tegra_plane, drm_plane); 554a0a23564SMichal Meloun crtc = container_of(drm_plane->crtc, struct tegra_crtc, drm_crtc); 555a0a23564SMichal Meloun 556a0a23564SMichal Meloun sc = device_get_softc(crtc->dev); 557a0a23564SMichal Meloun idx = plane->index; 558a0a23564SMichal Meloun 559a0a23564SMichal Meloun LOCK(sc); 560a0a23564SMichal Meloun 561a0a23564SMichal Meloun WR4(sc, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT << idx); 562a0a23564SMichal Meloun 563a0a23564SMichal Meloun val = RD4(sc, DC_WINC_WIN_OPTIONS); 564a0a23564SMichal Meloun val &= ~WIN_ENABLE; 565a0a23564SMichal Meloun WR4(sc, DC_WINC_WIN_OPTIONS, val); 566a0a23564SMichal Meloun 567a0a23564SMichal Meloun UNLOCK(sc); 568a0a23564SMichal Meloun 569a0a23564SMichal Meloun WR4(sc, DC_CMD_STATE_CONTROL, WIN_A_UPDATE << idx); 570a0a23564SMichal Meloun WR4(sc, DC_CMD_STATE_CONTROL, WIN_A_ACT_REQ << idx); 571a0a23564SMichal Meloun 572a0a23564SMichal Meloun return (0); 573a0a23564SMichal Meloun } 574a0a23564SMichal Meloun 575a0a23564SMichal Meloun static void 576a0a23564SMichal Meloun dc_plane_destroy(struct drm_plane *plane) 577a0a23564SMichal Meloun { 578a0a23564SMichal Meloun 579a0a23564SMichal Meloun dc_plane_disable(plane); 580a0a23564SMichal Meloun drm_plane_cleanup(plane); 581a0a23564SMichal Meloun free(plane, DRM_MEM_KMS); 582a0a23564SMichal Meloun } 583a0a23564SMichal Meloun 584a0a23564SMichal Meloun static const struct drm_plane_funcs dc_plane_funcs = { 585a0a23564SMichal Meloun .update_plane = dc_plane_update, 586a0a23564SMichal Meloun .disable_plane = dc_plane_disable, 587a0a23564SMichal Meloun .destroy = dc_plane_destroy, 588a0a23564SMichal Meloun }; 589a0a23564SMichal Meloun 590a0a23564SMichal Meloun /* ------------------------------------------------------------------- 591a0a23564SMichal Meloun * 592a0a23564SMichal Meloun * CRTC helper functions. 593a0a23564SMichal Meloun * 594a0a23564SMichal Meloun */ 595a0a23564SMichal Meloun static void 596a0a23564SMichal Meloun dc_crtc_dpms(struct drm_crtc *crtc, int mode) 597a0a23564SMichal Meloun { 598a0a23564SMichal Meloun /* Empty function */ 599a0a23564SMichal Meloun } 600a0a23564SMichal Meloun 601a0a23564SMichal Meloun static bool 602a0a23564SMichal Meloun dc_crtc_mode_fixup(struct drm_crtc *crtc, const struct drm_display_mode *mode, 603a0a23564SMichal Meloun struct drm_display_mode *adjusted) 604a0a23564SMichal Meloun { 605a0a23564SMichal Meloun 606a0a23564SMichal Meloun return (true); 607a0a23564SMichal Meloun } 608a0a23564SMichal Meloun 609a0a23564SMichal Meloun static int 610a0a23564SMichal Meloun dc_set_base(struct dc_softc *sc, int x, int y, struct tegra_fb *fb) 611a0a23564SMichal Meloun { 612a0a23564SMichal Meloun struct dc_window win; 613a0a23564SMichal Meloun int rv; 614a0a23564SMichal Meloun 615a0a23564SMichal Meloun memset(&win, 0, sizeof(win)); 616a0a23564SMichal Meloun win.src_x = x; 617a0a23564SMichal Meloun win.src_y = y; 618a0a23564SMichal Meloun win.src_w = fb->drm_fb.width; 619a0a23564SMichal Meloun win.src_h = fb->drm_fb.height; 620a0a23564SMichal Meloun win.dst_x = x; 621a0a23564SMichal Meloun win.dst_y = y; 622a0a23564SMichal Meloun win.dst_w = fb->drm_fb.width; 623a0a23564SMichal Meloun win.dst_h = fb->drm_fb.height; 624a0a23564SMichal Meloun 625a0a23564SMichal Meloun rv = dc_parse_drm_format(fb, &win); 626a0a23564SMichal Meloun if (rv != 0) { 627a0a23564SMichal Meloun DRM_WARNING("unsupported pixel format %d\n", 628a0a23564SMichal Meloun fb->drm_fb.pixel_format); 629a0a23564SMichal Meloun return (rv); 630a0a23564SMichal Meloun } 631a0a23564SMichal Meloun dc_setup_window(sc, 0, &win); 632a0a23564SMichal Meloun 633a0a23564SMichal Meloun return (0); 634a0a23564SMichal Meloun } 635a0a23564SMichal Meloun 636a0a23564SMichal Meloun static int 637a0a23564SMichal Meloun dc_crtc_mode_set(struct drm_crtc *drm_crtc, struct drm_display_mode *mode, 638a0a23564SMichal Meloun struct drm_display_mode *adjusted, int x, int y, 639a0a23564SMichal Meloun struct drm_framebuffer *old_fb) 640a0a23564SMichal Meloun { 641a0a23564SMichal Meloun struct dc_softc *sc; 642a0a23564SMichal Meloun struct tegra_crtc *crtc; 643a0a23564SMichal Meloun struct tegra_fb *fb; 644a0a23564SMichal Meloun struct dc_window win; 645a0a23564SMichal Meloun uint32_t div, h_ref_to_sync, v_ref_to_sync; 646a0a23564SMichal Meloun int rv; 647a0a23564SMichal Meloun 648a0a23564SMichal Meloun crtc = container_of(drm_crtc, struct tegra_crtc, drm_crtc); 649a0a23564SMichal Meloun sc = device_get_softc(crtc->dev); 650a0a23564SMichal Meloun fb = container_of(drm_crtc->fb, struct tegra_fb, drm_fb); 651a0a23564SMichal Meloun 652a0a23564SMichal Meloun h_ref_to_sync = 1; 653a0a23564SMichal Meloun v_ref_to_sync = 1; 654a0a23564SMichal Meloun /* Setup timing */ 655a0a23564SMichal Meloun rv = dc_setup_clk(sc, drm_crtc, mode, &div); 656a0a23564SMichal Meloun if (rv != 0) { 657a0a23564SMichal Meloun device_printf(sc->dev, "Cannot set pixel clock\n"); 658a0a23564SMichal Meloun return (rv); 659a0a23564SMichal Meloun } 660a0a23564SMichal Meloun 661a0a23564SMichal Meloun /* Timing */ 662a0a23564SMichal Meloun WR4(sc, DC_DISP_DISP_TIMING_OPTIONS, 0); 663a0a23564SMichal Meloun 664a0a23564SMichal Meloun WR4(sc, DC_DISP_REF_TO_SYNC, 665a0a23564SMichal Meloun (v_ref_to_sync << 16) | 666a0a23564SMichal Meloun h_ref_to_sync); 667a0a23564SMichal Meloun 668a0a23564SMichal Meloun WR4(sc, DC_DISP_SYNC_WIDTH, 669a0a23564SMichal Meloun ((mode->vsync_end - mode->vsync_start) << 16) | 670a0a23564SMichal Meloun ((mode->hsync_end - mode->hsync_start) << 0)); 671a0a23564SMichal Meloun 672a0a23564SMichal Meloun WR4(sc, DC_DISP_BACK_PORCH, 673a0a23564SMichal Meloun ((mode->vtotal - mode->vsync_end) << 16) | 674a0a23564SMichal Meloun ((mode->htotal - mode->hsync_end) << 0)); 675a0a23564SMichal Meloun 676a0a23564SMichal Meloun WR4(sc, DC_DISP_FRONT_PORCH, 677a0a23564SMichal Meloun ((mode->vsync_start - mode->vdisplay) << 16) | 678a0a23564SMichal Meloun ((mode->hsync_start - mode->hdisplay) << 0)); 679a0a23564SMichal Meloun 680a0a23564SMichal Meloun WR4(sc, DC_DISP_DISP_ACTIVE, 681a0a23564SMichal Meloun (mode->vdisplay << 16) | mode->hdisplay); 682a0a23564SMichal Meloun 683a0a23564SMichal Meloun WR4(sc, DC_DISP_DISP_INTERFACE_CONTROL, DISP_DATA_FORMAT(DF1P1C)); 684a0a23564SMichal Meloun 685a0a23564SMichal Meloun WR4(sc,DC_DISP_DISP_CLOCK_CONTROL, 686a0a23564SMichal Meloun SHIFT_CLK_DIVIDER(div) | PIXEL_CLK_DIVIDER(PCD1)); 687a0a23564SMichal Meloun 688a0a23564SMichal Meloun memset(&win, 0, sizeof(win)); 689a0a23564SMichal Meloun win.src_x = x; 690a0a23564SMichal Meloun win.src_y = y; 691a0a23564SMichal Meloun win.src_w = mode->hdisplay; 692a0a23564SMichal Meloun win.src_h = mode->vdisplay; 693a0a23564SMichal Meloun win.dst_x = x; 694a0a23564SMichal Meloun win.dst_y = y; 695a0a23564SMichal Meloun win.dst_w = mode->hdisplay; 696a0a23564SMichal Meloun win.dst_h = mode->vdisplay; 697a0a23564SMichal Meloun 698a0a23564SMichal Meloun rv = dc_parse_drm_format(fb, &win); 699a0a23564SMichal Meloun if (rv != 0) { 700a0a23564SMichal Meloun DRM_WARNING("unsupported pixel format %d\n", 701a0a23564SMichal Meloun drm_crtc->fb->pixel_format); 702a0a23564SMichal Meloun return (rv); 703a0a23564SMichal Meloun } 704a0a23564SMichal Meloun 705a0a23564SMichal Meloun dc_setup_window(sc, 0, &win); 706a0a23564SMichal Meloun 707a0a23564SMichal Meloun return (0); 708a0a23564SMichal Meloun 709a0a23564SMichal Meloun } 710a0a23564SMichal Meloun 711a0a23564SMichal Meloun static int 712a0a23564SMichal Meloun dc_crtc_mode_set_base(struct drm_crtc *drm_crtc, int x, int y, 713a0a23564SMichal Meloun struct drm_framebuffer *old_fb) 714a0a23564SMichal Meloun { 715a0a23564SMichal Meloun struct dc_softc *sc; 716a0a23564SMichal Meloun struct tegra_crtc *crtc; 717a0a23564SMichal Meloun struct tegra_fb *fb; 718a0a23564SMichal Meloun int rv; 719a0a23564SMichal Meloun 720a0a23564SMichal Meloun crtc = container_of(drm_crtc, struct tegra_crtc, drm_crtc); 721a0a23564SMichal Meloun fb = container_of(drm_crtc->fb, struct tegra_fb, drm_fb); 722a0a23564SMichal Meloun sc = device_get_softc(crtc->dev); 723a0a23564SMichal Meloun 724a0a23564SMichal Meloun rv = dc_set_base(sc, x, y, fb); 725a0a23564SMichal Meloun 726a0a23564SMichal Meloun /* Commit */ 727a0a23564SMichal Meloun WR4(sc, DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE); 728a0a23564SMichal Meloun WR4(sc, DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ); 729a0a23564SMichal Meloun return (rv); 730a0a23564SMichal Meloun } 731a0a23564SMichal Meloun 732a0a23564SMichal Meloun static void 733a0a23564SMichal Meloun dc_crtc_prepare(struct drm_crtc *drm_crtc) 734a0a23564SMichal Meloun { 735a0a23564SMichal Meloun 736a0a23564SMichal Meloun struct dc_softc *sc; 737a0a23564SMichal Meloun struct tegra_crtc *crtc; 738a0a23564SMichal Meloun uint32_t val; 739a0a23564SMichal Meloun 740a0a23564SMichal Meloun crtc = container_of(drm_crtc, struct tegra_crtc, drm_crtc); 741a0a23564SMichal Meloun sc = device_get_softc(crtc->dev); 742a0a23564SMichal Meloun 743a0a23564SMichal Meloun WR4(sc, DC_CMD_GENERAL_INCR_SYNCPT_CNTRL, SYNCPT_CNTRL_NO_STALL); 744a0a23564SMichal Meloun /* XXX allocate syncpoint from host1x */ 745a0a23564SMichal Meloun WR4(sc, DC_CMD_CONT_SYNCPT_VSYNC, SYNCPT_VSYNC_ENABLE | 746a0a23564SMichal Meloun (sc->tegra_crtc.nvidia_head == 0 ? SYNCPT_VBLANK0: SYNCPT_VBLANK1)); 747a0a23564SMichal Meloun 748a0a23564SMichal Meloun WR4(sc, DC_CMD_DISPLAY_POWER_CONTROL, 749a0a23564SMichal Meloun PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE | 750a0a23564SMichal Meloun PW4_ENABLE | PM0_ENABLE | PM1_ENABLE); 751a0a23564SMichal Meloun 752a0a23564SMichal Meloun val = RD4(sc, DC_CMD_DISPLAY_COMMAND); 753a0a23564SMichal Meloun val |= DISPLAY_CTRL_MODE(CTRL_MODE_C_DISPLAY); 754a0a23564SMichal Meloun WR4(sc, DC_CMD_DISPLAY_COMMAND, val); 755a0a23564SMichal Meloun 756a0a23564SMichal Meloun WR4(sc, DC_CMD_INT_MASK, 757a0a23564SMichal Meloun WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT | 758a0a23564SMichal Meloun WIN_A_OF_INT | WIN_B_OF_INT | WIN_C_OF_INT); 759a0a23564SMichal Meloun 760a0a23564SMichal Meloun WR4(sc, DC_CMD_INT_ENABLE, 761a0a23564SMichal Meloun VBLANK_INT | WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT | 762a0a23564SMichal Meloun WIN_A_OF_INT | WIN_B_OF_INT | WIN_C_OF_INT); 763a0a23564SMichal Meloun } 764a0a23564SMichal Meloun 765a0a23564SMichal Meloun static void 766a0a23564SMichal Meloun dc_crtc_commit(struct drm_crtc *drm_crtc) 767a0a23564SMichal Meloun { 768a0a23564SMichal Meloun struct dc_softc *sc; 769a0a23564SMichal Meloun struct tegra_crtc *crtc; 770a0a23564SMichal Meloun uint32_t val; 771a0a23564SMichal Meloun 772a0a23564SMichal Meloun crtc = container_of(drm_crtc, struct tegra_crtc, drm_crtc); 773a0a23564SMichal Meloun sc = device_get_softc(crtc->dev); 774a0a23564SMichal Meloun 775a0a23564SMichal Meloun WR4(sc, DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE); 776a0a23564SMichal Meloun 777a0a23564SMichal Meloun val = RD4(sc, DC_CMD_INT_MASK); 778a0a23564SMichal Meloun val |= FRAME_END_INT; 779a0a23564SMichal Meloun WR4(sc, DC_CMD_INT_MASK, val); 780a0a23564SMichal Meloun 781a0a23564SMichal Meloun val = RD4(sc, DC_CMD_INT_ENABLE); 782a0a23564SMichal Meloun val |= FRAME_END_INT; 783a0a23564SMichal Meloun WR4(sc, DC_CMD_INT_ENABLE, val); 784a0a23564SMichal Meloun 785a0a23564SMichal Meloun WR4(sc, DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | WIN_A_ACT_REQ); 786a0a23564SMichal Meloun } 787a0a23564SMichal Meloun 788a0a23564SMichal Meloun static void 789a0a23564SMichal Meloun dc_crtc_load_lut(struct drm_crtc *crtc) 790a0a23564SMichal Meloun { 791a0a23564SMichal Meloun 792a0a23564SMichal Meloun /* empty function */ 793a0a23564SMichal Meloun } 794a0a23564SMichal Meloun 795a0a23564SMichal Meloun static const struct drm_crtc_helper_funcs dc_crtc_helper_funcs = { 796a0a23564SMichal Meloun .dpms = dc_crtc_dpms, 797a0a23564SMichal Meloun .mode_fixup = dc_crtc_mode_fixup, 798a0a23564SMichal Meloun .mode_set = dc_crtc_mode_set, 799a0a23564SMichal Meloun .mode_set_base = dc_crtc_mode_set_base, 800a0a23564SMichal Meloun .prepare = dc_crtc_prepare, 801a0a23564SMichal Meloun .commit = dc_crtc_commit, 802a0a23564SMichal Meloun .load_lut = dc_crtc_load_lut, 803a0a23564SMichal Meloun }; 804a0a23564SMichal Meloun 805a0a23564SMichal Meloun static int 806a0a23564SMichal Meloun drm_crtc_index(struct drm_crtc *crtc) 807a0a23564SMichal Meloun { 808a0a23564SMichal Meloun int idx; 809a0a23564SMichal Meloun struct drm_crtc *tmp; 810a0a23564SMichal Meloun 811a0a23564SMichal Meloun idx = 0; 812a0a23564SMichal Meloun list_for_each_entry(tmp, &crtc->dev->mode_config.crtc_list, head) { 813a0a23564SMichal Meloun if (tmp == crtc) 814a0a23564SMichal Meloun return (idx); 815a0a23564SMichal Meloun idx++; 816a0a23564SMichal Meloun } 817a0a23564SMichal Meloun panic("Cannot find CRTC"); 818a0a23564SMichal Meloun } 819a0a23564SMichal Meloun 820a0a23564SMichal Meloun /* ------------------------------------------------------------------- 821a0a23564SMichal Meloun * 822a0a23564SMichal Meloun * Exported functions (mainly vsync related). 823a0a23564SMichal Meloun * 824a0a23564SMichal Meloun * XXX revisit this -> convert to bus methods? 825a0a23564SMichal Meloun */ 826a0a23564SMichal Meloun int 827a0a23564SMichal Meloun tegra_dc_get_pipe(struct drm_crtc *drm_crtc) 828a0a23564SMichal Meloun { 829a0a23564SMichal Meloun struct tegra_crtc *crtc; 830a0a23564SMichal Meloun 831a0a23564SMichal Meloun crtc = container_of(drm_crtc, struct tegra_crtc, drm_crtc); 832a0a23564SMichal Meloun return (crtc->nvidia_head); 833a0a23564SMichal Meloun } 834a0a23564SMichal Meloun 835a0a23564SMichal Meloun void 836a0a23564SMichal Meloun tegra_dc_enable_vblank(struct drm_crtc *drm_crtc) 837a0a23564SMichal Meloun { 838a0a23564SMichal Meloun struct dc_softc *sc; 839a0a23564SMichal Meloun struct tegra_crtc *crtc; 840a0a23564SMichal Meloun uint32_t val; 841a0a23564SMichal Meloun 842a0a23564SMichal Meloun crtc = container_of(drm_crtc, struct tegra_crtc, drm_crtc); 843a0a23564SMichal Meloun sc = device_get_softc(crtc->dev); 844a0a23564SMichal Meloun 845a0a23564SMichal Meloun LOCK(sc); 846a0a23564SMichal Meloun val = RD4(sc, DC_CMD_INT_MASK); 847a0a23564SMichal Meloun val |= VBLANK_INT; 848a0a23564SMichal Meloun WR4(sc, DC_CMD_INT_MASK, val); 849a0a23564SMichal Meloun UNLOCK(sc); 850a0a23564SMichal Meloun } 851a0a23564SMichal Meloun 852a0a23564SMichal Meloun void 853a0a23564SMichal Meloun tegra_dc_disable_vblank(struct drm_crtc *drm_crtc) 854a0a23564SMichal Meloun { 855a0a23564SMichal Meloun struct dc_softc *sc; 856a0a23564SMichal Meloun struct tegra_crtc *crtc; 857a0a23564SMichal Meloun uint32_t val; 858a0a23564SMichal Meloun 859a0a23564SMichal Meloun crtc = container_of(drm_crtc, struct tegra_crtc, drm_crtc); 860a0a23564SMichal Meloun sc = device_get_softc(crtc->dev); 861a0a23564SMichal Meloun 862a0a23564SMichal Meloun LOCK(sc); 863a0a23564SMichal Meloun val = RD4(sc, DC_CMD_INT_MASK); 864a0a23564SMichal Meloun val &= ~VBLANK_INT; 865a0a23564SMichal Meloun WR4(sc, DC_CMD_INT_MASK, val); 866a0a23564SMichal Meloun UNLOCK(sc); 867a0a23564SMichal Meloun } 868a0a23564SMichal Meloun 869a0a23564SMichal Meloun static void 870a0a23564SMichal Meloun dc_finish_page_flip(struct dc_softc *sc) 871a0a23564SMichal Meloun { 872a0a23564SMichal Meloun struct drm_crtc *drm_crtc; 873a0a23564SMichal Meloun struct drm_device *drm; 874a0a23564SMichal Meloun struct tegra_fb *fb; 875a0a23564SMichal Meloun struct tegra_bo *bo; 876a0a23564SMichal Meloun uint32_t base; 877a0a23564SMichal Meloun int idx; 878a0a23564SMichal Meloun 879a0a23564SMichal Meloun drm_crtc = &sc->tegra_crtc.drm_crtc; 880a0a23564SMichal Meloun drm = drm_crtc->dev; 881a0a23564SMichal Meloun fb = container_of(drm_crtc->fb, struct tegra_fb, drm_fb); 882a0a23564SMichal Meloun 883a0a23564SMichal Meloun mtx_lock(&drm->event_lock); 884a0a23564SMichal Meloun 885a0a23564SMichal Meloun if (sc->event == NULL) { 886a0a23564SMichal Meloun mtx_unlock(&drm->event_lock); 887a0a23564SMichal Meloun return; 888a0a23564SMichal Meloun } 889a0a23564SMichal Meloun 890a0a23564SMichal Meloun LOCK(sc); 891a0a23564SMichal Meloun /* Read active copy of WINBUF_START_ADDR */ 892a0a23564SMichal Meloun WR4(sc, DC_CMD_DISPLAY_WINDOW_HEADER, WINDOW_A_SELECT); 893a0a23564SMichal Meloun WR4(sc, DC_CMD_STATE_ACCESS, READ_MUX); 894a0a23564SMichal Meloun base = RD4(sc, DC_WINBUF_START_ADDR); 895a0a23564SMichal Meloun WR4(sc, DC_CMD_STATE_ACCESS, 0); 896a0a23564SMichal Meloun UNLOCK(sc); 897a0a23564SMichal Meloun 898a0a23564SMichal Meloun /* Is already active */ 899a0a23564SMichal Meloun bo = tegra_fb_get_plane(fb, 0); 900a0a23564SMichal Meloun if (base == (bo->pbase + fb->drm_fb.offsets[0])) { 901a0a23564SMichal Meloun idx = drm_crtc_index(drm_crtc); 902a0a23564SMichal Meloun drm_send_vblank_event(drm, idx, sc->event); 903a0a23564SMichal Meloun drm_vblank_put(drm, idx); 904a0a23564SMichal Meloun sc->event = NULL; 905a0a23564SMichal Meloun } 906a0a23564SMichal Meloun 907a0a23564SMichal Meloun mtx_unlock(&drm->event_lock); 908a0a23564SMichal Meloun } 909a0a23564SMichal Meloun 910a0a23564SMichal Meloun void 911a0a23564SMichal Meloun tegra_dc_cancel_page_flip(struct drm_crtc *drm_crtc, struct drm_file *file) 912a0a23564SMichal Meloun { 913a0a23564SMichal Meloun struct dc_softc *sc; 914a0a23564SMichal Meloun struct tegra_crtc *crtc; 915a0a23564SMichal Meloun struct drm_device *drm; 916a0a23564SMichal Meloun 917a0a23564SMichal Meloun crtc = container_of(drm_crtc, struct tegra_crtc, drm_crtc); 918a0a23564SMichal Meloun sc = device_get_softc(crtc->dev); 919a0a23564SMichal Meloun drm = drm_crtc->dev; 920a0a23564SMichal Meloun mtx_lock(&drm->event_lock); 921a0a23564SMichal Meloun 922a0a23564SMichal Meloun if ((sc->event != NULL) && (sc->event->base.file_priv == file)) { 923a0a23564SMichal Meloun sc->event->base.destroy(&sc->event->base); 924a0a23564SMichal Meloun drm_vblank_put(drm, drm_crtc_index(drm_crtc)); 925a0a23564SMichal Meloun sc->event = NULL; 926a0a23564SMichal Meloun } 927a0a23564SMichal Meloun mtx_unlock(&drm->event_lock); 928a0a23564SMichal Meloun } 929a0a23564SMichal Meloun 930a0a23564SMichal Meloun /* ------------------------------------------------------------------- 931a0a23564SMichal Meloun * 932a0a23564SMichal Meloun * CRTC functions. 933a0a23564SMichal Meloun * 934a0a23564SMichal Meloun */ 935a0a23564SMichal Meloun static int 936a0a23564SMichal Meloun dc_page_flip(struct drm_crtc *drm_crtc, struct drm_framebuffer *drm_fb, 937a0a23564SMichal Meloun struct drm_pending_vblank_event *event) 938a0a23564SMichal Meloun { 939a0a23564SMichal Meloun struct dc_softc *sc; 940a0a23564SMichal Meloun struct tegra_crtc *crtc; 941a0a23564SMichal Meloun struct tegra_fb *fb; 942a0a23564SMichal Meloun struct drm_device *drm; 943a0a23564SMichal Meloun 944a0a23564SMichal Meloun crtc = container_of(drm_crtc, struct tegra_crtc, drm_crtc); 945a0a23564SMichal Meloun sc = device_get_softc(crtc->dev); 946a0a23564SMichal Meloun fb = container_of(drm_crtc->fb, struct tegra_fb, drm_fb); 947a0a23564SMichal Meloun drm = drm_crtc->dev; 948a0a23564SMichal Meloun 949a0a23564SMichal Meloun if (sc->event != NULL) 950a0a23564SMichal Meloun return (-EBUSY); 951a0a23564SMichal Meloun 952a0a23564SMichal Meloun if (event != NULL) { 953a0a23564SMichal Meloun event->pipe = sc->tegra_crtc.nvidia_head; 954a0a23564SMichal Meloun sc->event = event; 955a0a23564SMichal Meloun drm_vblank_get(drm, event->pipe); 956a0a23564SMichal Meloun } 957a0a23564SMichal Meloun 958a0a23564SMichal Meloun dc_set_base(sc, drm_crtc->x, drm_crtc->y, fb); 959a0a23564SMichal Meloun drm_crtc->fb = drm_fb; 960a0a23564SMichal Meloun 961a0a23564SMichal Meloun /* Commit */ 962a0a23564SMichal Meloun WR4(sc, DC_CMD_STATE_CONTROL, GENERAL_UPDATE | WIN_A_UPDATE); 963a0a23564SMichal Meloun 964a0a23564SMichal Meloun return (0); 965a0a23564SMichal Meloun } 966a0a23564SMichal Meloun 967a0a23564SMichal Meloun static int 968a0a23564SMichal Meloun dc_cursor_set(struct drm_crtc *drm_crtc, struct drm_file *file, 969a0a23564SMichal Meloun uint32_t handle, uint32_t width, uint32_t height) 970a0a23564SMichal Meloun { 971a0a23564SMichal Meloun 972a0a23564SMichal Meloun struct dc_softc *sc; 973a0a23564SMichal Meloun struct tegra_crtc *crtc; 974a0a23564SMichal Meloun struct drm_gem_object *gem; 975a0a23564SMichal Meloun struct tegra_bo *bo; 976a0a23564SMichal Meloun int i; 977a0a23564SMichal Meloun uint32_t val, *src, *dst; 978a0a23564SMichal Meloun 979a0a23564SMichal Meloun crtc = container_of(drm_crtc, struct tegra_crtc, drm_crtc); 980a0a23564SMichal Meloun sc = device_get_softc(crtc->dev); 981a0a23564SMichal Meloun 982a0a23564SMichal Meloun if (width != height) 983a0a23564SMichal Meloun return (-EINVAL); 984a0a23564SMichal Meloun 985a0a23564SMichal Meloun switch (width) { 986a0a23564SMichal Meloun case 32: 987a0a23564SMichal Meloun val = CURSOR_SIZE(C32x32); 988a0a23564SMichal Meloun break; 989a0a23564SMichal Meloun case 64: 990a0a23564SMichal Meloun val = CURSOR_SIZE(C64x64); 991a0a23564SMichal Meloun break; 992a0a23564SMichal Meloun case 128: 993a0a23564SMichal Meloun val = CURSOR_SIZE(C128x128); 994a0a23564SMichal Meloun break; 995a0a23564SMichal Meloun case 256: 996a0a23564SMichal Meloun val = CURSOR_SIZE(C256x256); 997a0a23564SMichal Meloun break; 998a0a23564SMichal Meloun default: 999a0a23564SMichal Meloun return (-EINVAL); 1000a0a23564SMichal Meloun } 1001a0a23564SMichal Meloun 1002a0a23564SMichal Meloun bo = NULL; 1003a0a23564SMichal Meloun gem = NULL; 1004a0a23564SMichal Meloun if (handle != 0) { 1005a0a23564SMichal Meloun gem = drm_gem_object_lookup(drm_crtc->dev, file, handle); 1006a0a23564SMichal Meloun if (gem == NULL) 1007a0a23564SMichal Meloun return (-ENOENT); 1008a0a23564SMichal Meloun bo = container_of(gem, struct tegra_bo, gem_obj); 1009a0a23564SMichal Meloun } 1010a0a23564SMichal Meloun 1011a0a23564SMichal Meloun if (sc->cursor_gem != NULL) { 1012a0a23564SMichal Meloun drm_gem_object_unreference(sc->cursor_gem); 1013a0a23564SMichal Meloun } 1014a0a23564SMichal Meloun sc->cursor_gem = gem; 1015a0a23564SMichal Meloun 1016a0a23564SMichal Meloun if (bo != NULL) { 1017a0a23564SMichal Meloun /* 1018a0a23564SMichal Meloun * Copy cursor into cache and convert it from ARGB to RGBA. 1019a0a23564SMichal Meloun * XXXX - this is broken by design - client can write to BO at 1020a0a23564SMichal Meloun * any time. We can dedicate other window for cursor or switch 1021a0a23564SMichal Meloun * to sw cursor in worst case. 1022a0a23564SMichal Meloun */ 1023a0a23564SMichal Meloun src = (uint32_t *)bo->vbase; 1024a0a23564SMichal Meloun dst = (uint32_t *)crtc->cursor_vbase; 1025a0a23564SMichal Meloun for (i = 0; i < width * height; i++) 1026a0a23564SMichal Meloun dst[i] = (src[i] << 8) | (src[i] >> 24); 1027a0a23564SMichal Meloun 1028a0a23564SMichal Meloun val |= CURSOR_CLIP(CC_DISPLAY); 1029a0a23564SMichal Meloun val |= CURSOR_START_ADDR(crtc->cursor_pbase); 1030a0a23564SMichal Meloun WR4(sc, DC_DISP_CURSOR_START_ADDR, val); 1031a0a23564SMichal Meloun 1032a0a23564SMichal Meloun val = RD4(sc, DC_DISP_BLEND_CURSOR_CONTROL); 1033a0a23564SMichal Meloun val &= ~CURSOR_DST_BLEND_FACTOR_SELECT(~0); 1034a0a23564SMichal Meloun val &= ~CURSOR_SRC_BLEND_FACTOR_SELECT(~0); 1035a0a23564SMichal Meloun val |= CURSOR_MODE_SELECT; 1036a0a23564SMichal Meloun val |= CURSOR_DST_BLEND_FACTOR_SELECT(DST_NEG_K1_TIMES_SRC); 1037a0a23564SMichal Meloun val |= CURSOR_SRC_BLEND_FACTOR_SELECT(SRC_BLEND_K1_TIMES_SRC); 1038a0a23564SMichal Meloun val |= CURSOR_ALPHA(~0); 1039a0a23564SMichal Meloun WR4(sc, DC_DISP_BLEND_CURSOR_CONTROL, val); 1040a0a23564SMichal Meloun 1041a0a23564SMichal Meloun val = RD4(sc, DC_DISP_DISP_WIN_OPTIONS); 1042a0a23564SMichal Meloun val |= CURSOR_ENABLE; 1043a0a23564SMichal Meloun WR4(sc, DC_DISP_DISP_WIN_OPTIONS, val); 1044a0a23564SMichal Meloun } else { 1045a0a23564SMichal Meloun val = RD4(sc, DC_DISP_DISP_WIN_OPTIONS); 1046a0a23564SMichal Meloun val &= ~CURSOR_ENABLE; 1047a0a23564SMichal Meloun WR4(sc, DC_DISP_DISP_WIN_OPTIONS, val); 1048a0a23564SMichal Meloun } 1049a0a23564SMichal Meloun 1050a0a23564SMichal Meloun /* XXX This fixes cursor underflow issues, but why ? */ 1051a0a23564SMichal Meloun WR4(sc, DC_DISP_CURSOR_UNDERFLOW_CTRL, CURSOR_UFLOW_CYA); 1052a0a23564SMichal Meloun 1053a0a23564SMichal Meloun WR4(sc, DC_CMD_STATE_CONTROL, GENERAL_UPDATE | CURSOR_UPDATE ); 1054a0a23564SMichal Meloun WR4(sc, DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ | CURSOR_ACT_REQ); 1055a0a23564SMichal Meloun return (0); 1056a0a23564SMichal Meloun } 1057a0a23564SMichal Meloun 1058a0a23564SMichal Meloun static int 1059a0a23564SMichal Meloun dc_cursor_move(struct drm_crtc *drm_crtc, int x, int y) 1060a0a23564SMichal Meloun { 1061a0a23564SMichal Meloun struct dc_softc *sc; 1062a0a23564SMichal Meloun struct tegra_crtc *crtc; 1063a0a23564SMichal Meloun 1064a0a23564SMichal Meloun crtc = container_of(drm_crtc, struct tegra_crtc, drm_crtc); 1065a0a23564SMichal Meloun sc = device_get_softc(crtc->dev); 1066a0a23564SMichal Meloun WR4(sc, DC_DISP_CURSOR_POSITION, CURSOR_POSITION(x, y)); 1067a0a23564SMichal Meloun 1068a0a23564SMichal Meloun WR4(sc, DC_CMD_STATE_CONTROL, CURSOR_UPDATE); 1069a0a23564SMichal Meloun WR4(sc, DC_CMD_STATE_CONTROL, CURSOR_ACT_REQ); 1070a0a23564SMichal Meloun 1071a0a23564SMichal Meloun return (0); 1072a0a23564SMichal Meloun } 1073a0a23564SMichal Meloun 1074a0a23564SMichal Meloun static void 1075a0a23564SMichal Meloun dc_destroy(struct drm_crtc *crtc) 1076a0a23564SMichal Meloun { 1077a0a23564SMichal Meloun 1078a0a23564SMichal Meloun drm_crtc_cleanup(crtc); 1079a0a23564SMichal Meloun memset(crtc, 0, sizeof(*crtc)); 1080a0a23564SMichal Meloun } 1081a0a23564SMichal Meloun 1082a0a23564SMichal Meloun static const struct drm_crtc_funcs dc_crtc_funcs = { 1083a0a23564SMichal Meloun .page_flip = dc_page_flip, 1084a0a23564SMichal Meloun .cursor_set = dc_cursor_set, 1085a0a23564SMichal Meloun .cursor_move = dc_cursor_move, 1086a0a23564SMichal Meloun .set_config = drm_crtc_helper_set_config, 1087a0a23564SMichal Meloun .destroy = dc_destroy, 1088a0a23564SMichal Meloun }; 1089a0a23564SMichal Meloun 1090a0a23564SMichal Meloun /* ------------------------------------------------------------------- 1091a0a23564SMichal Meloun * 1092a0a23564SMichal Meloun * Bus and infrastructure. 1093a0a23564SMichal Meloun * 1094a0a23564SMichal Meloun */ 1095a0a23564SMichal Meloun static int 1096a0a23564SMichal Meloun dc_init_planes(struct dc_softc *sc, struct tegra_drm *drm) 1097a0a23564SMichal Meloun { 1098a0a23564SMichal Meloun int i, rv; 1099a0a23564SMichal Meloun struct tegra_plane *plane; 1100a0a23564SMichal Meloun 1101a0a23564SMichal Meloun rv = 0; 1102a0a23564SMichal Meloun for (i = 0; i < DC_MAX_PLANES; i++) { 1103a0a23564SMichal Meloun plane = malloc(sizeof(*plane), DRM_MEM_KMS, M_WAITOK | M_ZERO); 1104a0a23564SMichal Meloun plane->index = i + 1; 1105a0a23564SMichal Meloun rv = drm_plane_init(&drm->drm_dev, &plane->drm_plane, 1106a0a23564SMichal Meloun 1 << sc->tegra_crtc.nvidia_head, &dc_plane_funcs, 1107a0a23564SMichal Meloun dc_plane_formats, nitems(dc_plane_formats), false); 1108a0a23564SMichal Meloun if (rv != 0) { 1109a0a23564SMichal Meloun free(plane, DRM_MEM_KMS); 1110a0a23564SMichal Meloun return (rv); 1111a0a23564SMichal Meloun } 1112a0a23564SMichal Meloun } 1113a0a23564SMichal Meloun return 0; 1114a0a23564SMichal Meloun } 1115a0a23564SMichal Meloun 1116a0a23564SMichal Meloun static void 1117a0a23564SMichal Meloun dc_display_enable(device_t dev, bool enable) 1118a0a23564SMichal Meloun { 1119a0a23564SMichal Meloun struct dc_softc *sc; 1120a0a23564SMichal Meloun uint32_t val; 1121a0a23564SMichal Meloun 1122a0a23564SMichal Meloun sc = device_get_softc(dev); 1123a0a23564SMichal Meloun 1124a0a23564SMichal Meloun /* Set display mode */ 1125a0a23564SMichal Meloun val = enable ? CTRL_MODE_C_DISPLAY: CTRL_MODE_STOP; 1126a0a23564SMichal Meloun WR4(sc, DC_CMD_DISPLAY_COMMAND, DISPLAY_CTRL_MODE(val)); 1127a0a23564SMichal Meloun 1128a0a23564SMichal Meloun /* and commit it*/ 1129a0a23564SMichal Meloun WR4(sc, DC_CMD_STATE_CONTROL, GENERAL_UPDATE); 1130a0a23564SMichal Meloun WR4(sc, DC_CMD_STATE_CONTROL, GENERAL_ACT_REQ); 1131a0a23564SMichal Meloun } 1132a0a23564SMichal Meloun 1133a0a23564SMichal Meloun static void 1134a0a23564SMichal Meloun dc_hdmi_enable(device_t dev, bool enable) 1135a0a23564SMichal Meloun { 1136a0a23564SMichal Meloun struct dc_softc *sc; 1137a0a23564SMichal Meloun uint32_t val; 1138a0a23564SMichal Meloun 1139a0a23564SMichal Meloun sc = device_get_softc(dev); 1140a0a23564SMichal Meloun 1141a0a23564SMichal Meloun val = RD4(sc, DC_DISP_DISP_WIN_OPTIONS); 1142a0a23564SMichal Meloun if (enable) 1143a0a23564SMichal Meloun val |= HDMI_ENABLE; 1144a0a23564SMichal Meloun else 1145a0a23564SMichal Meloun val &= ~HDMI_ENABLE; 1146a0a23564SMichal Meloun WR4(sc, DC_DISP_DISP_WIN_OPTIONS, val); 1147a0a23564SMichal Meloun 1148a0a23564SMichal Meloun } 1149a0a23564SMichal Meloun 1150a0a23564SMichal Meloun static void 1151a0a23564SMichal Meloun dc_setup_timing(device_t dev, int h_pulse_start) 1152a0a23564SMichal Meloun { 1153a0a23564SMichal Meloun struct dc_softc *sc; 1154a0a23564SMichal Meloun 1155a0a23564SMichal Meloun sc = device_get_softc(dev); 1156a0a23564SMichal Meloun 1157a0a23564SMichal Meloun /* Setup display timing */ 1158a0a23564SMichal Meloun WR4(sc, DC_DISP_DISP_TIMING_OPTIONS, VSYNC_H_POSITION(1)); 1159a0a23564SMichal Meloun WR4(sc, DC_DISP_DISP_COLOR_CONTROL, 1160a0a23564SMichal Meloun DITHER_CONTROL(DITHER_DISABLE) | BASE_COLOR_SIZE(SIZE_BASE888)); 1161a0a23564SMichal Meloun 1162a0a23564SMichal Meloun WR4(sc, DC_DISP_DISP_SIGNAL_OPTIONS0, H_PULSE2_ENABLE); 1163a0a23564SMichal Meloun WR4(sc, DC_DISP_H_PULSE2_CONTROL, 1164a0a23564SMichal Meloun PULSE_CONTROL_QUAL(QUAL_VACTIVE) | PULSE_CONTROL_LAST(LAST_END_A)); 1165a0a23564SMichal Meloun 1166a0a23564SMichal Meloun WR4(sc, DC_DISP_H_PULSE2_POSITION_A, 1167a0a23564SMichal Meloun PULSE_START(h_pulse_start) | PULSE_END(h_pulse_start + 8)); 1168a0a23564SMichal Meloun } 1169a0a23564SMichal Meloun 1170a0a23564SMichal Meloun static void 1171a0a23564SMichal Meloun dc_intr(void *arg) 1172a0a23564SMichal Meloun { 1173a0a23564SMichal Meloun struct dc_softc *sc; 1174a0a23564SMichal Meloun uint32_t status; 1175a0a23564SMichal Meloun 1176a0a23564SMichal Meloun sc = arg; 1177a0a23564SMichal Meloun 1178a0a23564SMichal Meloun /* Confirm interrupt */ 1179a0a23564SMichal Meloun status = RD4(sc, DC_CMD_INT_STATUS); 1180a0a23564SMichal Meloun WR4(sc, DC_CMD_INT_STATUS, status); 1181a0a23564SMichal Meloun if (status & VBLANK_INT) { 1182a0a23564SMichal Meloun drm_handle_vblank(sc->tegra_crtc.drm_crtc.dev, 1183a0a23564SMichal Meloun sc->tegra_crtc.nvidia_head); 1184a0a23564SMichal Meloun dc_finish_page_flip(sc); 1185a0a23564SMichal Meloun } 1186a0a23564SMichal Meloun } 1187a0a23564SMichal Meloun 1188a0a23564SMichal Meloun static int 1189a0a23564SMichal Meloun dc_init_client(device_t dev, device_t host1x, struct tegra_drm *drm) 1190a0a23564SMichal Meloun { 1191a0a23564SMichal Meloun struct dc_softc *sc; 1192a0a23564SMichal Meloun int rv; 1193a0a23564SMichal Meloun 1194a0a23564SMichal Meloun sc = device_get_softc(dev); 1195a0a23564SMichal Meloun 1196a0a23564SMichal Meloun if (drm->pitch_align < sc->pitch_align) 1197a0a23564SMichal Meloun drm->pitch_align = sc->pitch_align; 1198a0a23564SMichal Meloun 1199a0a23564SMichal Meloun drm_crtc_init(&drm->drm_dev, &sc->tegra_crtc.drm_crtc, &dc_crtc_funcs); 1200a0a23564SMichal Meloun drm_mode_crtc_set_gamma_size(&sc->tegra_crtc.drm_crtc, 256); 1201a0a23564SMichal Meloun drm_crtc_helper_add(&sc->tegra_crtc.drm_crtc, &dc_crtc_helper_funcs); 1202a0a23564SMichal Meloun 1203a0a23564SMichal Meloun rv = dc_init_planes(sc, drm); 1204a0a23564SMichal Meloun if (rv!= 0){ 1205a0a23564SMichal Meloun device_printf(dev, "Cannot init planes\n"); 1206a0a23564SMichal Meloun return (rv); 1207a0a23564SMichal Meloun } 1208a0a23564SMichal Meloun 1209a0a23564SMichal Meloun WR4(sc, DC_CMD_INT_TYPE, 1210a0a23564SMichal Meloun WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT | 1211a0a23564SMichal Meloun WIN_A_OF_INT | WIN_B_OF_INT | WIN_C_OF_INT); 1212a0a23564SMichal Meloun 1213a0a23564SMichal Meloun WR4(sc, DC_CMD_INT_POLARITY, 1214a0a23564SMichal Meloun WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT | 1215a0a23564SMichal Meloun WIN_A_OF_INT | WIN_B_OF_INT | WIN_C_OF_INT); 1216a0a23564SMichal Meloun 1217a0a23564SMichal Meloun WR4(sc, DC_CMD_INT_ENABLE, 0); 1218a0a23564SMichal Meloun WR4(sc, DC_CMD_INT_MASK, 0); 1219a0a23564SMichal Meloun 1220a0a23564SMichal Meloun rv = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC | INTR_MPSAFE, 1221a0a23564SMichal Meloun NULL, dc_intr, sc, &sc->irq_ih); 1222a0a23564SMichal Meloun if (rv != 0) { 1223a0a23564SMichal Meloun device_printf(dev, "Cannot register interrupt handler\n"); 1224a0a23564SMichal Meloun return (rv); 1225a0a23564SMichal Meloun } 1226a0a23564SMichal Meloun 1227a0a23564SMichal Meloun /* allocate memory for cursor cache */ 122844d0efb2SAlan Cox sc->tegra_crtc.cursor_vbase = kmem_alloc_contig(256 * 256 * 4, 122944d0efb2SAlan Cox M_WAITOK | M_ZERO, 0, -1UL, PAGE_SIZE, 0, 123044d0efb2SAlan Cox VM_MEMATTR_WRITE_COMBINING); 1231f49fd63aSJohn Baldwin sc->tegra_crtc.cursor_pbase = 1232f49fd63aSJohn Baldwin vtophys((uintptr_t)sc->tegra_crtc.cursor_vbase); 1233a0a23564SMichal Meloun return (0); 1234a0a23564SMichal Meloun } 1235a0a23564SMichal Meloun 1236a0a23564SMichal Meloun static int 1237a0a23564SMichal Meloun dc_exit_client(device_t dev, device_t host1x, struct tegra_drm *drm) 1238a0a23564SMichal Meloun { 1239a0a23564SMichal Meloun struct dc_softc *sc; 1240a0a23564SMichal Meloun 1241a0a23564SMichal Meloun sc = device_get_softc(dev); 1242a0a23564SMichal Meloun 1243a0a23564SMichal Meloun if (sc->irq_ih != NULL) 1244a0a23564SMichal Meloun bus_teardown_intr(dev, sc->irq_res, sc->irq_ih); 1245a0a23564SMichal Meloun sc->irq_ih = NULL; 1246a0a23564SMichal Meloun 1247a0a23564SMichal Meloun return (0); 1248a0a23564SMichal Meloun } 1249a0a23564SMichal Meloun 1250a0a23564SMichal Meloun static int 1251a0a23564SMichal Meloun get_fdt_resources(struct dc_softc *sc, phandle_t node) 1252a0a23564SMichal Meloun { 1253a0a23564SMichal Meloun int rv; 1254a0a23564SMichal Meloun 1255a0a23564SMichal Meloun rv = hwreset_get_by_ofw_name(sc->dev, 0, "dc", &sc->hwreset_dc); 1256a0a23564SMichal Meloun if (rv != 0) { 1257a0a23564SMichal Meloun device_printf(sc->dev, "Cannot get 'dc' reset\n"); 1258a0a23564SMichal Meloun return (rv); 1259a0a23564SMichal Meloun } 1260a0a23564SMichal Meloun rv = clk_get_by_ofw_name(sc->dev, 0, "parent", &sc->clk_parent); 1261a0a23564SMichal Meloun if (rv != 0) { 1262a0a23564SMichal Meloun device_printf(sc->dev, "Cannot get 'parent' clock\n"); 1263a0a23564SMichal Meloun return (rv); 1264a0a23564SMichal Meloun } 1265a0a23564SMichal Meloun rv = clk_get_by_ofw_name(sc->dev, 0, "dc", &sc->clk_dc); 1266a0a23564SMichal Meloun if (rv != 0) { 1267a0a23564SMichal Meloun device_printf(sc->dev, "Cannot get 'dc' clock\n"); 1268a0a23564SMichal Meloun return (rv); 1269a0a23564SMichal Meloun } 1270a0a23564SMichal Meloun 1271a0a23564SMichal Meloun rv = OF_getencprop(node, "nvidia,head", &sc->tegra_crtc.nvidia_head, 1272a0a23564SMichal Meloun sizeof(sc->tegra_crtc.nvidia_head)); 1273a0a23564SMichal Meloun if (rv <= 0) { 1274a0a23564SMichal Meloun device_printf(sc->dev, 1275a0a23564SMichal Meloun "Cannot get 'nvidia,head' property\n"); 1276a0a23564SMichal Meloun return (rv); 1277a0a23564SMichal Meloun } 1278a0a23564SMichal Meloun return (0); 1279a0a23564SMichal Meloun } 1280a0a23564SMichal Meloun 1281a0a23564SMichal Meloun static int 1282a0a23564SMichal Meloun enable_fdt_resources(struct dc_softc *sc) 1283a0a23564SMichal Meloun { 1284a0a23564SMichal Meloun int id, rv; 1285a0a23564SMichal Meloun 1286a0a23564SMichal Meloun rv = clk_set_parent_by_clk(sc->clk_dc, sc->clk_parent); 1287a0a23564SMichal Meloun if (rv != 0) { 1288a0a23564SMichal Meloun device_printf(sc->dev, "Cannot set parent for 'dc' clock\n"); 1289a0a23564SMichal Meloun return (rv); 1290a0a23564SMichal Meloun } 1291a0a23564SMichal Meloun 1292a0a23564SMichal Meloun id = (sc->tegra_crtc.nvidia_head == 0) ? 1293a0a23564SMichal Meloun TEGRA_POWERGATE_DIS: TEGRA_POWERGATE_DISB; 1294a0a23564SMichal Meloun rv = tegra_powergate_sequence_power_up(id, sc->clk_dc, sc->hwreset_dc); 1295a0a23564SMichal Meloun if (rv != 0) { 1296a0a23564SMichal Meloun device_printf(sc->dev, "Cannot enable 'DIS' powergate\n"); 1297a0a23564SMichal Meloun return (rv); 1298a0a23564SMichal Meloun } 1299a0a23564SMichal Meloun 1300a0a23564SMichal Meloun return (0); 1301a0a23564SMichal Meloun } 1302a0a23564SMichal Meloun 1303a0a23564SMichal Meloun static int 1304a0a23564SMichal Meloun dc_probe(device_t dev) 1305a0a23564SMichal Meloun { 1306a0a23564SMichal Meloun 1307a0a23564SMichal Meloun if (!ofw_bus_status_okay(dev)) 1308a0a23564SMichal Meloun return (ENXIO); 1309a0a23564SMichal Meloun 1310a0a23564SMichal Meloun if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) 1311a0a23564SMichal Meloun return (ENXIO); 1312a0a23564SMichal Meloun 1313a0a23564SMichal Meloun device_set_desc(dev, "Tegra Display Controller"); 1314a0a23564SMichal Meloun return (BUS_PROBE_DEFAULT); 1315a0a23564SMichal Meloun } 1316a0a23564SMichal Meloun 1317a0a23564SMichal Meloun static int 1318a0a23564SMichal Meloun dc_attach(device_t dev) 1319a0a23564SMichal Meloun { 1320a0a23564SMichal Meloun struct dc_softc *sc; 1321a0a23564SMichal Meloun phandle_t node; 1322a0a23564SMichal Meloun int rid, rv; 1323a0a23564SMichal Meloun 1324a0a23564SMichal Meloun sc = device_get_softc(dev); 1325a0a23564SMichal Meloun sc->dev = dev; 1326a0a23564SMichal Meloun sc->tegra_crtc.dev = dev; 1327a0a23564SMichal Meloun 1328a0a23564SMichal Meloun node = ofw_bus_get_node(sc->dev); 1329a0a23564SMichal Meloun LOCK_INIT(sc); 1330a0a23564SMichal Meloun 1331a0a23564SMichal Meloun rid = 0; 1332a0a23564SMichal Meloun sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 1333a0a23564SMichal Meloun RF_ACTIVE); 1334a0a23564SMichal Meloun if (sc->mem_res == NULL) { 1335a0a23564SMichal Meloun device_printf(dev, "Cannot allocate memory resources\n"); 1336a0a23564SMichal Meloun goto fail; 1337a0a23564SMichal Meloun } 1338a0a23564SMichal Meloun 1339a0a23564SMichal Meloun rid = 0; 1340a0a23564SMichal Meloun sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE); 1341a0a23564SMichal Meloun if (sc->irq_res == NULL) { 1342a0a23564SMichal Meloun device_printf(dev, "Cannot allocate IRQ resources\n"); 1343a0a23564SMichal Meloun goto fail; 1344a0a23564SMichal Meloun } 1345a0a23564SMichal Meloun 1346a0a23564SMichal Meloun rv = get_fdt_resources(sc, node); 1347a0a23564SMichal Meloun if (rv != 0) { 1348a0a23564SMichal Meloun device_printf(dev, "Cannot parse FDT resources\n"); 1349a0a23564SMichal Meloun goto fail; 1350a0a23564SMichal Meloun } 1351a0a23564SMichal Meloun rv = enable_fdt_resources(sc); 1352a0a23564SMichal Meloun if (rv != 0) { 1353a0a23564SMichal Meloun device_printf(dev, "Cannot enable FDT resources\n"); 1354a0a23564SMichal Meloun goto fail; 1355a0a23564SMichal Meloun } 1356a0a23564SMichal Meloun 1357a0a23564SMichal Meloun /* 1358a0a23564SMichal Meloun * Tegra124 1359a0a23564SMichal Meloun * - 64 for RGB modes 1360a0a23564SMichal Meloun * - 128 for YUV planar modes 1361a0a23564SMichal Meloun * - 256 for block linear modes 1362a0a23564SMichal Meloun */ 1363a0a23564SMichal Meloun sc->pitch_align = 256; 1364a0a23564SMichal Meloun 1365a0a23564SMichal Meloun rv = TEGRA_DRM_REGISTER_CLIENT(device_get_parent(sc->dev), sc->dev); 1366a0a23564SMichal Meloun if (rv != 0) { 1367a0a23564SMichal Meloun device_printf(dev, "Cannot register DRM device\n"); 1368a0a23564SMichal Meloun goto fail; 1369a0a23564SMichal Meloun } 1370a0a23564SMichal Meloun 1371*18250ec6SJohn Baldwin bus_attach_children(dev); 1372*18250ec6SJohn Baldwin return (0); 1373a0a23564SMichal Meloun 1374a0a23564SMichal Meloun fail: 1375a0a23564SMichal Meloun TEGRA_DRM_DEREGISTER_CLIENT(device_get_parent(sc->dev), sc->dev); 1376a0a23564SMichal Meloun if (sc->irq_ih != NULL) 1377a0a23564SMichal Meloun bus_teardown_intr(dev, sc->irq_res, sc->irq_ih); 1378a0a23564SMichal Meloun if (sc->clk_parent != NULL) 1379a0a23564SMichal Meloun clk_release(sc->clk_parent); 1380a0a23564SMichal Meloun if (sc->clk_dc != NULL) 1381a0a23564SMichal Meloun clk_release(sc->clk_dc); 1382a0a23564SMichal Meloun if (sc->hwreset_dc != NULL) 1383a0a23564SMichal Meloun hwreset_release(sc->hwreset_dc); 1384a0a23564SMichal Meloun if (sc->irq_res != NULL) 1385a0a23564SMichal Meloun bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res); 1386a0a23564SMichal Meloun if (sc->mem_res != NULL) 1387a0a23564SMichal Meloun bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res); 1388a0a23564SMichal Meloun LOCK_DESTROY(sc); 1389a0a23564SMichal Meloun 1390a0a23564SMichal Meloun return (ENXIO); 1391a0a23564SMichal Meloun } 1392a0a23564SMichal Meloun 1393a0a23564SMichal Meloun static int 1394a0a23564SMichal Meloun dc_detach(device_t dev) 1395a0a23564SMichal Meloun { 1396a0a23564SMichal Meloun struct dc_softc *sc; 1397d412c076SJohn Baldwin int error; 1398d412c076SJohn Baldwin 1399d412c076SJohn Baldwin error = bus_generic_detach(dev); 1400d412c076SJohn Baldwin if (error != 0) 1401d412c076SJohn Baldwin return (error); 1402a0a23564SMichal Meloun 1403a0a23564SMichal Meloun sc = device_get_softc(dev); 1404a0a23564SMichal Meloun 1405a0a23564SMichal Meloun TEGRA_DRM_DEREGISTER_CLIENT(device_get_parent(sc->dev), sc->dev); 1406a0a23564SMichal Meloun 1407a0a23564SMichal Meloun if (sc->irq_ih != NULL) 1408a0a23564SMichal Meloun bus_teardown_intr(dev, sc->irq_res, sc->irq_ih); 1409a0a23564SMichal Meloun if (sc->clk_parent != NULL) 1410a0a23564SMichal Meloun clk_release(sc->clk_parent); 1411a0a23564SMichal Meloun if (sc->clk_dc != NULL) 1412a0a23564SMichal Meloun clk_release(sc->clk_dc); 1413a0a23564SMichal Meloun if (sc->hwreset_dc != NULL) 1414a0a23564SMichal Meloun hwreset_release(sc->hwreset_dc); 1415a0a23564SMichal Meloun if (sc->irq_res != NULL) 1416a0a23564SMichal Meloun bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res); 1417a0a23564SMichal Meloun if (sc->mem_res != NULL) 1418a0a23564SMichal Meloun bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res); 1419a0a23564SMichal Meloun LOCK_DESTROY(sc); 1420a0a23564SMichal Meloun 1421d412c076SJohn Baldwin return (0); 1422a0a23564SMichal Meloun } 1423a0a23564SMichal Meloun 1424a0a23564SMichal Meloun static device_method_t tegra_dc_methods[] = { 1425a0a23564SMichal Meloun /* Device interface */ 1426a0a23564SMichal Meloun DEVMETHOD(device_probe, dc_probe), 1427a0a23564SMichal Meloun DEVMETHOD(device_attach, dc_attach), 1428a0a23564SMichal Meloun DEVMETHOD(device_detach, dc_detach), 1429a0a23564SMichal Meloun 1430a0a23564SMichal Meloun /* tegra drm interface */ 1431a0a23564SMichal Meloun DEVMETHOD(tegra_drm_init_client, dc_init_client), 1432a0a23564SMichal Meloun DEVMETHOD(tegra_drm_exit_client, dc_exit_client), 1433a0a23564SMichal Meloun 1434a0a23564SMichal Meloun /* tegra dc interface */ 1435a0a23564SMichal Meloun DEVMETHOD(tegra_dc_display_enable, dc_display_enable), 1436a0a23564SMichal Meloun DEVMETHOD(tegra_dc_hdmi_enable, dc_hdmi_enable), 1437a0a23564SMichal Meloun DEVMETHOD(tegra_dc_setup_timing, dc_setup_timing), 1438a0a23564SMichal Meloun 1439a0a23564SMichal Meloun DEVMETHOD_END 1440a0a23564SMichal Meloun }; 1441a0a23564SMichal Meloun 1442a0a23564SMichal Meloun DEFINE_CLASS_0(tegra_dc, tegra_dc_driver, tegra_dc_methods, 1443a0a23564SMichal Meloun sizeof(struct dc_softc)); 1444289f133bSJohn Baldwin DRIVER_MODULE(tegra_dc, host1x, tegra_dc_driver, NULL, NULL); 1445