1*dee8268fSThierry Reding /* 2*dee8268fSThierry Reding * Copyright (C) 2012 Avionic Design GmbH 3*dee8268fSThierry Reding * Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved. 4*dee8268fSThierry Reding * 5*dee8268fSThierry Reding * This program is free software; you can redistribute it and/or modify 6*dee8268fSThierry Reding * it under the terms of the GNU General Public License version 2 as 7*dee8268fSThierry Reding * published by the Free Software Foundation. 8*dee8268fSThierry Reding */ 9*dee8268fSThierry Reding 10*dee8268fSThierry Reding #include <linux/clk.h> 11*dee8268fSThierry Reding #include <linux/clk/tegra.h> 12*dee8268fSThierry Reding #include <linux/debugfs.h> 13*dee8268fSThierry Reding 14*dee8268fSThierry Reding #include "dc.h" 15*dee8268fSThierry Reding #include "drm.h" 16*dee8268fSThierry Reding #include "gem.h" 17*dee8268fSThierry Reding 18*dee8268fSThierry Reding struct tegra_plane { 19*dee8268fSThierry Reding struct drm_plane base; 20*dee8268fSThierry Reding unsigned int index; 21*dee8268fSThierry Reding }; 22*dee8268fSThierry Reding 23*dee8268fSThierry Reding static inline struct tegra_plane *to_tegra_plane(struct drm_plane *plane) 24*dee8268fSThierry Reding { 25*dee8268fSThierry Reding return container_of(plane, struct tegra_plane, base); 26*dee8268fSThierry Reding } 27*dee8268fSThierry Reding 28*dee8268fSThierry Reding static int tegra_plane_update(struct drm_plane *plane, struct drm_crtc *crtc, 29*dee8268fSThierry Reding struct drm_framebuffer *fb, int crtc_x, 30*dee8268fSThierry Reding int crtc_y, unsigned int crtc_w, 31*dee8268fSThierry Reding unsigned int crtc_h, uint32_t src_x, 32*dee8268fSThierry Reding uint32_t src_y, uint32_t src_w, uint32_t src_h) 33*dee8268fSThierry Reding { 34*dee8268fSThierry Reding struct tegra_plane *p = to_tegra_plane(plane); 35*dee8268fSThierry Reding struct tegra_dc *dc = to_tegra_dc(crtc); 36*dee8268fSThierry Reding struct tegra_dc_window window; 37*dee8268fSThierry Reding unsigned int i; 38*dee8268fSThierry Reding 39*dee8268fSThierry Reding memset(&window, 0, sizeof(window)); 40*dee8268fSThierry Reding window.src.x = src_x >> 16; 41*dee8268fSThierry Reding window.src.y = src_y >> 16; 42*dee8268fSThierry Reding window.src.w = src_w >> 16; 43*dee8268fSThierry Reding window.src.h = src_h >> 16; 44*dee8268fSThierry Reding window.dst.x = crtc_x; 45*dee8268fSThierry Reding window.dst.y = crtc_y; 46*dee8268fSThierry Reding window.dst.w = crtc_w; 47*dee8268fSThierry Reding window.dst.h = crtc_h; 48*dee8268fSThierry Reding window.format = tegra_dc_format(fb->pixel_format); 49*dee8268fSThierry Reding window.bits_per_pixel = fb->bits_per_pixel; 50*dee8268fSThierry Reding 51*dee8268fSThierry Reding for (i = 0; i < drm_format_num_planes(fb->pixel_format); i++) { 52*dee8268fSThierry Reding struct tegra_bo *bo = tegra_fb_get_plane(fb, i); 53*dee8268fSThierry Reding 54*dee8268fSThierry Reding window.base[i] = bo->paddr + fb->offsets[i]; 55*dee8268fSThierry Reding 56*dee8268fSThierry Reding /* 57*dee8268fSThierry Reding * Tegra doesn't support different strides for U and V planes 58*dee8268fSThierry Reding * so we display a warning if the user tries to display a 59*dee8268fSThierry Reding * framebuffer with such a configuration. 60*dee8268fSThierry Reding */ 61*dee8268fSThierry Reding if (i >= 2) { 62*dee8268fSThierry Reding if (fb->pitches[i] != window.stride[1]) 63*dee8268fSThierry Reding DRM_ERROR("unsupported UV-plane configuration\n"); 64*dee8268fSThierry Reding } else { 65*dee8268fSThierry Reding window.stride[i] = fb->pitches[i]; 66*dee8268fSThierry Reding } 67*dee8268fSThierry Reding } 68*dee8268fSThierry Reding 69*dee8268fSThierry Reding return tegra_dc_setup_window(dc, p->index, &window); 70*dee8268fSThierry Reding } 71*dee8268fSThierry Reding 72*dee8268fSThierry Reding static int tegra_plane_disable(struct drm_plane *plane) 73*dee8268fSThierry Reding { 74*dee8268fSThierry Reding struct tegra_dc *dc = to_tegra_dc(plane->crtc); 75*dee8268fSThierry Reding struct tegra_plane *p = to_tegra_plane(plane); 76*dee8268fSThierry Reding unsigned long value; 77*dee8268fSThierry Reding 78*dee8268fSThierry Reding if (!plane->crtc) 79*dee8268fSThierry Reding return 0; 80*dee8268fSThierry Reding 81*dee8268fSThierry Reding value = WINDOW_A_SELECT << p->index; 82*dee8268fSThierry Reding tegra_dc_writel(dc, value, DC_CMD_DISPLAY_WINDOW_HEADER); 83*dee8268fSThierry Reding 84*dee8268fSThierry Reding value = tegra_dc_readl(dc, DC_WIN_WIN_OPTIONS); 85*dee8268fSThierry Reding value &= ~WIN_ENABLE; 86*dee8268fSThierry Reding tegra_dc_writel(dc, value, DC_WIN_WIN_OPTIONS); 87*dee8268fSThierry Reding 88*dee8268fSThierry Reding tegra_dc_writel(dc, WIN_A_UPDATE << p->index, DC_CMD_STATE_CONTROL); 89*dee8268fSThierry Reding tegra_dc_writel(dc, WIN_A_ACT_REQ << p->index, DC_CMD_STATE_CONTROL); 90*dee8268fSThierry Reding 91*dee8268fSThierry Reding return 0; 92*dee8268fSThierry Reding } 93*dee8268fSThierry Reding 94*dee8268fSThierry Reding static void tegra_plane_destroy(struct drm_plane *plane) 95*dee8268fSThierry Reding { 96*dee8268fSThierry Reding tegra_plane_disable(plane); 97*dee8268fSThierry Reding drm_plane_cleanup(plane); 98*dee8268fSThierry Reding } 99*dee8268fSThierry Reding 100*dee8268fSThierry Reding static const struct drm_plane_funcs tegra_plane_funcs = { 101*dee8268fSThierry Reding .update_plane = tegra_plane_update, 102*dee8268fSThierry Reding .disable_plane = tegra_plane_disable, 103*dee8268fSThierry Reding .destroy = tegra_plane_destroy, 104*dee8268fSThierry Reding }; 105*dee8268fSThierry Reding 106*dee8268fSThierry Reding static const uint32_t plane_formats[] = { 107*dee8268fSThierry Reding DRM_FORMAT_XBGR8888, 108*dee8268fSThierry Reding DRM_FORMAT_XRGB8888, 109*dee8268fSThierry Reding DRM_FORMAT_RGB565, 110*dee8268fSThierry Reding DRM_FORMAT_UYVY, 111*dee8268fSThierry Reding DRM_FORMAT_YUV420, 112*dee8268fSThierry Reding DRM_FORMAT_YUV422, 113*dee8268fSThierry Reding }; 114*dee8268fSThierry Reding 115*dee8268fSThierry Reding static int tegra_dc_add_planes(struct drm_device *drm, struct tegra_dc *dc) 116*dee8268fSThierry Reding { 117*dee8268fSThierry Reding unsigned int i; 118*dee8268fSThierry Reding int err = 0; 119*dee8268fSThierry Reding 120*dee8268fSThierry Reding for (i = 0; i < 2; i++) { 121*dee8268fSThierry Reding struct tegra_plane *plane; 122*dee8268fSThierry Reding 123*dee8268fSThierry Reding plane = devm_kzalloc(drm->dev, sizeof(*plane), GFP_KERNEL); 124*dee8268fSThierry Reding if (!plane) 125*dee8268fSThierry Reding return -ENOMEM; 126*dee8268fSThierry Reding 127*dee8268fSThierry Reding plane->index = 1 + i; 128*dee8268fSThierry Reding 129*dee8268fSThierry Reding err = drm_plane_init(drm, &plane->base, 1 << dc->pipe, 130*dee8268fSThierry Reding &tegra_plane_funcs, plane_formats, 131*dee8268fSThierry Reding ARRAY_SIZE(plane_formats), false); 132*dee8268fSThierry Reding if (err < 0) 133*dee8268fSThierry Reding return err; 134*dee8268fSThierry Reding } 135*dee8268fSThierry Reding 136*dee8268fSThierry Reding return 0; 137*dee8268fSThierry Reding } 138*dee8268fSThierry Reding 139*dee8268fSThierry Reding static int tegra_dc_set_base(struct tegra_dc *dc, int x, int y, 140*dee8268fSThierry Reding struct drm_framebuffer *fb) 141*dee8268fSThierry Reding { 142*dee8268fSThierry Reding unsigned int format = tegra_dc_format(fb->pixel_format); 143*dee8268fSThierry Reding struct tegra_bo *bo = tegra_fb_get_plane(fb, 0); 144*dee8268fSThierry Reding unsigned long value; 145*dee8268fSThierry Reding 146*dee8268fSThierry Reding tegra_dc_writel(dc, WINDOW_A_SELECT, DC_CMD_DISPLAY_WINDOW_HEADER); 147*dee8268fSThierry Reding 148*dee8268fSThierry Reding value = fb->offsets[0] + y * fb->pitches[0] + 149*dee8268fSThierry Reding x * fb->bits_per_pixel / 8; 150*dee8268fSThierry Reding 151*dee8268fSThierry Reding tegra_dc_writel(dc, bo->paddr + value, DC_WINBUF_START_ADDR); 152*dee8268fSThierry Reding tegra_dc_writel(dc, fb->pitches[0], DC_WIN_LINE_STRIDE); 153*dee8268fSThierry Reding tegra_dc_writel(dc, format, DC_WIN_COLOR_DEPTH); 154*dee8268fSThierry Reding 155*dee8268fSThierry Reding value = GENERAL_UPDATE | WIN_A_UPDATE; 156*dee8268fSThierry Reding tegra_dc_writel(dc, value, DC_CMD_STATE_CONTROL); 157*dee8268fSThierry Reding 158*dee8268fSThierry Reding value = GENERAL_ACT_REQ | WIN_A_ACT_REQ; 159*dee8268fSThierry Reding tegra_dc_writel(dc, value, DC_CMD_STATE_CONTROL); 160*dee8268fSThierry Reding 161*dee8268fSThierry Reding return 0; 162*dee8268fSThierry Reding } 163*dee8268fSThierry Reding 164*dee8268fSThierry Reding void tegra_dc_enable_vblank(struct tegra_dc *dc) 165*dee8268fSThierry Reding { 166*dee8268fSThierry Reding unsigned long value, flags; 167*dee8268fSThierry Reding 168*dee8268fSThierry Reding spin_lock_irqsave(&dc->lock, flags); 169*dee8268fSThierry Reding 170*dee8268fSThierry Reding value = tegra_dc_readl(dc, DC_CMD_INT_MASK); 171*dee8268fSThierry Reding value |= VBLANK_INT; 172*dee8268fSThierry Reding tegra_dc_writel(dc, value, DC_CMD_INT_MASK); 173*dee8268fSThierry Reding 174*dee8268fSThierry Reding spin_unlock_irqrestore(&dc->lock, flags); 175*dee8268fSThierry Reding } 176*dee8268fSThierry Reding 177*dee8268fSThierry Reding void tegra_dc_disable_vblank(struct tegra_dc *dc) 178*dee8268fSThierry Reding { 179*dee8268fSThierry Reding unsigned long value, flags; 180*dee8268fSThierry Reding 181*dee8268fSThierry Reding spin_lock_irqsave(&dc->lock, flags); 182*dee8268fSThierry Reding 183*dee8268fSThierry Reding value = tegra_dc_readl(dc, DC_CMD_INT_MASK); 184*dee8268fSThierry Reding value &= ~VBLANK_INT; 185*dee8268fSThierry Reding tegra_dc_writel(dc, value, DC_CMD_INT_MASK); 186*dee8268fSThierry Reding 187*dee8268fSThierry Reding spin_unlock_irqrestore(&dc->lock, flags); 188*dee8268fSThierry Reding } 189*dee8268fSThierry Reding 190*dee8268fSThierry Reding static void tegra_dc_finish_page_flip(struct tegra_dc *dc) 191*dee8268fSThierry Reding { 192*dee8268fSThierry Reding struct drm_device *drm = dc->base.dev; 193*dee8268fSThierry Reding struct drm_crtc *crtc = &dc->base; 194*dee8268fSThierry Reding unsigned long flags, base; 195*dee8268fSThierry Reding struct tegra_bo *bo; 196*dee8268fSThierry Reding 197*dee8268fSThierry Reding if (!dc->event) 198*dee8268fSThierry Reding return; 199*dee8268fSThierry Reding 200*dee8268fSThierry Reding bo = tegra_fb_get_plane(crtc->fb, 0); 201*dee8268fSThierry Reding 202*dee8268fSThierry Reding /* check if new start address has been latched */ 203*dee8268fSThierry Reding tegra_dc_writel(dc, READ_MUX, DC_CMD_STATE_ACCESS); 204*dee8268fSThierry Reding base = tegra_dc_readl(dc, DC_WINBUF_START_ADDR); 205*dee8268fSThierry Reding tegra_dc_writel(dc, 0, DC_CMD_STATE_ACCESS); 206*dee8268fSThierry Reding 207*dee8268fSThierry Reding if (base == bo->paddr + crtc->fb->offsets[0]) { 208*dee8268fSThierry Reding spin_lock_irqsave(&drm->event_lock, flags); 209*dee8268fSThierry Reding drm_send_vblank_event(drm, dc->pipe, dc->event); 210*dee8268fSThierry Reding drm_vblank_put(drm, dc->pipe); 211*dee8268fSThierry Reding dc->event = NULL; 212*dee8268fSThierry Reding spin_unlock_irqrestore(&drm->event_lock, flags); 213*dee8268fSThierry Reding } 214*dee8268fSThierry Reding } 215*dee8268fSThierry Reding 216*dee8268fSThierry Reding void tegra_dc_cancel_page_flip(struct drm_crtc *crtc, struct drm_file *file) 217*dee8268fSThierry Reding { 218*dee8268fSThierry Reding struct tegra_dc *dc = to_tegra_dc(crtc); 219*dee8268fSThierry Reding struct drm_device *drm = crtc->dev; 220*dee8268fSThierry Reding unsigned long flags; 221*dee8268fSThierry Reding 222*dee8268fSThierry Reding spin_lock_irqsave(&drm->event_lock, flags); 223*dee8268fSThierry Reding 224*dee8268fSThierry Reding if (dc->event && dc->event->base.file_priv == file) { 225*dee8268fSThierry Reding dc->event->base.destroy(&dc->event->base); 226*dee8268fSThierry Reding drm_vblank_put(drm, dc->pipe); 227*dee8268fSThierry Reding dc->event = NULL; 228*dee8268fSThierry Reding } 229*dee8268fSThierry Reding 230*dee8268fSThierry Reding spin_unlock_irqrestore(&drm->event_lock, flags); 231*dee8268fSThierry Reding } 232*dee8268fSThierry Reding 233*dee8268fSThierry Reding static int tegra_dc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, 234*dee8268fSThierry Reding struct drm_pending_vblank_event *event, uint32_t page_flip_flags) 235*dee8268fSThierry Reding { 236*dee8268fSThierry Reding struct tegra_dc *dc = to_tegra_dc(crtc); 237*dee8268fSThierry Reding struct drm_device *drm = crtc->dev; 238*dee8268fSThierry Reding 239*dee8268fSThierry Reding if (dc->event) 240*dee8268fSThierry Reding return -EBUSY; 241*dee8268fSThierry Reding 242*dee8268fSThierry Reding if (event) { 243*dee8268fSThierry Reding event->pipe = dc->pipe; 244*dee8268fSThierry Reding dc->event = event; 245*dee8268fSThierry Reding drm_vblank_get(drm, dc->pipe); 246*dee8268fSThierry Reding } 247*dee8268fSThierry Reding 248*dee8268fSThierry Reding tegra_dc_set_base(dc, 0, 0, fb); 249*dee8268fSThierry Reding crtc->fb = fb; 250*dee8268fSThierry Reding 251*dee8268fSThierry Reding return 0; 252*dee8268fSThierry Reding } 253*dee8268fSThierry Reding 254*dee8268fSThierry Reding static const struct drm_crtc_funcs tegra_crtc_funcs = { 255*dee8268fSThierry Reding .page_flip = tegra_dc_page_flip, 256*dee8268fSThierry Reding .set_config = drm_crtc_helper_set_config, 257*dee8268fSThierry Reding .destroy = drm_crtc_cleanup, 258*dee8268fSThierry Reding }; 259*dee8268fSThierry Reding 260*dee8268fSThierry Reding static void tegra_crtc_disable(struct drm_crtc *crtc) 261*dee8268fSThierry Reding { 262*dee8268fSThierry Reding struct drm_device *drm = crtc->dev; 263*dee8268fSThierry Reding struct drm_plane *plane; 264*dee8268fSThierry Reding 265*dee8268fSThierry Reding list_for_each_entry(plane, &drm->mode_config.plane_list, head) { 266*dee8268fSThierry Reding if (plane->crtc == crtc) { 267*dee8268fSThierry Reding tegra_plane_disable(plane); 268*dee8268fSThierry Reding plane->crtc = NULL; 269*dee8268fSThierry Reding 270*dee8268fSThierry Reding if (plane->fb) { 271*dee8268fSThierry Reding drm_framebuffer_unreference(plane->fb); 272*dee8268fSThierry Reding plane->fb = NULL; 273*dee8268fSThierry Reding } 274*dee8268fSThierry Reding } 275*dee8268fSThierry Reding } 276*dee8268fSThierry Reding } 277*dee8268fSThierry Reding 278*dee8268fSThierry Reding static bool tegra_crtc_mode_fixup(struct drm_crtc *crtc, 279*dee8268fSThierry Reding const struct drm_display_mode *mode, 280*dee8268fSThierry Reding struct drm_display_mode *adjusted) 281*dee8268fSThierry Reding { 282*dee8268fSThierry Reding return true; 283*dee8268fSThierry Reding } 284*dee8268fSThierry Reding 285*dee8268fSThierry Reding static inline u32 compute_dda_inc(unsigned int in, unsigned int out, bool v, 286*dee8268fSThierry Reding unsigned int bpp) 287*dee8268fSThierry Reding { 288*dee8268fSThierry Reding fixed20_12 outf = dfixed_init(out); 289*dee8268fSThierry Reding fixed20_12 inf = dfixed_init(in); 290*dee8268fSThierry Reding u32 dda_inc; 291*dee8268fSThierry Reding int max; 292*dee8268fSThierry Reding 293*dee8268fSThierry Reding if (v) 294*dee8268fSThierry Reding max = 15; 295*dee8268fSThierry Reding else { 296*dee8268fSThierry Reding switch (bpp) { 297*dee8268fSThierry Reding case 2: 298*dee8268fSThierry Reding max = 8; 299*dee8268fSThierry Reding break; 300*dee8268fSThierry Reding 301*dee8268fSThierry Reding default: 302*dee8268fSThierry Reding WARN_ON_ONCE(1); 303*dee8268fSThierry Reding /* fallthrough */ 304*dee8268fSThierry Reding case 4: 305*dee8268fSThierry Reding max = 4; 306*dee8268fSThierry Reding break; 307*dee8268fSThierry Reding } 308*dee8268fSThierry Reding } 309*dee8268fSThierry Reding 310*dee8268fSThierry Reding outf.full = max_t(u32, outf.full - dfixed_const(1), dfixed_const(1)); 311*dee8268fSThierry Reding inf.full -= dfixed_const(1); 312*dee8268fSThierry Reding 313*dee8268fSThierry Reding dda_inc = dfixed_div(inf, outf); 314*dee8268fSThierry Reding dda_inc = min_t(u32, dda_inc, dfixed_const(max)); 315*dee8268fSThierry Reding 316*dee8268fSThierry Reding return dda_inc; 317*dee8268fSThierry Reding } 318*dee8268fSThierry Reding 319*dee8268fSThierry Reding static inline u32 compute_initial_dda(unsigned int in) 320*dee8268fSThierry Reding { 321*dee8268fSThierry Reding fixed20_12 inf = dfixed_init(in); 322*dee8268fSThierry Reding return dfixed_frac(inf); 323*dee8268fSThierry Reding } 324*dee8268fSThierry Reding 325*dee8268fSThierry Reding static int tegra_dc_set_timings(struct tegra_dc *dc, 326*dee8268fSThierry Reding struct drm_display_mode *mode) 327*dee8268fSThierry Reding { 328*dee8268fSThierry Reding /* TODO: For HDMI compliance, h & v ref_to_sync should be set to 1 */ 329*dee8268fSThierry Reding unsigned int h_ref_to_sync = 0; 330*dee8268fSThierry Reding unsigned int v_ref_to_sync = 0; 331*dee8268fSThierry Reding unsigned long value; 332*dee8268fSThierry Reding 333*dee8268fSThierry Reding tegra_dc_writel(dc, 0x0, DC_DISP_DISP_TIMING_OPTIONS); 334*dee8268fSThierry Reding 335*dee8268fSThierry Reding value = (v_ref_to_sync << 16) | h_ref_to_sync; 336*dee8268fSThierry Reding tegra_dc_writel(dc, value, DC_DISP_REF_TO_SYNC); 337*dee8268fSThierry Reding 338*dee8268fSThierry Reding value = ((mode->vsync_end - mode->vsync_start) << 16) | 339*dee8268fSThierry Reding ((mode->hsync_end - mode->hsync_start) << 0); 340*dee8268fSThierry Reding tegra_dc_writel(dc, value, DC_DISP_SYNC_WIDTH); 341*dee8268fSThierry Reding 342*dee8268fSThierry Reding value = ((mode->vtotal - mode->vsync_end) << 16) | 343*dee8268fSThierry Reding ((mode->htotal - mode->hsync_end) << 0); 344*dee8268fSThierry Reding tegra_dc_writel(dc, value, DC_DISP_BACK_PORCH); 345*dee8268fSThierry Reding 346*dee8268fSThierry Reding value = ((mode->vsync_start - mode->vdisplay) << 16) | 347*dee8268fSThierry Reding ((mode->hsync_start - mode->hdisplay) << 0); 348*dee8268fSThierry Reding tegra_dc_writel(dc, value, DC_DISP_FRONT_PORCH); 349*dee8268fSThierry Reding 350*dee8268fSThierry Reding value = (mode->vdisplay << 16) | mode->hdisplay; 351*dee8268fSThierry Reding tegra_dc_writel(dc, value, DC_DISP_ACTIVE); 352*dee8268fSThierry Reding 353*dee8268fSThierry Reding return 0; 354*dee8268fSThierry Reding } 355*dee8268fSThierry Reding 356*dee8268fSThierry Reding static int tegra_crtc_setup_clk(struct drm_crtc *crtc, 357*dee8268fSThierry Reding struct drm_display_mode *mode, 358*dee8268fSThierry Reding unsigned long *div) 359*dee8268fSThierry Reding { 360*dee8268fSThierry Reding unsigned long pclk = mode->clock * 1000, rate; 361*dee8268fSThierry Reding struct tegra_dc *dc = to_tegra_dc(crtc); 362*dee8268fSThierry Reding struct tegra_output *output = NULL; 363*dee8268fSThierry Reding struct drm_encoder *encoder; 364*dee8268fSThierry Reding long err; 365*dee8268fSThierry Reding 366*dee8268fSThierry Reding list_for_each_entry(encoder, &crtc->dev->mode_config.encoder_list, head) 367*dee8268fSThierry Reding if (encoder->crtc == crtc) { 368*dee8268fSThierry Reding output = encoder_to_output(encoder); 369*dee8268fSThierry Reding break; 370*dee8268fSThierry Reding } 371*dee8268fSThierry Reding 372*dee8268fSThierry Reding if (!output) 373*dee8268fSThierry Reding return -ENODEV; 374*dee8268fSThierry Reding 375*dee8268fSThierry Reding /* 376*dee8268fSThierry Reding * This assumes that the display controller will divide its parent 377*dee8268fSThierry Reding * clock by 2 to generate the pixel clock. 378*dee8268fSThierry Reding */ 379*dee8268fSThierry Reding err = tegra_output_setup_clock(output, dc->clk, pclk * 2); 380*dee8268fSThierry Reding if (err < 0) { 381*dee8268fSThierry Reding dev_err(dc->dev, "failed to setup clock: %ld\n", err); 382*dee8268fSThierry Reding return err; 383*dee8268fSThierry Reding } 384*dee8268fSThierry Reding 385*dee8268fSThierry Reding rate = clk_get_rate(dc->clk); 386*dee8268fSThierry Reding *div = (rate * 2 / pclk) - 2; 387*dee8268fSThierry Reding 388*dee8268fSThierry Reding DRM_DEBUG_KMS("rate: %lu, div: %lu\n", rate, *div); 389*dee8268fSThierry Reding 390*dee8268fSThierry Reding return 0; 391*dee8268fSThierry Reding } 392*dee8268fSThierry Reding 393*dee8268fSThierry Reding static bool tegra_dc_format_is_yuv(unsigned int format, bool *planar) 394*dee8268fSThierry Reding { 395*dee8268fSThierry Reding switch (format) { 396*dee8268fSThierry Reding case WIN_COLOR_DEPTH_YCbCr422: 397*dee8268fSThierry Reding case WIN_COLOR_DEPTH_YUV422: 398*dee8268fSThierry Reding if (planar) 399*dee8268fSThierry Reding *planar = false; 400*dee8268fSThierry Reding 401*dee8268fSThierry Reding return true; 402*dee8268fSThierry Reding 403*dee8268fSThierry Reding case WIN_COLOR_DEPTH_YCbCr420P: 404*dee8268fSThierry Reding case WIN_COLOR_DEPTH_YUV420P: 405*dee8268fSThierry Reding case WIN_COLOR_DEPTH_YCbCr422P: 406*dee8268fSThierry Reding case WIN_COLOR_DEPTH_YUV422P: 407*dee8268fSThierry Reding case WIN_COLOR_DEPTH_YCbCr422R: 408*dee8268fSThierry Reding case WIN_COLOR_DEPTH_YUV422R: 409*dee8268fSThierry Reding case WIN_COLOR_DEPTH_YCbCr422RA: 410*dee8268fSThierry Reding case WIN_COLOR_DEPTH_YUV422RA: 411*dee8268fSThierry Reding if (planar) 412*dee8268fSThierry Reding *planar = true; 413*dee8268fSThierry Reding 414*dee8268fSThierry Reding return true; 415*dee8268fSThierry Reding } 416*dee8268fSThierry Reding 417*dee8268fSThierry Reding return false; 418*dee8268fSThierry Reding } 419*dee8268fSThierry Reding 420*dee8268fSThierry Reding int tegra_dc_setup_window(struct tegra_dc *dc, unsigned int index, 421*dee8268fSThierry Reding const struct tegra_dc_window *window) 422*dee8268fSThierry Reding { 423*dee8268fSThierry Reding unsigned h_offset, v_offset, h_size, v_size, h_dda, v_dda, bpp; 424*dee8268fSThierry Reding unsigned long value; 425*dee8268fSThierry Reding bool yuv, planar; 426*dee8268fSThierry Reding 427*dee8268fSThierry Reding /* 428*dee8268fSThierry Reding * For YUV planar modes, the number of bytes per pixel takes into 429*dee8268fSThierry Reding * account only the luma component and therefore is 1. 430*dee8268fSThierry Reding */ 431*dee8268fSThierry Reding yuv = tegra_dc_format_is_yuv(window->format, &planar); 432*dee8268fSThierry Reding if (!yuv) 433*dee8268fSThierry Reding bpp = window->bits_per_pixel / 8; 434*dee8268fSThierry Reding else 435*dee8268fSThierry Reding bpp = planar ? 1 : 2; 436*dee8268fSThierry Reding 437*dee8268fSThierry Reding value = WINDOW_A_SELECT << index; 438*dee8268fSThierry Reding tegra_dc_writel(dc, value, DC_CMD_DISPLAY_WINDOW_HEADER); 439*dee8268fSThierry Reding 440*dee8268fSThierry Reding tegra_dc_writel(dc, window->format, DC_WIN_COLOR_DEPTH); 441*dee8268fSThierry Reding tegra_dc_writel(dc, 0, DC_WIN_BYTE_SWAP); 442*dee8268fSThierry Reding 443*dee8268fSThierry Reding value = V_POSITION(window->dst.y) | H_POSITION(window->dst.x); 444*dee8268fSThierry Reding tegra_dc_writel(dc, value, DC_WIN_POSITION); 445*dee8268fSThierry Reding 446*dee8268fSThierry Reding value = V_SIZE(window->dst.h) | H_SIZE(window->dst.w); 447*dee8268fSThierry Reding tegra_dc_writel(dc, value, DC_WIN_SIZE); 448*dee8268fSThierry Reding 449*dee8268fSThierry Reding h_offset = window->src.x * bpp; 450*dee8268fSThierry Reding v_offset = window->src.y; 451*dee8268fSThierry Reding h_size = window->src.w * bpp; 452*dee8268fSThierry Reding v_size = window->src.h; 453*dee8268fSThierry Reding 454*dee8268fSThierry Reding value = V_PRESCALED_SIZE(v_size) | H_PRESCALED_SIZE(h_size); 455*dee8268fSThierry Reding tegra_dc_writel(dc, value, DC_WIN_PRESCALED_SIZE); 456*dee8268fSThierry Reding 457*dee8268fSThierry Reding /* 458*dee8268fSThierry Reding * For DDA computations the number of bytes per pixel for YUV planar 459*dee8268fSThierry Reding * modes needs to take into account all Y, U and V components. 460*dee8268fSThierry Reding */ 461*dee8268fSThierry Reding if (yuv && planar) 462*dee8268fSThierry Reding bpp = 2; 463*dee8268fSThierry Reding 464*dee8268fSThierry Reding h_dda = compute_dda_inc(window->src.w, window->dst.w, false, bpp); 465*dee8268fSThierry Reding v_dda = compute_dda_inc(window->src.h, window->dst.h, true, bpp); 466*dee8268fSThierry Reding 467*dee8268fSThierry Reding value = V_DDA_INC(v_dda) | H_DDA_INC(h_dda); 468*dee8268fSThierry Reding tegra_dc_writel(dc, value, DC_WIN_DDA_INC); 469*dee8268fSThierry Reding 470*dee8268fSThierry Reding h_dda = compute_initial_dda(window->src.x); 471*dee8268fSThierry Reding v_dda = compute_initial_dda(window->src.y); 472*dee8268fSThierry Reding 473*dee8268fSThierry Reding tegra_dc_writel(dc, h_dda, DC_WIN_H_INITIAL_DDA); 474*dee8268fSThierry Reding tegra_dc_writel(dc, v_dda, DC_WIN_V_INITIAL_DDA); 475*dee8268fSThierry Reding 476*dee8268fSThierry Reding tegra_dc_writel(dc, 0, DC_WIN_UV_BUF_STRIDE); 477*dee8268fSThierry Reding tegra_dc_writel(dc, 0, DC_WIN_BUF_STRIDE); 478*dee8268fSThierry Reding 479*dee8268fSThierry Reding tegra_dc_writel(dc, window->base[0], DC_WINBUF_START_ADDR); 480*dee8268fSThierry Reding 481*dee8268fSThierry Reding if (yuv && planar) { 482*dee8268fSThierry Reding tegra_dc_writel(dc, window->base[1], DC_WINBUF_START_ADDR_U); 483*dee8268fSThierry Reding tegra_dc_writel(dc, window->base[2], DC_WINBUF_START_ADDR_V); 484*dee8268fSThierry Reding value = window->stride[1] << 16 | window->stride[0]; 485*dee8268fSThierry Reding tegra_dc_writel(dc, value, DC_WIN_LINE_STRIDE); 486*dee8268fSThierry Reding } else { 487*dee8268fSThierry Reding tegra_dc_writel(dc, window->stride[0], DC_WIN_LINE_STRIDE); 488*dee8268fSThierry Reding } 489*dee8268fSThierry Reding 490*dee8268fSThierry Reding tegra_dc_writel(dc, h_offset, DC_WINBUF_ADDR_H_OFFSET); 491*dee8268fSThierry Reding tegra_dc_writel(dc, v_offset, DC_WINBUF_ADDR_V_OFFSET); 492*dee8268fSThierry Reding 493*dee8268fSThierry Reding value = WIN_ENABLE; 494*dee8268fSThierry Reding 495*dee8268fSThierry Reding if (yuv) { 496*dee8268fSThierry Reding /* setup default colorspace conversion coefficients */ 497*dee8268fSThierry Reding tegra_dc_writel(dc, 0x00f0, DC_WIN_CSC_YOF); 498*dee8268fSThierry Reding tegra_dc_writel(dc, 0x012a, DC_WIN_CSC_KYRGB); 499*dee8268fSThierry Reding tegra_dc_writel(dc, 0x0000, DC_WIN_CSC_KUR); 500*dee8268fSThierry Reding tegra_dc_writel(dc, 0x0198, DC_WIN_CSC_KVR); 501*dee8268fSThierry Reding tegra_dc_writel(dc, 0x039b, DC_WIN_CSC_KUG); 502*dee8268fSThierry Reding tegra_dc_writel(dc, 0x032f, DC_WIN_CSC_KVG); 503*dee8268fSThierry Reding tegra_dc_writel(dc, 0x0204, DC_WIN_CSC_KUB); 504*dee8268fSThierry Reding tegra_dc_writel(dc, 0x0000, DC_WIN_CSC_KVB); 505*dee8268fSThierry Reding 506*dee8268fSThierry Reding value |= CSC_ENABLE; 507*dee8268fSThierry Reding } else if (window->bits_per_pixel < 24) { 508*dee8268fSThierry Reding value |= COLOR_EXPAND; 509*dee8268fSThierry Reding } 510*dee8268fSThierry Reding 511*dee8268fSThierry Reding tegra_dc_writel(dc, value, DC_WIN_WIN_OPTIONS); 512*dee8268fSThierry Reding 513*dee8268fSThierry Reding /* 514*dee8268fSThierry Reding * Disable blending and assume Window A is the bottom-most window, 515*dee8268fSThierry Reding * Window C is the top-most window and Window B is in the middle. 516*dee8268fSThierry Reding */ 517*dee8268fSThierry Reding tegra_dc_writel(dc, 0xffff00, DC_WIN_BLEND_NOKEY); 518*dee8268fSThierry Reding tegra_dc_writel(dc, 0xffff00, DC_WIN_BLEND_1WIN); 519*dee8268fSThierry Reding 520*dee8268fSThierry Reding switch (index) { 521*dee8268fSThierry Reding case 0: 522*dee8268fSThierry Reding tegra_dc_writel(dc, 0x000000, DC_WIN_BLEND_2WIN_X); 523*dee8268fSThierry Reding tegra_dc_writel(dc, 0x000000, DC_WIN_BLEND_2WIN_Y); 524*dee8268fSThierry Reding tegra_dc_writel(dc, 0x000000, DC_WIN_BLEND_3WIN_XY); 525*dee8268fSThierry Reding break; 526*dee8268fSThierry Reding 527*dee8268fSThierry Reding case 1: 528*dee8268fSThierry Reding tegra_dc_writel(dc, 0xffff00, DC_WIN_BLEND_2WIN_X); 529*dee8268fSThierry Reding tegra_dc_writel(dc, 0x000000, DC_WIN_BLEND_2WIN_Y); 530*dee8268fSThierry Reding tegra_dc_writel(dc, 0x000000, DC_WIN_BLEND_3WIN_XY); 531*dee8268fSThierry Reding break; 532*dee8268fSThierry Reding 533*dee8268fSThierry Reding case 2: 534*dee8268fSThierry Reding tegra_dc_writel(dc, 0xffff00, DC_WIN_BLEND_2WIN_X); 535*dee8268fSThierry Reding tegra_dc_writel(dc, 0xffff00, DC_WIN_BLEND_2WIN_Y); 536*dee8268fSThierry Reding tegra_dc_writel(dc, 0xffff00, DC_WIN_BLEND_3WIN_XY); 537*dee8268fSThierry Reding break; 538*dee8268fSThierry Reding } 539*dee8268fSThierry Reding 540*dee8268fSThierry Reding tegra_dc_writel(dc, WIN_A_UPDATE << index, DC_CMD_STATE_CONTROL); 541*dee8268fSThierry Reding tegra_dc_writel(dc, WIN_A_ACT_REQ << index, DC_CMD_STATE_CONTROL); 542*dee8268fSThierry Reding 543*dee8268fSThierry Reding return 0; 544*dee8268fSThierry Reding } 545*dee8268fSThierry Reding 546*dee8268fSThierry Reding unsigned int tegra_dc_format(uint32_t format) 547*dee8268fSThierry Reding { 548*dee8268fSThierry Reding switch (format) { 549*dee8268fSThierry Reding case DRM_FORMAT_XBGR8888: 550*dee8268fSThierry Reding return WIN_COLOR_DEPTH_R8G8B8A8; 551*dee8268fSThierry Reding 552*dee8268fSThierry Reding case DRM_FORMAT_XRGB8888: 553*dee8268fSThierry Reding return WIN_COLOR_DEPTH_B8G8R8A8; 554*dee8268fSThierry Reding 555*dee8268fSThierry Reding case DRM_FORMAT_RGB565: 556*dee8268fSThierry Reding return WIN_COLOR_DEPTH_B5G6R5; 557*dee8268fSThierry Reding 558*dee8268fSThierry Reding case DRM_FORMAT_UYVY: 559*dee8268fSThierry Reding return WIN_COLOR_DEPTH_YCbCr422; 560*dee8268fSThierry Reding 561*dee8268fSThierry Reding case DRM_FORMAT_YUV420: 562*dee8268fSThierry Reding return WIN_COLOR_DEPTH_YCbCr420P; 563*dee8268fSThierry Reding 564*dee8268fSThierry Reding case DRM_FORMAT_YUV422: 565*dee8268fSThierry Reding return WIN_COLOR_DEPTH_YCbCr422P; 566*dee8268fSThierry Reding 567*dee8268fSThierry Reding default: 568*dee8268fSThierry Reding break; 569*dee8268fSThierry Reding } 570*dee8268fSThierry Reding 571*dee8268fSThierry Reding WARN(1, "unsupported pixel format %u, using default\n", format); 572*dee8268fSThierry Reding return WIN_COLOR_DEPTH_B8G8R8A8; 573*dee8268fSThierry Reding } 574*dee8268fSThierry Reding 575*dee8268fSThierry Reding static int tegra_crtc_mode_set(struct drm_crtc *crtc, 576*dee8268fSThierry Reding struct drm_display_mode *mode, 577*dee8268fSThierry Reding struct drm_display_mode *adjusted, 578*dee8268fSThierry Reding int x, int y, struct drm_framebuffer *old_fb) 579*dee8268fSThierry Reding { 580*dee8268fSThierry Reding struct tegra_bo *bo = tegra_fb_get_plane(crtc->fb, 0); 581*dee8268fSThierry Reding struct tegra_dc *dc = to_tegra_dc(crtc); 582*dee8268fSThierry Reding struct tegra_dc_window window; 583*dee8268fSThierry Reding unsigned long div, value; 584*dee8268fSThierry Reding int err; 585*dee8268fSThierry Reding 586*dee8268fSThierry Reding drm_vblank_pre_modeset(crtc->dev, dc->pipe); 587*dee8268fSThierry Reding 588*dee8268fSThierry Reding err = tegra_crtc_setup_clk(crtc, mode, &div); 589*dee8268fSThierry Reding if (err) { 590*dee8268fSThierry Reding dev_err(dc->dev, "failed to setup clock for CRTC: %d\n", err); 591*dee8268fSThierry Reding return err; 592*dee8268fSThierry Reding } 593*dee8268fSThierry Reding 594*dee8268fSThierry Reding /* program display mode */ 595*dee8268fSThierry Reding tegra_dc_set_timings(dc, mode); 596*dee8268fSThierry Reding 597*dee8268fSThierry Reding value = DE_SELECT_ACTIVE | DE_CONTROL_NORMAL; 598*dee8268fSThierry Reding tegra_dc_writel(dc, value, DC_DISP_DATA_ENABLE_OPTIONS); 599*dee8268fSThierry Reding 600*dee8268fSThierry Reding value = tegra_dc_readl(dc, DC_COM_PIN_OUTPUT_POLARITY(1)); 601*dee8268fSThierry Reding value &= ~LVS_OUTPUT_POLARITY_LOW; 602*dee8268fSThierry Reding value &= ~LHS_OUTPUT_POLARITY_LOW; 603*dee8268fSThierry Reding tegra_dc_writel(dc, value, DC_COM_PIN_OUTPUT_POLARITY(1)); 604*dee8268fSThierry Reding 605*dee8268fSThierry Reding value = DISP_DATA_FORMAT_DF1P1C | DISP_ALIGNMENT_MSB | 606*dee8268fSThierry Reding DISP_ORDER_RED_BLUE; 607*dee8268fSThierry Reding tegra_dc_writel(dc, value, DC_DISP_DISP_INTERFACE_CONTROL); 608*dee8268fSThierry Reding 609*dee8268fSThierry Reding tegra_dc_writel(dc, 0x00010001, DC_DISP_SHIFT_CLOCK_OPTIONS); 610*dee8268fSThierry Reding 611*dee8268fSThierry Reding value = SHIFT_CLK_DIVIDER(div) | PIXEL_CLK_DIVIDER_PCD1; 612*dee8268fSThierry Reding tegra_dc_writel(dc, value, DC_DISP_DISP_CLOCK_CONTROL); 613*dee8268fSThierry Reding 614*dee8268fSThierry Reding /* setup window parameters */ 615*dee8268fSThierry Reding memset(&window, 0, sizeof(window)); 616*dee8268fSThierry Reding window.src.x = 0; 617*dee8268fSThierry Reding window.src.y = 0; 618*dee8268fSThierry Reding window.src.w = mode->hdisplay; 619*dee8268fSThierry Reding window.src.h = mode->vdisplay; 620*dee8268fSThierry Reding window.dst.x = 0; 621*dee8268fSThierry Reding window.dst.y = 0; 622*dee8268fSThierry Reding window.dst.w = mode->hdisplay; 623*dee8268fSThierry Reding window.dst.h = mode->vdisplay; 624*dee8268fSThierry Reding window.format = tegra_dc_format(crtc->fb->pixel_format); 625*dee8268fSThierry Reding window.bits_per_pixel = crtc->fb->bits_per_pixel; 626*dee8268fSThierry Reding window.stride[0] = crtc->fb->pitches[0]; 627*dee8268fSThierry Reding window.base[0] = bo->paddr; 628*dee8268fSThierry Reding 629*dee8268fSThierry Reding err = tegra_dc_setup_window(dc, 0, &window); 630*dee8268fSThierry Reding if (err < 0) 631*dee8268fSThierry Reding dev_err(dc->dev, "failed to enable root plane\n"); 632*dee8268fSThierry Reding 633*dee8268fSThierry Reding return 0; 634*dee8268fSThierry Reding } 635*dee8268fSThierry Reding 636*dee8268fSThierry Reding static int tegra_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, 637*dee8268fSThierry Reding struct drm_framebuffer *old_fb) 638*dee8268fSThierry Reding { 639*dee8268fSThierry Reding struct tegra_dc *dc = to_tegra_dc(crtc); 640*dee8268fSThierry Reding 641*dee8268fSThierry Reding return tegra_dc_set_base(dc, x, y, crtc->fb); 642*dee8268fSThierry Reding } 643*dee8268fSThierry Reding 644*dee8268fSThierry Reding static void tegra_crtc_prepare(struct drm_crtc *crtc) 645*dee8268fSThierry Reding { 646*dee8268fSThierry Reding struct tegra_dc *dc = to_tegra_dc(crtc); 647*dee8268fSThierry Reding unsigned int syncpt; 648*dee8268fSThierry Reding unsigned long value; 649*dee8268fSThierry Reding 650*dee8268fSThierry Reding /* hardware initialization */ 651*dee8268fSThierry Reding tegra_periph_reset_deassert(dc->clk); 652*dee8268fSThierry Reding usleep_range(10000, 20000); 653*dee8268fSThierry Reding 654*dee8268fSThierry Reding if (dc->pipe) 655*dee8268fSThierry Reding syncpt = SYNCPT_VBLANK1; 656*dee8268fSThierry Reding else 657*dee8268fSThierry Reding syncpt = SYNCPT_VBLANK0; 658*dee8268fSThierry Reding 659*dee8268fSThierry Reding /* initialize display controller */ 660*dee8268fSThierry Reding tegra_dc_writel(dc, 0x00000100, DC_CMD_GENERAL_INCR_SYNCPT_CNTRL); 661*dee8268fSThierry Reding tegra_dc_writel(dc, 0x100 | syncpt, DC_CMD_CONT_SYNCPT_VSYNC); 662*dee8268fSThierry Reding 663*dee8268fSThierry Reding value = WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT | WIN_A_OF_INT; 664*dee8268fSThierry Reding tegra_dc_writel(dc, value, DC_CMD_INT_TYPE); 665*dee8268fSThierry Reding 666*dee8268fSThierry Reding value = WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT | 667*dee8268fSThierry Reding WIN_A_OF_INT | WIN_B_OF_INT | WIN_C_OF_INT; 668*dee8268fSThierry Reding tegra_dc_writel(dc, value, DC_CMD_INT_POLARITY); 669*dee8268fSThierry Reding 670*dee8268fSThierry Reding value = PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE | 671*dee8268fSThierry Reding PW4_ENABLE | PM0_ENABLE | PM1_ENABLE; 672*dee8268fSThierry Reding tegra_dc_writel(dc, value, DC_CMD_DISPLAY_POWER_CONTROL); 673*dee8268fSThierry Reding 674*dee8268fSThierry Reding value = tegra_dc_readl(dc, DC_CMD_DISPLAY_COMMAND); 675*dee8268fSThierry Reding value |= DISP_CTRL_MODE_C_DISPLAY; 676*dee8268fSThierry Reding tegra_dc_writel(dc, value, DC_CMD_DISPLAY_COMMAND); 677*dee8268fSThierry Reding 678*dee8268fSThierry Reding /* initialize timer */ 679*dee8268fSThierry Reding value = CURSOR_THRESHOLD(0) | WINDOW_A_THRESHOLD(0x20) | 680*dee8268fSThierry Reding WINDOW_B_THRESHOLD(0x20) | WINDOW_C_THRESHOLD(0x20); 681*dee8268fSThierry Reding tegra_dc_writel(dc, value, DC_DISP_DISP_MEM_HIGH_PRIORITY); 682*dee8268fSThierry Reding 683*dee8268fSThierry Reding value = CURSOR_THRESHOLD(0) | WINDOW_A_THRESHOLD(1) | 684*dee8268fSThierry Reding WINDOW_B_THRESHOLD(1) | WINDOW_C_THRESHOLD(1); 685*dee8268fSThierry Reding tegra_dc_writel(dc, value, DC_DISP_DISP_MEM_HIGH_PRIORITY_TIMER); 686*dee8268fSThierry Reding 687*dee8268fSThierry Reding value = VBLANK_INT | WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT; 688*dee8268fSThierry Reding tegra_dc_writel(dc, value, DC_CMD_INT_ENABLE); 689*dee8268fSThierry Reding 690*dee8268fSThierry Reding value = WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT; 691*dee8268fSThierry Reding tegra_dc_writel(dc, value, DC_CMD_INT_MASK); 692*dee8268fSThierry Reding } 693*dee8268fSThierry Reding 694*dee8268fSThierry Reding static void tegra_crtc_commit(struct drm_crtc *crtc) 695*dee8268fSThierry Reding { 696*dee8268fSThierry Reding struct tegra_dc *dc = to_tegra_dc(crtc); 697*dee8268fSThierry Reding unsigned long value; 698*dee8268fSThierry Reding 699*dee8268fSThierry Reding value = GENERAL_UPDATE | WIN_A_UPDATE; 700*dee8268fSThierry Reding tegra_dc_writel(dc, value, DC_CMD_STATE_CONTROL); 701*dee8268fSThierry Reding 702*dee8268fSThierry Reding value = GENERAL_ACT_REQ | WIN_A_ACT_REQ; 703*dee8268fSThierry Reding tegra_dc_writel(dc, value, DC_CMD_STATE_CONTROL); 704*dee8268fSThierry Reding 705*dee8268fSThierry Reding drm_vblank_post_modeset(crtc->dev, dc->pipe); 706*dee8268fSThierry Reding } 707*dee8268fSThierry Reding 708*dee8268fSThierry Reding static void tegra_crtc_load_lut(struct drm_crtc *crtc) 709*dee8268fSThierry Reding { 710*dee8268fSThierry Reding } 711*dee8268fSThierry Reding 712*dee8268fSThierry Reding static const struct drm_crtc_helper_funcs tegra_crtc_helper_funcs = { 713*dee8268fSThierry Reding .disable = tegra_crtc_disable, 714*dee8268fSThierry Reding .mode_fixup = tegra_crtc_mode_fixup, 715*dee8268fSThierry Reding .mode_set = tegra_crtc_mode_set, 716*dee8268fSThierry Reding .mode_set_base = tegra_crtc_mode_set_base, 717*dee8268fSThierry Reding .prepare = tegra_crtc_prepare, 718*dee8268fSThierry Reding .commit = tegra_crtc_commit, 719*dee8268fSThierry Reding .load_lut = tegra_crtc_load_lut, 720*dee8268fSThierry Reding }; 721*dee8268fSThierry Reding 722*dee8268fSThierry Reding static irqreturn_t tegra_dc_irq(int irq, void *data) 723*dee8268fSThierry Reding { 724*dee8268fSThierry Reding struct tegra_dc *dc = data; 725*dee8268fSThierry Reding unsigned long status; 726*dee8268fSThierry Reding 727*dee8268fSThierry Reding status = tegra_dc_readl(dc, DC_CMD_INT_STATUS); 728*dee8268fSThierry Reding tegra_dc_writel(dc, status, DC_CMD_INT_STATUS); 729*dee8268fSThierry Reding 730*dee8268fSThierry Reding if (status & FRAME_END_INT) { 731*dee8268fSThierry Reding /* 732*dee8268fSThierry Reding dev_dbg(dc->dev, "%s(): frame end\n", __func__); 733*dee8268fSThierry Reding */ 734*dee8268fSThierry Reding } 735*dee8268fSThierry Reding 736*dee8268fSThierry Reding if (status & VBLANK_INT) { 737*dee8268fSThierry Reding /* 738*dee8268fSThierry Reding dev_dbg(dc->dev, "%s(): vertical blank\n", __func__); 739*dee8268fSThierry Reding */ 740*dee8268fSThierry Reding drm_handle_vblank(dc->base.dev, dc->pipe); 741*dee8268fSThierry Reding tegra_dc_finish_page_flip(dc); 742*dee8268fSThierry Reding } 743*dee8268fSThierry Reding 744*dee8268fSThierry Reding if (status & (WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT)) { 745*dee8268fSThierry Reding /* 746*dee8268fSThierry Reding dev_dbg(dc->dev, "%s(): underflow\n", __func__); 747*dee8268fSThierry Reding */ 748*dee8268fSThierry Reding } 749*dee8268fSThierry Reding 750*dee8268fSThierry Reding return IRQ_HANDLED; 751*dee8268fSThierry Reding } 752*dee8268fSThierry Reding 753*dee8268fSThierry Reding static int tegra_dc_show_regs(struct seq_file *s, void *data) 754*dee8268fSThierry Reding { 755*dee8268fSThierry Reding struct drm_info_node *node = s->private; 756*dee8268fSThierry Reding struct tegra_dc *dc = node->info_ent->data; 757*dee8268fSThierry Reding 758*dee8268fSThierry Reding #define DUMP_REG(name) \ 759*dee8268fSThierry Reding seq_printf(s, "%-40s %#05x %08lx\n", #name, name, \ 760*dee8268fSThierry Reding tegra_dc_readl(dc, name)) 761*dee8268fSThierry Reding 762*dee8268fSThierry Reding DUMP_REG(DC_CMD_GENERAL_INCR_SYNCPT); 763*dee8268fSThierry Reding DUMP_REG(DC_CMD_GENERAL_INCR_SYNCPT_CNTRL); 764*dee8268fSThierry Reding DUMP_REG(DC_CMD_GENERAL_INCR_SYNCPT_ERROR); 765*dee8268fSThierry Reding DUMP_REG(DC_CMD_WIN_A_INCR_SYNCPT); 766*dee8268fSThierry Reding DUMP_REG(DC_CMD_WIN_A_INCR_SYNCPT_CNTRL); 767*dee8268fSThierry Reding DUMP_REG(DC_CMD_WIN_A_INCR_SYNCPT_ERROR); 768*dee8268fSThierry Reding DUMP_REG(DC_CMD_WIN_B_INCR_SYNCPT); 769*dee8268fSThierry Reding DUMP_REG(DC_CMD_WIN_B_INCR_SYNCPT_CNTRL); 770*dee8268fSThierry Reding DUMP_REG(DC_CMD_WIN_B_INCR_SYNCPT_ERROR); 771*dee8268fSThierry Reding DUMP_REG(DC_CMD_WIN_C_INCR_SYNCPT); 772*dee8268fSThierry Reding DUMP_REG(DC_CMD_WIN_C_INCR_SYNCPT_CNTRL); 773*dee8268fSThierry Reding DUMP_REG(DC_CMD_WIN_C_INCR_SYNCPT_ERROR); 774*dee8268fSThierry Reding DUMP_REG(DC_CMD_CONT_SYNCPT_VSYNC); 775*dee8268fSThierry Reding DUMP_REG(DC_CMD_DISPLAY_COMMAND_OPTION0); 776*dee8268fSThierry Reding DUMP_REG(DC_CMD_DISPLAY_COMMAND); 777*dee8268fSThierry Reding DUMP_REG(DC_CMD_SIGNAL_RAISE); 778*dee8268fSThierry Reding DUMP_REG(DC_CMD_DISPLAY_POWER_CONTROL); 779*dee8268fSThierry Reding DUMP_REG(DC_CMD_INT_STATUS); 780*dee8268fSThierry Reding DUMP_REG(DC_CMD_INT_MASK); 781*dee8268fSThierry Reding DUMP_REG(DC_CMD_INT_ENABLE); 782*dee8268fSThierry Reding DUMP_REG(DC_CMD_INT_TYPE); 783*dee8268fSThierry Reding DUMP_REG(DC_CMD_INT_POLARITY); 784*dee8268fSThierry Reding DUMP_REG(DC_CMD_SIGNAL_RAISE1); 785*dee8268fSThierry Reding DUMP_REG(DC_CMD_SIGNAL_RAISE2); 786*dee8268fSThierry Reding DUMP_REG(DC_CMD_SIGNAL_RAISE3); 787*dee8268fSThierry Reding DUMP_REG(DC_CMD_STATE_ACCESS); 788*dee8268fSThierry Reding DUMP_REG(DC_CMD_STATE_CONTROL); 789*dee8268fSThierry Reding DUMP_REG(DC_CMD_DISPLAY_WINDOW_HEADER); 790*dee8268fSThierry Reding DUMP_REG(DC_CMD_REG_ACT_CONTROL); 791*dee8268fSThierry Reding DUMP_REG(DC_COM_CRC_CONTROL); 792*dee8268fSThierry Reding DUMP_REG(DC_COM_CRC_CHECKSUM); 793*dee8268fSThierry Reding DUMP_REG(DC_COM_PIN_OUTPUT_ENABLE(0)); 794*dee8268fSThierry Reding DUMP_REG(DC_COM_PIN_OUTPUT_ENABLE(1)); 795*dee8268fSThierry Reding DUMP_REG(DC_COM_PIN_OUTPUT_ENABLE(2)); 796*dee8268fSThierry Reding DUMP_REG(DC_COM_PIN_OUTPUT_ENABLE(3)); 797*dee8268fSThierry Reding DUMP_REG(DC_COM_PIN_OUTPUT_POLARITY(0)); 798*dee8268fSThierry Reding DUMP_REG(DC_COM_PIN_OUTPUT_POLARITY(1)); 799*dee8268fSThierry Reding DUMP_REG(DC_COM_PIN_OUTPUT_POLARITY(2)); 800*dee8268fSThierry Reding DUMP_REG(DC_COM_PIN_OUTPUT_POLARITY(3)); 801*dee8268fSThierry Reding DUMP_REG(DC_COM_PIN_OUTPUT_DATA(0)); 802*dee8268fSThierry Reding DUMP_REG(DC_COM_PIN_OUTPUT_DATA(1)); 803*dee8268fSThierry Reding DUMP_REG(DC_COM_PIN_OUTPUT_DATA(2)); 804*dee8268fSThierry Reding DUMP_REG(DC_COM_PIN_OUTPUT_DATA(3)); 805*dee8268fSThierry Reding DUMP_REG(DC_COM_PIN_INPUT_ENABLE(0)); 806*dee8268fSThierry Reding DUMP_REG(DC_COM_PIN_INPUT_ENABLE(1)); 807*dee8268fSThierry Reding DUMP_REG(DC_COM_PIN_INPUT_ENABLE(2)); 808*dee8268fSThierry Reding DUMP_REG(DC_COM_PIN_INPUT_ENABLE(3)); 809*dee8268fSThierry Reding DUMP_REG(DC_COM_PIN_INPUT_DATA(0)); 810*dee8268fSThierry Reding DUMP_REG(DC_COM_PIN_INPUT_DATA(1)); 811*dee8268fSThierry Reding DUMP_REG(DC_COM_PIN_OUTPUT_SELECT(0)); 812*dee8268fSThierry Reding DUMP_REG(DC_COM_PIN_OUTPUT_SELECT(1)); 813*dee8268fSThierry Reding DUMP_REG(DC_COM_PIN_OUTPUT_SELECT(2)); 814*dee8268fSThierry Reding DUMP_REG(DC_COM_PIN_OUTPUT_SELECT(3)); 815*dee8268fSThierry Reding DUMP_REG(DC_COM_PIN_OUTPUT_SELECT(4)); 816*dee8268fSThierry Reding DUMP_REG(DC_COM_PIN_OUTPUT_SELECT(5)); 817*dee8268fSThierry Reding DUMP_REG(DC_COM_PIN_OUTPUT_SELECT(6)); 818*dee8268fSThierry Reding DUMP_REG(DC_COM_PIN_MISC_CONTROL); 819*dee8268fSThierry Reding DUMP_REG(DC_COM_PIN_PM0_CONTROL); 820*dee8268fSThierry Reding DUMP_REG(DC_COM_PIN_PM0_DUTY_CYCLE); 821*dee8268fSThierry Reding DUMP_REG(DC_COM_PIN_PM1_CONTROL); 822*dee8268fSThierry Reding DUMP_REG(DC_COM_PIN_PM1_DUTY_CYCLE); 823*dee8268fSThierry Reding DUMP_REG(DC_COM_SPI_CONTROL); 824*dee8268fSThierry Reding DUMP_REG(DC_COM_SPI_START_BYTE); 825*dee8268fSThierry Reding DUMP_REG(DC_COM_HSPI_WRITE_DATA_AB); 826*dee8268fSThierry Reding DUMP_REG(DC_COM_HSPI_WRITE_DATA_CD); 827*dee8268fSThierry Reding DUMP_REG(DC_COM_HSPI_CS_DC); 828*dee8268fSThierry Reding DUMP_REG(DC_COM_SCRATCH_REGISTER_A); 829*dee8268fSThierry Reding DUMP_REG(DC_COM_SCRATCH_REGISTER_B); 830*dee8268fSThierry Reding DUMP_REG(DC_COM_GPIO_CTRL); 831*dee8268fSThierry Reding DUMP_REG(DC_COM_GPIO_DEBOUNCE_COUNTER); 832*dee8268fSThierry Reding DUMP_REG(DC_COM_CRC_CHECKSUM_LATCHED); 833*dee8268fSThierry Reding DUMP_REG(DC_DISP_DISP_SIGNAL_OPTIONS0); 834*dee8268fSThierry Reding DUMP_REG(DC_DISP_DISP_SIGNAL_OPTIONS1); 835*dee8268fSThierry Reding DUMP_REG(DC_DISP_DISP_WIN_OPTIONS); 836*dee8268fSThierry Reding DUMP_REG(DC_DISP_DISP_MEM_HIGH_PRIORITY); 837*dee8268fSThierry Reding DUMP_REG(DC_DISP_DISP_MEM_HIGH_PRIORITY_TIMER); 838*dee8268fSThierry Reding DUMP_REG(DC_DISP_DISP_TIMING_OPTIONS); 839*dee8268fSThierry Reding DUMP_REG(DC_DISP_REF_TO_SYNC); 840*dee8268fSThierry Reding DUMP_REG(DC_DISP_SYNC_WIDTH); 841*dee8268fSThierry Reding DUMP_REG(DC_DISP_BACK_PORCH); 842*dee8268fSThierry Reding DUMP_REG(DC_DISP_ACTIVE); 843*dee8268fSThierry Reding DUMP_REG(DC_DISP_FRONT_PORCH); 844*dee8268fSThierry Reding DUMP_REG(DC_DISP_H_PULSE0_CONTROL); 845*dee8268fSThierry Reding DUMP_REG(DC_DISP_H_PULSE0_POSITION_A); 846*dee8268fSThierry Reding DUMP_REG(DC_DISP_H_PULSE0_POSITION_B); 847*dee8268fSThierry Reding DUMP_REG(DC_DISP_H_PULSE0_POSITION_C); 848*dee8268fSThierry Reding DUMP_REG(DC_DISP_H_PULSE0_POSITION_D); 849*dee8268fSThierry Reding DUMP_REG(DC_DISP_H_PULSE1_CONTROL); 850*dee8268fSThierry Reding DUMP_REG(DC_DISP_H_PULSE1_POSITION_A); 851*dee8268fSThierry Reding DUMP_REG(DC_DISP_H_PULSE1_POSITION_B); 852*dee8268fSThierry Reding DUMP_REG(DC_DISP_H_PULSE1_POSITION_C); 853*dee8268fSThierry Reding DUMP_REG(DC_DISP_H_PULSE1_POSITION_D); 854*dee8268fSThierry Reding DUMP_REG(DC_DISP_H_PULSE2_CONTROL); 855*dee8268fSThierry Reding DUMP_REG(DC_DISP_H_PULSE2_POSITION_A); 856*dee8268fSThierry Reding DUMP_REG(DC_DISP_H_PULSE2_POSITION_B); 857*dee8268fSThierry Reding DUMP_REG(DC_DISP_H_PULSE2_POSITION_C); 858*dee8268fSThierry Reding DUMP_REG(DC_DISP_H_PULSE2_POSITION_D); 859*dee8268fSThierry Reding DUMP_REG(DC_DISP_V_PULSE0_CONTROL); 860*dee8268fSThierry Reding DUMP_REG(DC_DISP_V_PULSE0_POSITION_A); 861*dee8268fSThierry Reding DUMP_REG(DC_DISP_V_PULSE0_POSITION_B); 862*dee8268fSThierry Reding DUMP_REG(DC_DISP_V_PULSE0_POSITION_C); 863*dee8268fSThierry Reding DUMP_REG(DC_DISP_V_PULSE1_CONTROL); 864*dee8268fSThierry Reding DUMP_REG(DC_DISP_V_PULSE1_POSITION_A); 865*dee8268fSThierry Reding DUMP_REG(DC_DISP_V_PULSE1_POSITION_B); 866*dee8268fSThierry Reding DUMP_REG(DC_DISP_V_PULSE1_POSITION_C); 867*dee8268fSThierry Reding DUMP_REG(DC_DISP_V_PULSE2_CONTROL); 868*dee8268fSThierry Reding DUMP_REG(DC_DISP_V_PULSE2_POSITION_A); 869*dee8268fSThierry Reding DUMP_REG(DC_DISP_V_PULSE3_CONTROL); 870*dee8268fSThierry Reding DUMP_REG(DC_DISP_V_PULSE3_POSITION_A); 871*dee8268fSThierry Reding DUMP_REG(DC_DISP_M0_CONTROL); 872*dee8268fSThierry Reding DUMP_REG(DC_DISP_M1_CONTROL); 873*dee8268fSThierry Reding DUMP_REG(DC_DISP_DI_CONTROL); 874*dee8268fSThierry Reding DUMP_REG(DC_DISP_PP_CONTROL); 875*dee8268fSThierry Reding DUMP_REG(DC_DISP_PP_SELECT_A); 876*dee8268fSThierry Reding DUMP_REG(DC_DISP_PP_SELECT_B); 877*dee8268fSThierry Reding DUMP_REG(DC_DISP_PP_SELECT_C); 878*dee8268fSThierry Reding DUMP_REG(DC_DISP_PP_SELECT_D); 879*dee8268fSThierry Reding DUMP_REG(DC_DISP_DISP_CLOCK_CONTROL); 880*dee8268fSThierry Reding DUMP_REG(DC_DISP_DISP_INTERFACE_CONTROL); 881*dee8268fSThierry Reding DUMP_REG(DC_DISP_DISP_COLOR_CONTROL); 882*dee8268fSThierry Reding DUMP_REG(DC_DISP_SHIFT_CLOCK_OPTIONS); 883*dee8268fSThierry Reding DUMP_REG(DC_DISP_DATA_ENABLE_OPTIONS); 884*dee8268fSThierry Reding DUMP_REG(DC_DISP_SERIAL_INTERFACE_OPTIONS); 885*dee8268fSThierry Reding DUMP_REG(DC_DISP_LCD_SPI_OPTIONS); 886*dee8268fSThierry Reding DUMP_REG(DC_DISP_BORDER_COLOR); 887*dee8268fSThierry Reding DUMP_REG(DC_DISP_COLOR_KEY0_LOWER); 888*dee8268fSThierry Reding DUMP_REG(DC_DISP_COLOR_KEY0_UPPER); 889*dee8268fSThierry Reding DUMP_REG(DC_DISP_COLOR_KEY1_LOWER); 890*dee8268fSThierry Reding DUMP_REG(DC_DISP_COLOR_KEY1_UPPER); 891*dee8268fSThierry Reding DUMP_REG(DC_DISP_CURSOR_FOREGROUND); 892*dee8268fSThierry Reding DUMP_REG(DC_DISP_CURSOR_BACKGROUND); 893*dee8268fSThierry Reding DUMP_REG(DC_DISP_CURSOR_START_ADDR); 894*dee8268fSThierry Reding DUMP_REG(DC_DISP_CURSOR_START_ADDR_NS); 895*dee8268fSThierry Reding DUMP_REG(DC_DISP_CURSOR_POSITION); 896*dee8268fSThierry Reding DUMP_REG(DC_DISP_CURSOR_POSITION_NS); 897*dee8268fSThierry Reding DUMP_REG(DC_DISP_INIT_SEQ_CONTROL); 898*dee8268fSThierry Reding DUMP_REG(DC_DISP_SPI_INIT_SEQ_DATA_A); 899*dee8268fSThierry Reding DUMP_REG(DC_DISP_SPI_INIT_SEQ_DATA_B); 900*dee8268fSThierry Reding DUMP_REG(DC_DISP_SPI_INIT_SEQ_DATA_C); 901*dee8268fSThierry Reding DUMP_REG(DC_DISP_SPI_INIT_SEQ_DATA_D); 902*dee8268fSThierry Reding DUMP_REG(DC_DISP_DC_MCCIF_FIFOCTRL); 903*dee8268fSThierry Reding DUMP_REG(DC_DISP_MCCIF_DISPLAY0A_HYST); 904*dee8268fSThierry Reding DUMP_REG(DC_DISP_MCCIF_DISPLAY0B_HYST); 905*dee8268fSThierry Reding DUMP_REG(DC_DISP_MCCIF_DISPLAY1A_HYST); 906*dee8268fSThierry Reding DUMP_REG(DC_DISP_MCCIF_DISPLAY1B_HYST); 907*dee8268fSThierry Reding DUMP_REG(DC_DISP_DAC_CRT_CTRL); 908*dee8268fSThierry Reding DUMP_REG(DC_DISP_DISP_MISC_CONTROL); 909*dee8268fSThierry Reding DUMP_REG(DC_DISP_SD_CONTROL); 910*dee8268fSThierry Reding DUMP_REG(DC_DISP_SD_CSC_COEFF); 911*dee8268fSThierry Reding DUMP_REG(DC_DISP_SD_LUT(0)); 912*dee8268fSThierry Reding DUMP_REG(DC_DISP_SD_LUT(1)); 913*dee8268fSThierry Reding DUMP_REG(DC_DISP_SD_LUT(2)); 914*dee8268fSThierry Reding DUMP_REG(DC_DISP_SD_LUT(3)); 915*dee8268fSThierry Reding DUMP_REG(DC_DISP_SD_LUT(4)); 916*dee8268fSThierry Reding DUMP_REG(DC_DISP_SD_LUT(5)); 917*dee8268fSThierry Reding DUMP_REG(DC_DISP_SD_LUT(6)); 918*dee8268fSThierry Reding DUMP_REG(DC_DISP_SD_LUT(7)); 919*dee8268fSThierry Reding DUMP_REG(DC_DISP_SD_LUT(8)); 920*dee8268fSThierry Reding DUMP_REG(DC_DISP_SD_FLICKER_CONTROL); 921*dee8268fSThierry Reding DUMP_REG(DC_DISP_DC_PIXEL_COUNT); 922*dee8268fSThierry Reding DUMP_REG(DC_DISP_SD_HISTOGRAM(0)); 923*dee8268fSThierry Reding DUMP_REG(DC_DISP_SD_HISTOGRAM(1)); 924*dee8268fSThierry Reding DUMP_REG(DC_DISP_SD_HISTOGRAM(2)); 925*dee8268fSThierry Reding DUMP_REG(DC_DISP_SD_HISTOGRAM(3)); 926*dee8268fSThierry Reding DUMP_REG(DC_DISP_SD_HISTOGRAM(4)); 927*dee8268fSThierry Reding DUMP_REG(DC_DISP_SD_HISTOGRAM(5)); 928*dee8268fSThierry Reding DUMP_REG(DC_DISP_SD_HISTOGRAM(6)); 929*dee8268fSThierry Reding DUMP_REG(DC_DISP_SD_HISTOGRAM(7)); 930*dee8268fSThierry Reding DUMP_REG(DC_DISP_SD_BL_TF(0)); 931*dee8268fSThierry Reding DUMP_REG(DC_DISP_SD_BL_TF(1)); 932*dee8268fSThierry Reding DUMP_REG(DC_DISP_SD_BL_TF(2)); 933*dee8268fSThierry Reding DUMP_REG(DC_DISP_SD_BL_TF(3)); 934*dee8268fSThierry Reding DUMP_REG(DC_DISP_SD_BL_CONTROL); 935*dee8268fSThierry Reding DUMP_REG(DC_DISP_SD_HW_K_VALUES); 936*dee8268fSThierry Reding DUMP_REG(DC_DISP_SD_MAN_K_VALUES); 937*dee8268fSThierry Reding DUMP_REG(DC_WIN_WIN_OPTIONS); 938*dee8268fSThierry Reding DUMP_REG(DC_WIN_BYTE_SWAP); 939*dee8268fSThierry Reding DUMP_REG(DC_WIN_BUFFER_CONTROL); 940*dee8268fSThierry Reding DUMP_REG(DC_WIN_COLOR_DEPTH); 941*dee8268fSThierry Reding DUMP_REG(DC_WIN_POSITION); 942*dee8268fSThierry Reding DUMP_REG(DC_WIN_SIZE); 943*dee8268fSThierry Reding DUMP_REG(DC_WIN_PRESCALED_SIZE); 944*dee8268fSThierry Reding DUMP_REG(DC_WIN_H_INITIAL_DDA); 945*dee8268fSThierry Reding DUMP_REG(DC_WIN_V_INITIAL_DDA); 946*dee8268fSThierry Reding DUMP_REG(DC_WIN_DDA_INC); 947*dee8268fSThierry Reding DUMP_REG(DC_WIN_LINE_STRIDE); 948*dee8268fSThierry Reding DUMP_REG(DC_WIN_BUF_STRIDE); 949*dee8268fSThierry Reding DUMP_REG(DC_WIN_UV_BUF_STRIDE); 950*dee8268fSThierry Reding DUMP_REG(DC_WIN_BUFFER_ADDR_MODE); 951*dee8268fSThierry Reding DUMP_REG(DC_WIN_DV_CONTROL); 952*dee8268fSThierry Reding DUMP_REG(DC_WIN_BLEND_NOKEY); 953*dee8268fSThierry Reding DUMP_REG(DC_WIN_BLEND_1WIN); 954*dee8268fSThierry Reding DUMP_REG(DC_WIN_BLEND_2WIN_X); 955*dee8268fSThierry Reding DUMP_REG(DC_WIN_BLEND_2WIN_Y); 956*dee8268fSThierry Reding DUMP_REG(DC_WIN_BLEND_3WIN_XY); 957*dee8268fSThierry Reding DUMP_REG(DC_WIN_HP_FETCH_CONTROL); 958*dee8268fSThierry Reding DUMP_REG(DC_WINBUF_START_ADDR); 959*dee8268fSThierry Reding DUMP_REG(DC_WINBUF_START_ADDR_NS); 960*dee8268fSThierry Reding DUMP_REG(DC_WINBUF_START_ADDR_U); 961*dee8268fSThierry Reding DUMP_REG(DC_WINBUF_START_ADDR_U_NS); 962*dee8268fSThierry Reding DUMP_REG(DC_WINBUF_START_ADDR_V); 963*dee8268fSThierry Reding DUMP_REG(DC_WINBUF_START_ADDR_V_NS); 964*dee8268fSThierry Reding DUMP_REG(DC_WINBUF_ADDR_H_OFFSET); 965*dee8268fSThierry Reding DUMP_REG(DC_WINBUF_ADDR_H_OFFSET_NS); 966*dee8268fSThierry Reding DUMP_REG(DC_WINBUF_ADDR_V_OFFSET); 967*dee8268fSThierry Reding DUMP_REG(DC_WINBUF_ADDR_V_OFFSET_NS); 968*dee8268fSThierry Reding DUMP_REG(DC_WINBUF_UFLOW_STATUS); 969*dee8268fSThierry Reding DUMP_REG(DC_WINBUF_AD_UFLOW_STATUS); 970*dee8268fSThierry Reding DUMP_REG(DC_WINBUF_BD_UFLOW_STATUS); 971*dee8268fSThierry Reding DUMP_REG(DC_WINBUF_CD_UFLOW_STATUS); 972*dee8268fSThierry Reding 973*dee8268fSThierry Reding #undef DUMP_REG 974*dee8268fSThierry Reding 975*dee8268fSThierry Reding return 0; 976*dee8268fSThierry Reding } 977*dee8268fSThierry Reding 978*dee8268fSThierry Reding static struct drm_info_list debugfs_files[] = { 979*dee8268fSThierry Reding { "regs", tegra_dc_show_regs, 0, NULL }, 980*dee8268fSThierry Reding }; 981*dee8268fSThierry Reding 982*dee8268fSThierry Reding static int tegra_dc_debugfs_init(struct tegra_dc *dc, struct drm_minor *minor) 983*dee8268fSThierry Reding { 984*dee8268fSThierry Reding unsigned int i; 985*dee8268fSThierry Reding char *name; 986*dee8268fSThierry Reding int err; 987*dee8268fSThierry Reding 988*dee8268fSThierry Reding name = kasprintf(GFP_KERNEL, "dc.%d", dc->pipe); 989*dee8268fSThierry Reding dc->debugfs = debugfs_create_dir(name, minor->debugfs_root); 990*dee8268fSThierry Reding kfree(name); 991*dee8268fSThierry Reding 992*dee8268fSThierry Reding if (!dc->debugfs) 993*dee8268fSThierry Reding return -ENOMEM; 994*dee8268fSThierry Reding 995*dee8268fSThierry Reding dc->debugfs_files = kmemdup(debugfs_files, sizeof(debugfs_files), 996*dee8268fSThierry Reding GFP_KERNEL); 997*dee8268fSThierry Reding if (!dc->debugfs_files) { 998*dee8268fSThierry Reding err = -ENOMEM; 999*dee8268fSThierry Reding goto remove; 1000*dee8268fSThierry Reding } 1001*dee8268fSThierry Reding 1002*dee8268fSThierry Reding for (i = 0; i < ARRAY_SIZE(debugfs_files); i++) 1003*dee8268fSThierry Reding dc->debugfs_files[i].data = dc; 1004*dee8268fSThierry Reding 1005*dee8268fSThierry Reding err = drm_debugfs_create_files(dc->debugfs_files, 1006*dee8268fSThierry Reding ARRAY_SIZE(debugfs_files), 1007*dee8268fSThierry Reding dc->debugfs, minor); 1008*dee8268fSThierry Reding if (err < 0) 1009*dee8268fSThierry Reding goto free; 1010*dee8268fSThierry Reding 1011*dee8268fSThierry Reding dc->minor = minor; 1012*dee8268fSThierry Reding 1013*dee8268fSThierry Reding return 0; 1014*dee8268fSThierry Reding 1015*dee8268fSThierry Reding free: 1016*dee8268fSThierry Reding kfree(dc->debugfs_files); 1017*dee8268fSThierry Reding dc->debugfs_files = NULL; 1018*dee8268fSThierry Reding remove: 1019*dee8268fSThierry Reding debugfs_remove(dc->debugfs); 1020*dee8268fSThierry Reding dc->debugfs = NULL; 1021*dee8268fSThierry Reding 1022*dee8268fSThierry Reding return err; 1023*dee8268fSThierry Reding } 1024*dee8268fSThierry Reding 1025*dee8268fSThierry Reding static int tegra_dc_debugfs_exit(struct tegra_dc *dc) 1026*dee8268fSThierry Reding { 1027*dee8268fSThierry Reding drm_debugfs_remove_files(dc->debugfs_files, ARRAY_SIZE(debugfs_files), 1028*dee8268fSThierry Reding dc->minor); 1029*dee8268fSThierry Reding dc->minor = NULL; 1030*dee8268fSThierry Reding 1031*dee8268fSThierry Reding kfree(dc->debugfs_files); 1032*dee8268fSThierry Reding dc->debugfs_files = NULL; 1033*dee8268fSThierry Reding 1034*dee8268fSThierry Reding debugfs_remove(dc->debugfs); 1035*dee8268fSThierry Reding dc->debugfs = NULL; 1036*dee8268fSThierry Reding 1037*dee8268fSThierry Reding return 0; 1038*dee8268fSThierry Reding } 1039*dee8268fSThierry Reding 1040*dee8268fSThierry Reding static int tegra_dc_init(struct host1x_client *client) 1041*dee8268fSThierry Reding { 1042*dee8268fSThierry Reding struct tegra_drm *tegra = dev_get_drvdata(client->parent); 1043*dee8268fSThierry Reding struct tegra_dc *dc = host1x_client_to_dc(client); 1044*dee8268fSThierry Reding int err; 1045*dee8268fSThierry Reding 1046*dee8268fSThierry Reding dc->pipe = tegra->drm->mode_config.num_crtc; 1047*dee8268fSThierry Reding 1048*dee8268fSThierry Reding drm_crtc_init(tegra->drm, &dc->base, &tegra_crtc_funcs); 1049*dee8268fSThierry Reding drm_mode_crtc_set_gamma_size(&dc->base, 256); 1050*dee8268fSThierry Reding drm_crtc_helper_add(&dc->base, &tegra_crtc_helper_funcs); 1051*dee8268fSThierry Reding 1052*dee8268fSThierry Reding err = tegra_dc_rgb_init(tegra->drm, dc); 1053*dee8268fSThierry Reding if (err < 0 && err != -ENODEV) { 1054*dee8268fSThierry Reding dev_err(dc->dev, "failed to initialize RGB output: %d\n", err); 1055*dee8268fSThierry Reding return err; 1056*dee8268fSThierry Reding } 1057*dee8268fSThierry Reding 1058*dee8268fSThierry Reding err = tegra_dc_add_planes(tegra->drm, dc); 1059*dee8268fSThierry Reding if (err < 0) 1060*dee8268fSThierry Reding return err; 1061*dee8268fSThierry Reding 1062*dee8268fSThierry Reding if (IS_ENABLED(CONFIG_DEBUG_FS)) { 1063*dee8268fSThierry Reding err = tegra_dc_debugfs_init(dc, tegra->drm->primary); 1064*dee8268fSThierry Reding if (err < 0) 1065*dee8268fSThierry Reding dev_err(dc->dev, "debugfs setup failed: %d\n", err); 1066*dee8268fSThierry Reding } 1067*dee8268fSThierry Reding 1068*dee8268fSThierry Reding err = devm_request_irq(dc->dev, dc->irq, tegra_dc_irq, 0, 1069*dee8268fSThierry Reding dev_name(dc->dev), dc); 1070*dee8268fSThierry Reding if (err < 0) { 1071*dee8268fSThierry Reding dev_err(dc->dev, "failed to request IRQ#%u: %d\n", dc->irq, 1072*dee8268fSThierry Reding err); 1073*dee8268fSThierry Reding return err; 1074*dee8268fSThierry Reding } 1075*dee8268fSThierry Reding 1076*dee8268fSThierry Reding return 0; 1077*dee8268fSThierry Reding } 1078*dee8268fSThierry Reding 1079*dee8268fSThierry Reding static int tegra_dc_exit(struct host1x_client *client) 1080*dee8268fSThierry Reding { 1081*dee8268fSThierry Reding struct tegra_dc *dc = host1x_client_to_dc(client); 1082*dee8268fSThierry Reding int err; 1083*dee8268fSThierry Reding 1084*dee8268fSThierry Reding devm_free_irq(dc->dev, dc->irq, dc); 1085*dee8268fSThierry Reding 1086*dee8268fSThierry Reding if (IS_ENABLED(CONFIG_DEBUG_FS)) { 1087*dee8268fSThierry Reding err = tegra_dc_debugfs_exit(dc); 1088*dee8268fSThierry Reding if (err < 0) 1089*dee8268fSThierry Reding dev_err(dc->dev, "debugfs cleanup failed: %d\n", err); 1090*dee8268fSThierry Reding } 1091*dee8268fSThierry Reding 1092*dee8268fSThierry Reding err = tegra_dc_rgb_exit(dc); 1093*dee8268fSThierry Reding if (err) { 1094*dee8268fSThierry Reding dev_err(dc->dev, "failed to shutdown RGB output: %d\n", err); 1095*dee8268fSThierry Reding return err; 1096*dee8268fSThierry Reding } 1097*dee8268fSThierry Reding 1098*dee8268fSThierry Reding return 0; 1099*dee8268fSThierry Reding } 1100*dee8268fSThierry Reding 1101*dee8268fSThierry Reding static const struct host1x_client_ops dc_client_ops = { 1102*dee8268fSThierry Reding .init = tegra_dc_init, 1103*dee8268fSThierry Reding .exit = tegra_dc_exit, 1104*dee8268fSThierry Reding }; 1105*dee8268fSThierry Reding 1106*dee8268fSThierry Reding static int tegra_dc_probe(struct platform_device *pdev) 1107*dee8268fSThierry Reding { 1108*dee8268fSThierry Reding struct resource *regs; 1109*dee8268fSThierry Reding struct tegra_dc *dc; 1110*dee8268fSThierry Reding int err; 1111*dee8268fSThierry Reding 1112*dee8268fSThierry Reding dc = devm_kzalloc(&pdev->dev, sizeof(*dc), GFP_KERNEL); 1113*dee8268fSThierry Reding if (!dc) 1114*dee8268fSThierry Reding return -ENOMEM; 1115*dee8268fSThierry Reding 1116*dee8268fSThierry Reding spin_lock_init(&dc->lock); 1117*dee8268fSThierry Reding INIT_LIST_HEAD(&dc->list); 1118*dee8268fSThierry Reding dc->dev = &pdev->dev; 1119*dee8268fSThierry Reding 1120*dee8268fSThierry Reding dc->clk = devm_clk_get(&pdev->dev, NULL); 1121*dee8268fSThierry Reding if (IS_ERR(dc->clk)) { 1122*dee8268fSThierry Reding dev_err(&pdev->dev, "failed to get clock\n"); 1123*dee8268fSThierry Reding return PTR_ERR(dc->clk); 1124*dee8268fSThierry Reding } 1125*dee8268fSThierry Reding 1126*dee8268fSThierry Reding err = clk_prepare_enable(dc->clk); 1127*dee8268fSThierry Reding if (err < 0) 1128*dee8268fSThierry Reding return err; 1129*dee8268fSThierry Reding 1130*dee8268fSThierry Reding regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); 1131*dee8268fSThierry Reding dc->regs = devm_ioremap_resource(&pdev->dev, regs); 1132*dee8268fSThierry Reding if (IS_ERR(dc->regs)) 1133*dee8268fSThierry Reding return PTR_ERR(dc->regs); 1134*dee8268fSThierry Reding 1135*dee8268fSThierry Reding dc->irq = platform_get_irq(pdev, 0); 1136*dee8268fSThierry Reding if (dc->irq < 0) { 1137*dee8268fSThierry Reding dev_err(&pdev->dev, "failed to get IRQ\n"); 1138*dee8268fSThierry Reding return -ENXIO; 1139*dee8268fSThierry Reding } 1140*dee8268fSThierry Reding 1141*dee8268fSThierry Reding INIT_LIST_HEAD(&dc->client.list); 1142*dee8268fSThierry Reding dc->client.ops = &dc_client_ops; 1143*dee8268fSThierry Reding dc->client.dev = &pdev->dev; 1144*dee8268fSThierry Reding 1145*dee8268fSThierry Reding err = tegra_dc_rgb_probe(dc); 1146*dee8268fSThierry Reding if (err < 0 && err != -ENODEV) { 1147*dee8268fSThierry Reding dev_err(&pdev->dev, "failed to probe RGB output: %d\n", err); 1148*dee8268fSThierry Reding return err; 1149*dee8268fSThierry Reding } 1150*dee8268fSThierry Reding 1151*dee8268fSThierry Reding err = host1x_client_register(&dc->client); 1152*dee8268fSThierry Reding if (err < 0) { 1153*dee8268fSThierry Reding dev_err(&pdev->dev, "failed to register host1x client: %d\n", 1154*dee8268fSThierry Reding err); 1155*dee8268fSThierry Reding return err; 1156*dee8268fSThierry Reding } 1157*dee8268fSThierry Reding 1158*dee8268fSThierry Reding platform_set_drvdata(pdev, dc); 1159*dee8268fSThierry Reding 1160*dee8268fSThierry Reding return 0; 1161*dee8268fSThierry Reding } 1162*dee8268fSThierry Reding 1163*dee8268fSThierry Reding static int tegra_dc_remove(struct platform_device *pdev) 1164*dee8268fSThierry Reding { 1165*dee8268fSThierry Reding struct tegra_dc *dc = platform_get_drvdata(pdev); 1166*dee8268fSThierry Reding int err; 1167*dee8268fSThierry Reding 1168*dee8268fSThierry Reding err = host1x_client_unregister(&dc->client); 1169*dee8268fSThierry Reding if (err < 0) { 1170*dee8268fSThierry Reding dev_err(&pdev->dev, "failed to unregister host1x client: %d\n", 1171*dee8268fSThierry Reding err); 1172*dee8268fSThierry Reding return err; 1173*dee8268fSThierry Reding } 1174*dee8268fSThierry Reding 1175*dee8268fSThierry Reding clk_disable_unprepare(dc->clk); 1176*dee8268fSThierry Reding 1177*dee8268fSThierry Reding return 0; 1178*dee8268fSThierry Reding } 1179*dee8268fSThierry Reding 1180*dee8268fSThierry Reding static struct of_device_id tegra_dc_of_match[] = { 1181*dee8268fSThierry Reding { .compatible = "nvidia,tegra30-dc", }, 1182*dee8268fSThierry Reding { .compatible = "nvidia,tegra20-dc", }, 1183*dee8268fSThierry Reding { }, 1184*dee8268fSThierry Reding }; 1185*dee8268fSThierry Reding 1186*dee8268fSThierry Reding struct platform_driver tegra_dc_driver = { 1187*dee8268fSThierry Reding .driver = { 1188*dee8268fSThierry Reding .name = "tegra-dc", 1189*dee8268fSThierry Reding .owner = THIS_MODULE, 1190*dee8268fSThierry Reding .of_match_table = tegra_dc_of_match, 1191*dee8268fSThierry Reding }, 1192*dee8268fSThierry Reding .probe = tegra_dc_probe, 1193*dee8268fSThierry Reding .remove = tegra_dc_remove, 1194*dee8268fSThierry Reding }; 1195