1*96f60e37SRussell King /* 2*96f60e37SRussell King * Copyright (C) 2012 Russell King 3*96f60e37SRussell King * Rewritten from the dovefb driver, and Armada510 manuals. 4*96f60e37SRussell King * 5*96f60e37SRussell King * This program is free software; you can redistribute it and/or modify 6*96f60e37SRussell King * it under the terms of the GNU General Public License version 2 as 7*96f60e37SRussell King * published by the Free Software Foundation. 8*96f60e37SRussell King */ 9*96f60e37SRussell King #include <linux/clk.h> 10*96f60e37SRussell King #include <drm/drmP.h> 11*96f60e37SRussell King #include <drm/drm_crtc_helper.h> 12*96f60e37SRussell King #include "armada_crtc.h" 13*96f60e37SRussell King #include "armada_drm.h" 14*96f60e37SRussell King #include "armada_fb.h" 15*96f60e37SRussell King #include "armada_gem.h" 16*96f60e37SRussell King #include "armada_hw.h" 17*96f60e37SRussell King 18*96f60e37SRussell King struct armada_frame_work { 19*96f60e37SRussell King struct drm_pending_vblank_event *event; 20*96f60e37SRussell King struct armada_regs regs[4]; 21*96f60e37SRussell King struct drm_framebuffer *old_fb; 22*96f60e37SRussell King }; 23*96f60e37SRussell King 24*96f60e37SRussell King enum csc_mode { 25*96f60e37SRussell King CSC_AUTO = 0, 26*96f60e37SRussell King CSC_YUV_CCIR601 = 1, 27*96f60e37SRussell King CSC_YUV_CCIR709 = 2, 28*96f60e37SRussell King CSC_RGB_COMPUTER = 1, 29*96f60e37SRussell King CSC_RGB_STUDIO = 2, 30*96f60e37SRussell King }; 31*96f60e37SRussell King 32*96f60e37SRussell King /* 33*96f60e37SRussell King * A note about interlacing. Let's consider HDMI 1920x1080i. 34*96f60e37SRussell King * The timing parameters we have from X are: 35*96f60e37SRussell King * Hact HsyA HsyI Htot Vact VsyA VsyI Vtot 36*96f60e37SRussell King * 1920 2448 2492 2640 1080 1084 1094 1125 37*96f60e37SRussell King * Which get translated to: 38*96f60e37SRussell King * Hact HsyA HsyI Htot Vact VsyA VsyI Vtot 39*96f60e37SRussell King * 1920 2448 2492 2640 540 542 547 562 40*96f60e37SRussell King * 41*96f60e37SRussell King * This is how it is defined by CEA-861-D - line and pixel numbers are 42*96f60e37SRussell King * referenced to the rising edge of VSYNC and HSYNC. Total clocks per 43*96f60e37SRussell King * line: 2640. The odd frame, the first active line is at line 21, and 44*96f60e37SRussell King * the even frame, the first active line is 584. 45*96f60e37SRussell King * 46*96f60e37SRussell King * LN: 560 561 562 563 567 568 569 47*96f60e37SRussell King * DE: ~~~|____________________________//__________________________ 48*96f60e37SRussell King * HSYNC: ____|~|_____|~|_____|~|_____|~|_//__|~|_____|~|_____|~|_____ 49*96f60e37SRussell King * VSYNC: _________________________|~~~~~~//~~~~~~~~~~~~~~~|__________ 50*96f60e37SRussell King * 22 blanking lines. VSYNC at 1320 (referenced to the HSYNC rising edge). 51*96f60e37SRussell King * 52*96f60e37SRussell King * LN: 1123 1124 1125 1 5 6 7 53*96f60e37SRussell King * DE: ~~~|____________________________//__________________________ 54*96f60e37SRussell King * HSYNC: ____|~|_____|~|_____|~|_____|~|_//__|~|_____|~|_____|~|_____ 55*96f60e37SRussell King * VSYNC: ____________________|~~~~~~~~~~~//~~~~~~~~~~|_______________ 56*96f60e37SRussell King * 23 blanking lines 57*96f60e37SRussell King * 58*96f60e37SRussell King * The Armada LCD Controller line and pixel numbers are, like X timings, 59*96f60e37SRussell King * referenced to the top left of the active frame. 60*96f60e37SRussell King * 61*96f60e37SRussell King * So, translating these to our LCD controller: 62*96f60e37SRussell King * Odd frame, 563 total lines, VSYNC at line 543-548, pixel 1128. 63*96f60e37SRussell King * Even frame, 562 total lines, VSYNC at line 542-547, pixel 2448. 64*96f60e37SRussell King * Note: Vsync front porch remains constant! 65*96f60e37SRussell King * 66*96f60e37SRussell King * if (odd_frame) { 67*96f60e37SRussell King * vtotal = mode->crtc_vtotal + 1; 68*96f60e37SRussell King * vbackporch = mode->crtc_vsync_start - mode->crtc_vdisplay + 1; 69*96f60e37SRussell King * vhorizpos = mode->crtc_hsync_start - mode->crtc_htotal / 2 70*96f60e37SRussell King * } else { 71*96f60e37SRussell King * vtotal = mode->crtc_vtotal; 72*96f60e37SRussell King * vbackporch = mode->crtc_vsync_start - mode->crtc_vdisplay; 73*96f60e37SRussell King * vhorizpos = mode->crtc_hsync_start; 74*96f60e37SRussell King * } 75*96f60e37SRussell King * vfrontporch = mode->crtc_vtotal - mode->crtc_vsync_end; 76*96f60e37SRussell King * 77*96f60e37SRussell King * So, we need to reprogram these registers on each vsync event: 78*96f60e37SRussell King * LCD_SPU_V_PORCH, LCD_SPU_ADV_REG, LCD_SPUT_V_H_TOTAL 79*96f60e37SRussell King * 80*96f60e37SRussell King * Note: we do not use the frame done interrupts because these appear 81*96f60e37SRussell King * to happen too early, and lead to jitter on the display (presumably 82*96f60e37SRussell King * they occur at the end of the last active line, before the vsync back 83*96f60e37SRussell King * porch, which we're reprogramming.) 84*96f60e37SRussell King */ 85*96f60e37SRussell King 86*96f60e37SRussell King void 87*96f60e37SRussell King armada_drm_crtc_update_regs(struct armada_crtc *dcrtc, struct armada_regs *regs) 88*96f60e37SRussell King { 89*96f60e37SRussell King while (regs->offset != ~0) { 90*96f60e37SRussell King void __iomem *reg = dcrtc->base + regs->offset; 91*96f60e37SRussell King uint32_t val; 92*96f60e37SRussell King 93*96f60e37SRussell King val = regs->mask; 94*96f60e37SRussell King if (val != 0) 95*96f60e37SRussell King val &= readl_relaxed(reg); 96*96f60e37SRussell King writel_relaxed(val | regs->val, reg); 97*96f60e37SRussell King ++regs; 98*96f60e37SRussell King } 99*96f60e37SRussell King } 100*96f60e37SRussell King 101*96f60e37SRussell King #define dpms_blanked(dpms) ((dpms) != DRM_MODE_DPMS_ON) 102*96f60e37SRussell King 103*96f60e37SRussell King static void armada_drm_crtc_update(struct armada_crtc *dcrtc) 104*96f60e37SRussell King { 105*96f60e37SRussell King uint32_t dumb_ctrl; 106*96f60e37SRussell King 107*96f60e37SRussell King dumb_ctrl = dcrtc->cfg_dumb_ctrl; 108*96f60e37SRussell King 109*96f60e37SRussell King if (!dpms_blanked(dcrtc->dpms)) 110*96f60e37SRussell King dumb_ctrl |= CFG_DUMB_ENA; 111*96f60e37SRussell King 112*96f60e37SRussell King /* 113*96f60e37SRussell King * When the dumb interface isn't in DUMB24_RGB888_0 mode, it might 114*96f60e37SRussell King * be using SPI or GPIO. If we set this to DUMB_BLANK, we will 115*96f60e37SRussell King * force LCD_D[23:0] to output blank color, overriding the GPIO or 116*96f60e37SRussell King * SPI usage. So leave it as-is unless in DUMB24_RGB888_0 mode. 117*96f60e37SRussell King */ 118*96f60e37SRussell King if (dpms_blanked(dcrtc->dpms) && 119*96f60e37SRussell King (dumb_ctrl & DUMB_MASK) == DUMB24_RGB888_0) { 120*96f60e37SRussell King dumb_ctrl &= ~DUMB_MASK; 121*96f60e37SRussell King dumb_ctrl |= DUMB_BLANK; 122*96f60e37SRussell King } 123*96f60e37SRussell King 124*96f60e37SRussell King /* 125*96f60e37SRussell King * The documentation doesn't indicate what the normal state of 126*96f60e37SRussell King * the sync signals are. Sebastian Hesselbart kindly probed 127*96f60e37SRussell King * these signals on his board to determine their state. 128*96f60e37SRussell King * 129*96f60e37SRussell King * The non-inverted state of the sync signals is active high. 130*96f60e37SRussell King * Setting these bits makes the appropriate signal active low. 131*96f60e37SRussell King */ 132*96f60e37SRussell King if (dcrtc->crtc.mode.flags & DRM_MODE_FLAG_NCSYNC) 133*96f60e37SRussell King dumb_ctrl |= CFG_INV_CSYNC; 134*96f60e37SRussell King if (dcrtc->crtc.mode.flags & DRM_MODE_FLAG_NHSYNC) 135*96f60e37SRussell King dumb_ctrl |= CFG_INV_HSYNC; 136*96f60e37SRussell King if (dcrtc->crtc.mode.flags & DRM_MODE_FLAG_NVSYNC) 137*96f60e37SRussell King dumb_ctrl |= CFG_INV_VSYNC; 138*96f60e37SRussell King 139*96f60e37SRussell King if (dcrtc->dumb_ctrl != dumb_ctrl) { 140*96f60e37SRussell King dcrtc->dumb_ctrl = dumb_ctrl; 141*96f60e37SRussell King writel_relaxed(dumb_ctrl, dcrtc->base + LCD_SPU_DUMB_CTRL); 142*96f60e37SRussell King } 143*96f60e37SRussell King } 144*96f60e37SRussell King 145*96f60e37SRussell King static unsigned armada_drm_crtc_calc_fb(struct drm_framebuffer *fb, 146*96f60e37SRussell King int x, int y, struct armada_regs *regs, bool interlaced) 147*96f60e37SRussell King { 148*96f60e37SRussell King struct armada_gem_object *obj = drm_fb_obj(fb); 149*96f60e37SRussell King unsigned pitch = fb->pitches[0]; 150*96f60e37SRussell King unsigned offset = y * pitch + x * fb->bits_per_pixel / 8; 151*96f60e37SRussell King uint32_t addr_odd, addr_even; 152*96f60e37SRussell King unsigned i = 0; 153*96f60e37SRussell King 154*96f60e37SRussell King DRM_DEBUG_DRIVER("pitch %u x %d y %d bpp %d\n", 155*96f60e37SRussell King pitch, x, y, fb->bits_per_pixel); 156*96f60e37SRussell King 157*96f60e37SRussell King addr_odd = addr_even = obj->dev_addr + offset; 158*96f60e37SRussell King 159*96f60e37SRussell King if (interlaced) { 160*96f60e37SRussell King addr_even += pitch; 161*96f60e37SRussell King pitch *= 2; 162*96f60e37SRussell King } 163*96f60e37SRussell King 164*96f60e37SRussell King /* write offset, base, and pitch */ 165*96f60e37SRussell King armada_reg_queue_set(regs, i, addr_odd, LCD_CFG_GRA_START_ADDR0); 166*96f60e37SRussell King armada_reg_queue_set(regs, i, addr_even, LCD_CFG_GRA_START_ADDR1); 167*96f60e37SRussell King armada_reg_queue_mod(regs, i, pitch, 0xffff, LCD_CFG_GRA_PITCH); 168*96f60e37SRussell King 169*96f60e37SRussell King return i; 170*96f60e37SRussell King } 171*96f60e37SRussell King 172*96f60e37SRussell King static int armada_drm_crtc_queue_frame_work(struct armada_crtc *dcrtc, 173*96f60e37SRussell King struct armada_frame_work *work) 174*96f60e37SRussell King { 175*96f60e37SRussell King struct drm_device *dev = dcrtc->crtc.dev; 176*96f60e37SRussell King unsigned long flags; 177*96f60e37SRussell King int ret; 178*96f60e37SRussell King 179*96f60e37SRussell King ret = drm_vblank_get(dev, dcrtc->num); 180*96f60e37SRussell King if (ret) { 181*96f60e37SRussell King DRM_ERROR("failed to acquire vblank counter\n"); 182*96f60e37SRussell King return ret; 183*96f60e37SRussell King } 184*96f60e37SRussell King 185*96f60e37SRussell King spin_lock_irqsave(&dev->event_lock, flags); 186*96f60e37SRussell King if (!dcrtc->frame_work) 187*96f60e37SRussell King dcrtc->frame_work = work; 188*96f60e37SRussell King else 189*96f60e37SRussell King ret = -EBUSY; 190*96f60e37SRussell King spin_unlock_irqrestore(&dev->event_lock, flags); 191*96f60e37SRussell King 192*96f60e37SRussell King if (ret) 193*96f60e37SRussell King drm_vblank_put(dev, dcrtc->num); 194*96f60e37SRussell King 195*96f60e37SRussell King return ret; 196*96f60e37SRussell King } 197*96f60e37SRussell King 198*96f60e37SRussell King static void armada_drm_crtc_complete_frame_work(struct armada_crtc *dcrtc) 199*96f60e37SRussell King { 200*96f60e37SRussell King struct drm_device *dev = dcrtc->crtc.dev; 201*96f60e37SRussell King struct armada_frame_work *work = dcrtc->frame_work; 202*96f60e37SRussell King 203*96f60e37SRussell King dcrtc->frame_work = NULL; 204*96f60e37SRussell King 205*96f60e37SRussell King armada_drm_crtc_update_regs(dcrtc, work->regs); 206*96f60e37SRussell King 207*96f60e37SRussell King if (work->event) 208*96f60e37SRussell King drm_send_vblank_event(dev, dcrtc->num, work->event); 209*96f60e37SRussell King 210*96f60e37SRussell King drm_vblank_put(dev, dcrtc->num); 211*96f60e37SRussell King 212*96f60e37SRussell King /* Finally, queue the process-half of the cleanup. */ 213*96f60e37SRussell King __armada_drm_queue_unref_work(dcrtc->crtc.dev, work->old_fb); 214*96f60e37SRussell King kfree(work); 215*96f60e37SRussell King } 216*96f60e37SRussell King 217*96f60e37SRussell King static void armada_drm_crtc_finish_fb(struct armada_crtc *dcrtc, 218*96f60e37SRussell King struct drm_framebuffer *fb, bool force) 219*96f60e37SRussell King { 220*96f60e37SRussell King struct armada_frame_work *work; 221*96f60e37SRussell King 222*96f60e37SRussell King if (!fb) 223*96f60e37SRussell King return; 224*96f60e37SRussell King 225*96f60e37SRussell King if (force) { 226*96f60e37SRussell King /* Display is disabled, so just drop the old fb */ 227*96f60e37SRussell King drm_framebuffer_unreference(fb); 228*96f60e37SRussell King return; 229*96f60e37SRussell King } 230*96f60e37SRussell King 231*96f60e37SRussell King work = kmalloc(sizeof(*work), GFP_KERNEL); 232*96f60e37SRussell King if (work) { 233*96f60e37SRussell King int i = 0; 234*96f60e37SRussell King work->event = NULL; 235*96f60e37SRussell King work->old_fb = fb; 236*96f60e37SRussell King armada_reg_queue_end(work->regs, i); 237*96f60e37SRussell King 238*96f60e37SRussell King if (armada_drm_crtc_queue_frame_work(dcrtc, work) == 0) 239*96f60e37SRussell King return; 240*96f60e37SRussell King 241*96f60e37SRussell King kfree(work); 242*96f60e37SRussell King } 243*96f60e37SRussell King 244*96f60e37SRussell King /* 245*96f60e37SRussell King * Oops - just drop the reference immediately and hope for 246*96f60e37SRussell King * the best. The worst that will happen is the buffer gets 247*96f60e37SRussell King * reused before it has finished being displayed. 248*96f60e37SRussell King */ 249*96f60e37SRussell King drm_framebuffer_unreference(fb); 250*96f60e37SRussell King } 251*96f60e37SRussell King 252*96f60e37SRussell King static void armada_drm_vblank_off(struct armada_crtc *dcrtc) 253*96f60e37SRussell King { 254*96f60e37SRussell King struct drm_device *dev = dcrtc->crtc.dev; 255*96f60e37SRussell King 256*96f60e37SRussell King /* 257*96f60e37SRussell King * Tell the DRM core that vblank IRQs aren't going to happen for 258*96f60e37SRussell King * a while. This cleans up any pending vblank events for us. 259*96f60e37SRussell King */ 260*96f60e37SRussell King drm_vblank_off(dev, dcrtc->num); 261*96f60e37SRussell King 262*96f60e37SRussell King /* Handle any pending flip event. */ 263*96f60e37SRussell King spin_lock_irq(&dev->event_lock); 264*96f60e37SRussell King if (dcrtc->frame_work) 265*96f60e37SRussell King armada_drm_crtc_complete_frame_work(dcrtc); 266*96f60e37SRussell King spin_unlock_irq(&dev->event_lock); 267*96f60e37SRussell King } 268*96f60e37SRussell King 269*96f60e37SRussell King void armada_drm_crtc_gamma_set(struct drm_crtc *crtc, u16 r, u16 g, u16 b, 270*96f60e37SRussell King int idx) 271*96f60e37SRussell King { 272*96f60e37SRussell King } 273*96f60e37SRussell King 274*96f60e37SRussell King void armada_drm_crtc_gamma_get(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b, 275*96f60e37SRussell King int idx) 276*96f60e37SRussell King { 277*96f60e37SRussell King } 278*96f60e37SRussell King 279*96f60e37SRussell King /* The mode_config.mutex will be held for this call */ 280*96f60e37SRussell King static void armada_drm_crtc_dpms(struct drm_crtc *crtc, int dpms) 281*96f60e37SRussell King { 282*96f60e37SRussell King struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); 283*96f60e37SRussell King 284*96f60e37SRussell King if (dcrtc->dpms != dpms) { 285*96f60e37SRussell King dcrtc->dpms = dpms; 286*96f60e37SRussell King armada_drm_crtc_update(dcrtc); 287*96f60e37SRussell King if (dpms_blanked(dpms)) 288*96f60e37SRussell King armada_drm_vblank_off(dcrtc); 289*96f60e37SRussell King } 290*96f60e37SRussell King } 291*96f60e37SRussell King 292*96f60e37SRussell King /* 293*96f60e37SRussell King * Prepare for a mode set. Turn off overlay to ensure that we don't end 294*96f60e37SRussell King * up with the overlay size being bigger than the active screen size. 295*96f60e37SRussell King * We rely upon X refreshing this state after the mode set has completed. 296*96f60e37SRussell King * 297*96f60e37SRussell King * The mode_config.mutex will be held for this call 298*96f60e37SRussell King */ 299*96f60e37SRussell King static void armada_drm_crtc_prepare(struct drm_crtc *crtc) 300*96f60e37SRussell King { 301*96f60e37SRussell King struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); 302*96f60e37SRussell King struct drm_plane *plane; 303*96f60e37SRussell King 304*96f60e37SRussell King /* 305*96f60e37SRussell King * If we have an overlay plane associated with this CRTC, disable 306*96f60e37SRussell King * it before the modeset to avoid its coordinates being outside 307*96f60e37SRussell King * the new mode parameters. DRM doesn't provide help with this. 308*96f60e37SRussell King */ 309*96f60e37SRussell King plane = dcrtc->plane; 310*96f60e37SRussell King if (plane) { 311*96f60e37SRussell King struct drm_framebuffer *fb = plane->fb; 312*96f60e37SRussell King 313*96f60e37SRussell King plane->funcs->disable_plane(plane); 314*96f60e37SRussell King plane->fb = NULL; 315*96f60e37SRussell King plane->crtc = NULL; 316*96f60e37SRussell King drm_framebuffer_unreference(fb); 317*96f60e37SRussell King } 318*96f60e37SRussell King } 319*96f60e37SRussell King 320*96f60e37SRussell King /* The mode_config.mutex will be held for this call */ 321*96f60e37SRussell King static void armada_drm_crtc_commit(struct drm_crtc *crtc) 322*96f60e37SRussell King { 323*96f60e37SRussell King struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); 324*96f60e37SRussell King 325*96f60e37SRussell King if (dcrtc->dpms != DRM_MODE_DPMS_ON) { 326*96f60e37SRussell King dcrtc->dpms = DRM_MODE_DPMS_ON; 327*96f60e37SRussell King armada_drm_crtc_update(dcrtc); 328*96f60e37SRussell King } 329*96f60e37SRussell King } 330*96f60e37SRussell King 331*96f60e37SRussell King /* The mode_config.mutex will be held for this call */ 332*96f60e37SRussell King static bool armada_drm_crtc_mode_fixup(struct drm_crtc *crtc, 333*96f60e37SRussell King const struct drm_display_mode *mode, struct drm_display_mode *adj) 334*96f60e37SRussell King { 335*96f60e37SRussell King struct armada_private *priv = crtc->dev->dev_private; 336*96f60e37SRussell King struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); 337*96f60e37SRussell King int ret; 338*96f60e37SRussell King 339*96f60e37SRussell King /* We can't do interlaced modes if we don't have the SPU_ADV_REG */ 340*96f60e37SRussell King if (!priv->variant->has_spu_adv_reg && 341*96f60e37SRussell King adj->flags & DRM_MODE_FLAG_INTERLACE) 342*96f60e37SRussell King return false; 343*96f60e37SRussell King 344*96f60e37SRussell King /* Check whether the display mode is possible */ 345*96f60e37SRussell King ret = priv->variant->crtc_compute_clock(dcrtc, adj, NULL); 346*96f60e37SRussell King if (ret) 347*96f60e37SRussell King return false; 348*96f60e37SRussell King 349*96f60e37SRussell King return true; 350*96f60e37SRussell King } 351*96f60e37SRussell King 352*96f60e37SRussell King void armada_drm_crtc_irq(struct armada_crtc *dcrtc, u32 stat) 353*96f60e37SRussell King { 354*96f60e37SRussell King struct armada_vbl_event *e, *n; 355*96f60e37SRussell King void __iomem *base = dcrtc->base; 356*96f60e37SRussell King 357*96f60e37SRussell King if (stat & DMA_FF_UNDERFLOW) 358*96f60e37SRussell King DRM_ERROR("video underflow on crtc %u\n", dcrtc->num); 359*96f60e37SRussell King if (stat & GRA_FF_UNDERFLOW) 360*96f60e37SRussell King DRM_ERROR("graphics underflow on crtc %u\n", dcrtc->num); 361*96f60e37SRussell King 362*96f60e37SRussell King if (stat & VSYNC_IRQ) 363*96f60e37SRussell King drm_handle_vblank(dcrtc->crtc.dev, dcrtc->num); 364*96f60e37SRussell King 365*96f60e37SRussell King spin_lock(&dcrtc->irq_lock); 366*96f60e37SRussell King 367*96f60e37SRussell King list_for_each_entry_safe(e, n, &dcrtc->vbl_list, node) { 368*96f60e37SRussell King list_del_init(&e->node); 369*96f60e37SRussell King drm_vblank_put(dcrtc->crtc.dev, dcrtc->num); 370*96f60e37SRussell King e->fn(dcrtc, e->data); 371*96f60e37SRussell King } 372*96f60e37SRussell King 373*96f60e37SRussell King if (stat & GRA_FRAME_IRQ && dcrtc->interlaced) { 374*96f60e37SRussell King int i = stat & GRA_FRAME_IRQ0 ? 0 : 1; 375*96f60e37SRussell King uint32_t val; 376*96f60e37SRussell King 377*96f60e37SRussell King writel_relaxed(dcrtc->v[i].spu_v_porch, base + LCD_SPU_V_PORCH); 378*96f60e37SRussell King writel_relaxed(dcrtc->v[i].spu_v_h_total, 379*96f60e37SRussell King base + LCD_SPUT_V_H_TOTAL); 380*96f60e37SRussell King 381*96f60e37SRussell King val = readl_relaxed(base + LCD_SPU_ADV_REG); 382*96f60e37SRussell King val &= ~(ADV_VSYNC_L_OFF | ADV_VSYNC_H_OFF | ADV_VSYNCOFFEN); 383*96f60e37SRussell King val |= dcrtc->v[i].spu_adv_reg; 384*96f60e37SRussell King writel_relaxed(val, dcrtc->base + LCD_SPU_ADV_REG); 385*96f60e37SRussell King } 386*96f60e37SRussell King spin_unlock(&dcrtc->irq_lock); 387*96f60e37SRussell King 388*96f60e37SRussell King if (stat & GRA_FRAME_IRQ) { 389*96f60e37SRussell King struct drm_device *dev = dcrtc->crtc.dev; 390*96f60e37SRussell King 391*96f60e37SRussell King spin_lock(&dev->event_lock); 392*96f60e37SRussell King if (dcrtc->frame_work) 393*96f60e37SRussell King armada_drm_crtc_complete_frame_work(dcrtc); 394*96f60e37SRussell King spin_unlock(&dev->event_lock); 395*96f60e37SRussell King 396*96f60e37SRussell King wake_up(&dcrtc->frame_wait); 397*96f60e37SRussell King } 398*96f60e37SRussell King } 399*96f60e37SRussell King 400*96f60e37SRussell King /* These are locked by dev->vbl_lock */ 401*96f60e37SRussell King void armada_drm_crtc_disable_irq(struct armada_crtc *dcrtc, u32 mask) 402*96f60e37SRussell King { 403*96f60e37SRussell King if (dcrtc->irq_ena & mask) { 404*96f60e37SRussell King dcrtc->irq_ena &= ~mask; 405*96f60e37SRussell King writel(dcrtc->irq_ena, dcrtc->base + LCD_SPU_IRQ_ENA); 406*96f60e37SRussell King } 407*96f60e37SRussell King } 408*96f60e37SRussell King 409*96f60e37SRussell King void armada_drm_crtc_enable_irq(struct armada_crtc *dcrtc, u32 mask) 410*96f60e37SRussell King { 411*96f60e37SRussell King if ((dcrtc->irq_ena & mask) != mask) { 412*96f60e37SRussell King dcrtc->irq_ena |= mask; 413*96f60e37SRussell King writel(dcrtc->irq_ena, dcrtc->base + LCD_SPU_IRQ_ENA); 414*96f60e37SRussell King if (readl_relaxed(dcrtc->base + LCD_SPU_IRQ_ISR) & mask) 415*96f60e37SRussell King writel(0, dcrtc->base + LCD_SPU_IRQ_ISR); 416*96f60e37SRussell King } 417*96f60e37SRussell King } 418*96f60e37SRussell King 419*96f60e37SRussell King static uint32_t armada_drm_crtc_calculate_csc(struct armada_crtc *dcrtc) 420*96f60e37SRussell King { 421*96f60e37SRussell King struct drm_display_mode *adj = &dcrtc->crtc.mode; 422*96f60e37SRussell King uint32_t val = 0; 423*96f60e37SRussell King 424*96f60e37SRussell King if (dcrtc->csc_yuv_mode == CSC_YUV_CCIR709) 425*96f60e37SRussell King val |= CFG_CSC_YUV_CCIR709; 426*96f60e37SRussell King if (dcrtc->csc_rgb_mode == CSC_RGB_STUDIO) 427*96f60e37SRussell King val |= CFG_CSC_RGB_STUDIO; 428*96f60e37SRussell King 429*96f60e37SRussell King /* 430*96f60e37SRussell King * In auto mode, set the colorimetry, based upon the HDMI spec. 431*96f60e37SRussell King * 1280x720p, 1920x1080p and 1920x1080i use ITU709, others use 432*96f60e37SRussell King * ITU601. It may be more appropriate to set this depending on 433*96f60e37SRussell King * the source - but what if the graphic frame is YUV and the 434*96f60e37SRussell King * video frame is RGB? 435*96f60e37SRussell King */ 436*96f60e37SRussell King if ((adj->hdisplay == 1280 && adj->vdisplay == 720 && 437*96f60e37SRussell King !(adj->flags & DRM_MODE_FLAG_INTERLACE)) || 438*96f60e37SRussell King (adj->hdisplay == 1920 && adj->vdisplay == 1080)) { 439*96f60e37SRussell King if (dcrtc->csc_yuv_mode == CSC_AUTO) 440*96f60e37SRussell King val |= CFG_CSC_YUV_CCIR709; 441*96f60e37SRussell King } 442*96f60e37SRussell King 443*96f60e37SRussell King /* 444*96f60e37SRussell King * We assume we're connected to a TV-like device, so the YUV->RGB 445*96f60e37SRussell King * conversion should produce a limited range. We should set this 446*96f60e37SRussell King * depending on the connectors attached to this CRTC, and what 447*96f60e37SRussell King * kind of device they report being connected. 448*96f60e37SRussell King */ 449*96f60e37SRussell King if (dcrtc->csc_rgb_mode == CSC_AUTO) 450*96f60e37SRussell King val |= CFG_CSC_RGB_STUDIO; 451*96f60e37SRussell King 452*96f60e37SRussell King return val; 453*96f60e37SRussell King } 454*96f60e37SRussell King 455*96f60e37SRussell King /* The mode_config.mutex will be held for this call */ 456*96f60e37SRussell King static int armada_drm_crtc_mode_set(struct drm_crtc *crtc, 457*96f60e37SRussell King struct drm_display_mode *mode, struct drm_display_mode *adj, 458*96f60e37SRussell King int x, int y, struct drm_framebuffer *old_fb) 459*96f60e37SRussell King { 460*96f60e37SRussell King struct armada_private *priv = crtc->dev->dev_private; 461*96f60e37SRussell King struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); 462*96f60e37SRussell King struct armada_regs regs[17]; 463*96f60e37SRussell King uint32_t lm, rm, tm, bm, val, sclk; 464*96f60e37SRussell King unsigned long flags; 465*96f60e37SRussell King unsigned i; 466*96f60e37SRussell King bool interlaced; 467*96f60e37SRussell King 468*96f60e37SRussell King drm_framebuffer_reference(crtc->fb); 469*96f60e37SRussell King 470*96f60e37SRussell King interlaced = !!(adj->flags & DRM_MODE_FLAG_INTERLACE); 471*96f60e37SRussell King 472*96f60e37SRussell King i = armada_drm_crtc_calc_fb(dcrtc->crtc.fb, x, y, regs, interlaced); 473*96f60e37SRussell King 474*96f60e37SRussell King rm = adj->crtc_hsync_start - adj->crtc_hdisplay; 475*96f60e37SRussell King lm = adj->crtc_htotal - adj->crtc_hsync_end; 476*96f60e37SRussell King bm = adj->crtc_vsync_start - adj->crtc_vdisplay; 477*96f60e37SRussell King tm = adj->crtc_vtotal - adj->crtc_vsync_end; 478*96f60e37SRussell King 479*96f60e37SRussell King DRM_DEBUG_DRIVER("H: %d %d %d %d lm %d rm %d\n", 480*96f60e37SRussell King adj->crtc_hdisplay, 481*96f60e37SRussell King adj->crtc_hsync_start, 482*96f60e37SRussell King adj->crtc_hsync_end, 483*96f60e37SRussell King adj->crtc_htotal, lm, rm); 484*96f60e37SRussell King DRM_DEBUG_DRIVER("V: %d %d %d %d tm %d bm %d\n", 485*96f60e37SRussell King adj->crtc_vdisplay, 486*96f60e37SRussell King adj->crtc_vsync_start, 487*96f60e37SRussell King adj->crtc_vsync_end, 488*96f60e37SRussell King adj->crtc_vtotal, tm, bm); 489*96f60e37SRussell King 490*96f60e37SRussell King /* Wait for pending flips to complete */ 491*96f60e37SRussell King wait_event(dcrtc->frame_wait, !dcrtc->frame_work); 492*96f60e37SRussell King 493*96f60e37SRussell King drm_vblank_pre_modeset(crtc->dev, dcrtc->num); 494*96f60e37SRussell King 495*96f60e37SRussell King crtc->mode = *adj; 496*96f60e37SRussell King 497*96f60e37SRussell King val = dcrtc->dumb_ctrl & ~CFG_DUMB_ENA; 498*96f60e37SRussell King if (val != dcrtc->dumb_ctrl) { 499*96f60e37SRussell King dcrtc->dumb_ctrl = val; 500*96f60e37SRussell King writel_relaxed(val, dcrtc->base + LCD_SPU_DUMB_CTRL); 501*96f60e37SRussell King } 502*96f60e37SRussell King 503*96f60e37SRussell King /* Now compute the divider for real */ 504*96f60e37SRussell King priv->variant->crtc_compute_clock(dcrtc, adj, &sclk); 505*96f60e37SRussell King 506*96f60e37SRussell King /* Ensure graphic fifo is enabled */ 507*96f60e37SRussell King armada_reg_queue_mod(regs, i, 0, CFG_PDWN64x66, LCD_SPU_SRAM_PARA1); 508*96f60e37SRussell King armada_reg_queue_set(regs, i, sclk, LCD_CFG_SCLK_DIV); 509*96f60e37SRussell King 510*96f60e37SRussell King if (interlaced ^ dcrtc->interlaced) { 511*96f60e37SRussell King if (adj->flags & DRM_MODE_FLAG_INTERLACE) 512*96f60e37SRussell King drm_vblank_get(dcrtc->crtc.dev, dcrtc->num); 513*96f60e37SRussell King else 514*96f60e37SRussell King drm_vblank_put(dcrtc->crtc.dev, dcrtc->num); 515*96f60e37SRussell King dcrtc->interlaced = interlaced; 516*96f60e37SRussell King } 517*96f60e37SRussell King 518*96f60e37SRussell King spin_lock_irqsave(&dcrtc->irq_lock, flags); 519*96f60e37SRussell King 520*96f60e37SRussell King /* Even interlaced/progressive frame */ 521*96f60e37SRussell King dcrtc->v[1].spu_v_h_total = adj->crtc_vtotal << 16 | 522*96f60e37SRussell King adj->crtc_htotal; 523*96f60e37SRussell King dcrtc->v[1].spu_v_porch = tm << 16 | bm; 524*96f60e37SRussell King val = adj->crtc_hsync_start; 525*96f60e37SRussell King dcrtc->v[1].spu_adv_reg = val << 20 | val | ADV_VSYNCOFFEN; 526*96f60e37SRussell King 527*96f60e37SRussell King if (interlaced) { 528*96f60e37SRussell King /* Odd interlaced frame */ 529*96f60e37SRussell King dcrtc->v[0].spu_v_h_total = dcrtc->v[1].spu_v_h_total + 530*96f60e37SRussell King (1 << 16); 531*96f60e37SRussell King dcrtc->v[0].spu_v_porch = dcrtc->v[1].spu_v_porch + 1; 532*96f60e37SRussell King val = adj->crtc_hsync_start - adj->crtc_htotal / 2; 533*96f60e37SRussell King dcrtc->v[0].spu_adv_reg = val << 20 | val | ADV_VSYNCOFFEN; 534*96f60e37SRussell King } else { 535*96f60e37SRussell King dcrtc->v[0] = dcrtc->v[1]; 536*96f60e37SRussell King } 537*96f60e37SRussell King 538*96f60e37SRussell King val = adj->crtc_vdisplay << 16 | adj->crtc_hdisplay; 539*96f60e37SRussell King 540*96f60e37SRussell King armada_reg_queue_set(regs, i, val, LCD_SPU_V_H_ACTIVE); 541*96f60e37SRussell King armada_reg_queue_set(regs, i, val, LCD_SPU_GRA_HPXL_VLN); 542*96f60e37SRussell King armada_reg_queue_set(regs, i, val, LCD_SPU_GZM_HPXL_VLN); 543*96f60e37SRussell King armada_reg_queue_set(regs, i, (lm << 16) | rm, LCD_SPU_H_PORCH); 544*96f60e37SRussell King armada_reg_queue_set(regs, i, dcrtc->v[0].spu_v_porch, LCD_SPU_V_PORCH); 545*96f60e37SRussell King armada_reg_queue_set(regs, i, dcrtc->v[0].spu_v_h_total, 546*96f60e37SRussell King LCD_SPUT_V_H_TOTAL); 547*96f60e37SRussell King 548*96f60e37SRussell King if (priv->variant->has_spu_adv_reg) 549*96f60e37SRussell King armada_reg_queue_mod(regs, i, dcrtc->v[0].spu_adv_reg, 550*96f60e37SRussell King ADV_VSYNC_L_OFF | ADV_VSYNC_H_OFF | 551*96f60e37SRussell King ADV_VSYNCOFFEN, LCD_SPU_ADV_REG); 552*96f60e37SRussell King 553*96f60e37SRussell King val = CFG_GRA_ENA | CFG_GRA_HSMOOTH; 554*96f60e37SRussell King val |= CFG_GRA_FMT(drm_fb_to_armada_fb(dcrtc->crtc.fb)->fmt); 555*96f60e37SRussell King val |= CFG_GRA_MOD(drm_fb_to_armada_fb(dcrtc->crtc.fb)->mod); 556*96f60e37SRussell King 557*96f60e37SRussell King if (drm_fb_to_armada_fb(dcrtc->crtc.fb)->fmt > CFG_420) 558*96f60e37SRussell King val |= CFG_PALETTE_ENA; 559*96f60e37SRussell King 560*96f60e37SRussell King if (interlaced) 561*96f60e37SRussell King val |= CFG_GRA_FTOGGLE; 562*96f60e37SRussell King 563*96f60e37SRussell King armada_reg_queue_mod(regs, i, val, CFG_GRAFORMAT | 564*96f60e37SRussell King CFG_GRA_MOD(CFG_SWAPRB | CFG_SWAPUV | 565*96f60e37SRussell King CFG_SWAPYU | CFG_YUV2RGB) | 566*96f60e37SRussell King CFG_PALETTE_ENA | CFG_GRA_FTOGGLE, 567*96f60e37SRussell King LCD_SPU_DMA_CTRL0); 568*96f60e37SRussell King 569*96f60e37SRussell King val = adj->flags & DRM_MODE_FLAG_NVSYNC ? CFG_VSYNC_INV : 0; 570*96f60e37SRussell King armada_reg_queue_mod(regs, i, val, CFG_VSYNC_INV, LCD_SPU_DMA_CTRL1); 571*96f60e37SRussell King 572*96f60e37SRussell King val = dcrtc->spu_iopad_ctrl | armada_drm_crtc_calculate_csc(dcrtc); 573*96f60e37SRussell King armada_reg_queue_set(regs, i, val, LCD_SPU_IOPAD_CONTROL); 574*96f60e37SRussell King armada_reg_queue_end(regs, i); 575*96f60e37SRussell King 576*96f60e37SRussell King armada_drm_crtc_update_regs(dcrtc, regs); 577*96f60e37SRussell King spin_unlock_irqrestore(&dcrtc->irq_lock, flags); 578*96f60e37SRussell King 579*96f60e37SRussell King armada_drm_crtc_update(dcrtc); 580*96f60e37SRussell King 581*96f60e37SRussell King drm_vblank_post_modeset(crtc->dev, dcrtc->num); 582*96f60e37SRussell King armada_drm_crtc_finish_fb(dcrtc, old_fb, dpms_blanked(dcrtc->dpms)); 583*96f60e37SRussell King 584*96f60e37SRussell King return 0; 585*96f60e37SRussell King } 586*96f60e37SRussell King 587*96f60e37SRussell King /* The mode_config.mutex will be held for this call */ 588*96f60e37SRussell King static int armada_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, 589*96f60e37SRussell King struct drm_framebuffer *old_fb) 590*96f60e37SRussell King { 591*96f60e37SRussell King struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); 592*96f60e37SRussell King struct armada_regs regs[4]; 593*96f60e37SRussell King unsigned i; 594*96f60e37SRussell King 595*96f60e37SRussell King i = armada_drm_crtc_calc_fb(crtc->fb, crtc->x, crtc->y, regs, 596*96f60e37SRussell King dcrtc->interlaced); 597*96f60e37SRussell King armada_reg_queue_end(regs, i); 598*96f60e37SRussell King 599*96f60e37SRussell King /* Wait for pending flips to complete */ 600*96f60e37SRussell King wait_event(dcrtc->frame_wait, !dcrtc->frame_work); 601*96f60e37SRussell King 602*96f60e37SRussell King /* Take a reference to the new fb as we're using it */ 603*96f60e37SRussell King drm_framebuffer_reference(crtc->fb); 604*96f60e37SRussell King 605*96f60e37SRussell King /* Update the base in the CRTC */ 606*96f60e37SRussell King armada_drm_crtc_update_regs(dcrtc, regs); 607*96f60e37SRussell King 608*96f60e37SRussell King /* Drop our previously held reference */ 609*96f60e37SRussell King armada_drm_crtc_finish_fb(dcrtc, old_fb, dpms_blanked(dcrtc->dpms)); 610*96f60e37SRussell King 611*96f60e37SRussell King return 0; 612*96f60e37SRussell King } 613*96f60e37SRussell King 614*96f60e37SRussell King static void armada_drm_crtc_load_lut(struct drm_crtc *crtc) 615*96f60e37SRussell King { 616*96f60e37SRussell King } 617*96f60e37SRussell King 618*96f60e37SRussell King /* The mode_config.mutex will be held for this call */ 619*96f60e37SRussell King static void armada_drm_crtc_disable(struct drm_crtc *crtc) 620*96f60e37SRussell King { 621*96f60e37SRussell King struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); 622*96f60e37SRussell King 623*96f60e37SRussell King armada_drm_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); 624*96f60e37SRussell King armada_drm_crtc_finish_fb(dcrtc, crtc->fb, true); 625*96f60e37SRussell King 626*96f60e37SRussell King /* Power down most RAMs and FIFOs */ 627*96f60e37SRussell King writel_relaxed(CFG_PDWN256x32 | CFG_PDWN256x24 | CFG_PDWN256x8 | 628*96f60e37SRussell King CFG_PDWN32x32 | CFG_PDWN16x66 | CFG_PDWN32x66 | 629*96f60e37SRussell King CFG_PDWN64x66, dcrtc->base + LCD_SPU_SRAM_PARA1); 630*96f60e37SRussell King } 631*96f60e37SRussell King 632*96f60e37SRussell King static const struct drm_crtc_helper_funcs armada_crtc_helper_funcs = { 633*96f60e37SRussell King .dpms = armada_drm_crtc_dpms, 634*96f60e37SRussell King .prepare = armada_drm_crtc_prepare, 635*96f60e37SRussell King .commit = armada_drm_crtc_commit, 636*96f60e37SRussell King .mode_fixup = armada_drm_crtc_mode_fixup, 637*96f60e37SRussell King .mode_set = armada_drm_crtc_mode_set, 638*96f60e37SRussell King .mode_set_base = armada_drm_crtc_mode_set_base, 639*96f60e37SRussell King .load_lut = armada_drm_crtc_load_lut, 640*96f60e37SRussell King .disable = armada_drm_crtc_disable, 641*96f60e37SRussell King }; 642*96f60e37SRussell King 643*96f60e37SRussell King static void armada_drm_crtc_destroy(struct drm_crtc *crtc) 644*96f60e37SRussell King { 645*96f60e37SRussell King struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); 646*96f60e37SRussell King struct armada_private *priv = crtc->dev->dev_private; 647*96f60e37SRussell King 648*96f60e37SRussell King priv->dcrtc[dcrtc->num] = NULL; 649*96f60e37SRussell King drm_crtc_cleanup(&dcrtc->crtc); 650*96f60e37SRussell King 651*96f60e37SRussell King if (!IS_ERR(dcrtc->clk)) 652*96f60e37SRussell King clk_disable_unprepare(dcrtc->clk); 653*96f60e37SRussell King 654*96f60e37SRussell King kfree(dcrtc); 655*96f60e37SRussell King } 656*96f60e37SRussell King 657*96f60e37SRussell King /* 658*96f60e37SRussell King * The mode_config lock is held here, to prevent races between this 659*96f60e37SRussell King * and a mode_set. 660*96f60e37SRussell King */ 661*96f60e37SRussell King static int armada_drm_crtc_page_flip(struct drm_crtc *crtc, 662*96f60e37SRussell King struct drm_framebuffer *fb, struct drm_pending_vblank_event *event) 663*96f60e37SRussell King { 664*96f60e37SRussell King struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); 665*96f60e37SRussell King struct armada_frame_work *work; 666*96f60e37SRussell King struct drm_device *dev = crtc->dev; 667*96f60e37SRussell King unsigned long flags; 668*96f60e37SRussell King unsigned i; 669*96f60e37SRussell King int ret; 670*96f60e37SRussell King 671*96f60e37SRussell King /* We don't support changing the pixel format */ 672*96f60e37SRussell King if (fb->pixel_format != crtc->fb->pixel_format) 673*96f60e37SRussell King return -EINVAL; 674*96f60e37SRussell King 675*96f60e37SRussell King work = kmalloc(sizeof(*work), GFP_KERNEL); 676*96f60e37SRussell King if (!work) 677*96f60e37SRussell King return -ENOMEM; 678*96f60e37SRussell King 679*96f60e37SRussell King work->event = event; 680*96f60e37SRussell King work->old_fb = dcrtc->crtc.fb; 681*96f60e37SRussell King 682*96f60e37SRussell King i = armada_drm_crtc_calc_fb(fb, crtc->x, crtc->y, work->regs, 683*96f60e37SRussell King dcrtc->interlaced); 684*96f60e37SRussell King armada_reg_queue_end(work->regs, i); 685*96f60e37SRussell King 686*96f60e37SRussell King /* 687*96f60e37SRussell King * Hold the old framebuffer for the work - DRM appears to drop our 688*96f60e37SRussell King * reference to the old framebuffer in drm_mode_page_flip_ioctl(). 689*96f60e37SRussell King */ 690*96f60e37SRussell King drm_framebuffer_reference(work->old_fb); 691*96f60e37SRussell King 692*96f60e37SRussell King ret = armada_drm_crtc_queue_frame_work(dcrtc, work); 693*96f60e37SRussell King if (ret) { 694*96f60e37SRussell King /* 695*96f60e37SRussell King * Undo our reference above; DRM does not drop the reference 696*96f60e37SRussell King * to this object on error, so that's okay. 697*96f60e37SRussell King */ 698*96f60e37SRussell King drm_framebuffer_unreference(work->old_fb); 699*96f60e37SRussell King kfree(work); 700*96f60e37SRussell King return ret; 701*96f60e37SRussell King } 702*96f60e37SRussell King 703*96f60e37SRussell King /* 704*96f60e37SRussell King * Don't take a reference on the new framebuffer; 705*96f60e37SRussell King * drm_mode_page_flip_ioctl() has already grabbed a reference and 706*96f60e37SRussell King * will _not_ drop that reference on successful return from this 707*96f60e37SRussell King * function. Simply mark this new framebuffer as the current one. 708*96f60e37SRussell King */ 709*96f60e37SRussell King dcrtc->crtc.fb = fb; 710*96f60e37SRussell King 711*96f60e37SRussell King /* 712*96f60e37SRussell King * Finally, if the display is blanked, we won't receive an 713*96f60e37SRussell King * interrupt, so complete it now. 714*96f60e37SRussell King */ 715*96f60e37SRussell King if (dpms_blanked(dcrtc->dpms)) { 716*96f60e37SRussell King spin_lock_irqsave(&dev->event_lock, flags); 717*96f60e37SRussell King if (dcrtc->frame_work) 718*96f60e37SRussell King armada_drm_crtc_complete_frame_work(dcrtc); 719*96f60e37SRussell King spin_unlock_irqrestore(&dev->event_lock, flags); 720*96f60e37SRussell King } 721*96f60e37SRussell King 722*96f60e37SRussell King return 0; 723*96f60e37SRussell King } 724*96f60e37SRussell King 725*96f60e37SRussell King static int 726*96f60e37SRussell King armada_drm_crtc_set_property(struct drm_crtc *crtc, 727*96f60e37SRussell King struct drm_property *property, uint64_t val) 728*96f60e37SRussell King { 729*96f60e37SRussell King struct armada_private *priv = crtc->dev->dev_private; 730*96f60e37SRussell King struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); 731*96f60e37SRussell King bool update_csc = false; 732*96f60e37SRussell King 733*96f60e37SRussell King if (property == priv->csc_yuv_prop) { 734*96f60e37SRussell King dcrtc->csc_yuv_mode = val; 735*96f60e37SRussell King update_csc = true; 736*96f60e37SRussell King } else if (property == priv->csc_rgb_prop) { 737*96f60e37SRussell King dcrtc->csc_rgb_mode = val; 738*96f60e37SRussell King update_csc = true; 739*96f60e37SRussell King } 740*96f60e37SRussell King 741*96f60e37SRussell King if (update_csc) { 742*96f60e37SRussell King uint32_t val; 743*96f60e37SRussell King 744*96f60e37SRussell King val = dcrtc->spu_iopad_ctrl | 745*96f60e37SRussell King armada_drm_crtc_calculate_csc(dcrtc); 746*96f60e37SRussell King writel_relaxed(val, dcrtc->base + LCD_SPU_IOPAD_CONTROL); 747*96f60e37SRussell King } 748*96f60e37SRussell King 749*96f60e37SRussell King return 0; 750*96f60e37SRussell King } 751*96f60e37SRussell King 752*96f60e37SRussell King static struct drm_crtc_funcs armada_crtc_funcs = { 753*96f60e37SRussell King .destroy = armada_drm_crtc_destroy, 754*96f60e37SRussell King .set_config = drm_crtc_helper_set_config, 755*96f60e37SRussell King .page_flip = armada_drm_crtc_page_flip, 756*96f60e37SRussell King .set_property = armada_drm_crtc_set_property, 757*96f60e37SRussell King }; 758*96f60e37SRussell King 759*96f60e37SRussell King static struct drm_prop_enum_list armada_drm_csc_yuv_enum_list[] = { 760*96f60e37SRussell King { CSC_AUTO, "Auto" }, 761*96f60e37SRussell King { CSC_YUV_CCIR601, "CCIR601" }, 762*96f60e37SRussell King { CSC_YUV_CCIR709, "CCIR709" }, 763*96f60e37SRussell King }; 764*96f60e37SRussell King 765*96f60e37SRussell King static struct drm_prop_enum_list armada_drm_csc_rgb_enum_list[] = { 766*96f60e37SRussell King { CSC_AUTO, "Auto" }, 767*96f60e37SRussell King { CSC_RGB_COMPUTER, "Computer system" }, 768*96f60e37SRussell King { CSC_RGB_STUDIO, "Studio" }, 769*96f60e37SRussell King }; 770*96f60e37SRussell King 771*96f60e37SRussell King static int armada_drm_crtc_create_properties(struct drm_device *dev) 772*96f60e37SRussell King { 773*96f60e37SRussell King struct armada_private *priv = dev->dev_private; 774*96f60e37SRussell King 775*96f60e37SRussell King if (priv->csc_yuv_prop) 776*96f60e37SRussell King return 0; 777*96f60e37SRussell King 778*96f60e37SRussell King priv->csc_yuv_prop = drm_property_create_enum(dev, 0, 779*96f60e37SRussell King "CSC_YUV", armada_drm_csc_yuv_enum_list, 780*96f60e37SRussell King ARRAY_SIZE(armada_drm_csc_yuv_enum_list)); 781*96f60e37SRussell King priv->csc_rgb_prop = drm_property_create_enum(dev, 0, 782*96f60e37SRussell King "CSC_RGB", armada_drm_csc_rgb_enum_list, 783*96f60e37SRussell King ARRAY_SIZE(armada_drm_csc_rgb_enum_list)); 784*96f60e37SRussell King 785*96f60e37SRussell King if (!priv->csc_yuv_prop || !priv->csc_rgb_prop) 786*96f60e37SRussell King return -ENOMEM; 787*96f60e37SRussell King 788*96f60e37SRussell King return 0; 789*96f60e37SRussell King } 790*96f60e37SRussell King 791*96f60e37SRussell King int armada_drm_crtc_create(struct drm_device *dev, unsigned num, 792*96f60e37SRussell King struct resource *res) 793*96f60e37SRussell King { 794*96f60e37SRussell King struct armada_private *priv = dev->dev_private; 795*96f60e37SRussell King struct armada_crtc *dcrtc; 796*96f60e37SRussell King void __iomem *base; 797*96f60e37SRussell King int ret; 798*96f60e37SRussell King 799*96f60e37SRussell King ret = armada_drm_crtc_create_properties(dev); 800*96f60e37SRussell King if (ret) 801*96f60e37SRussell King return ret; 802*96f60e37SRussell King 803*96f60e37SRussell King base = devm_request_and_ioremap(dev->dev, res); 804*96f60e37SRussell King if (!base) { 805*96f60e37SRussell King DRM_ERROR("failed to ioremap register\n"); 806*96f60e37SRussell King return -ENOMEM; 807*96f60e37SRussell King } 808*96f60e37SRussell King 809*96f60e37SRussell King dcrtc = kzalloc(sizeof(*dcrtc), GFP_KERNEL); 810*96f60e37SRussell King if (!dcrtc) { 811*96f60e37SRussell King DRM_ERROR("failed to allocate Armada crtc\n"); 812*96f60e37SRussell King return -ENOMEM; 813*96f60e37SRussell King } 814*96f60e37SRussell King 815*96f60e37SRussell King dcrtc->base = base; 816*96f60e37SRussell King dcrtc->num = num; 817*96f60e37SRussell King dcrtc->clk = ERR_PTR(-EINVAL); 818*96f60e37SRussell King dcrtc->csc_yuv_mode = CSC_AUTO; 819*96f60e37SRussell King dcrtc->csc_rgb_mode = CSC_AUTO; 820*96f60e37SRussell King dcrtc->cfg_dumb_ctrl = DUMB24_RGB888_0; 821*96f60e37SRussell King dcrtc->spu_iopad_ctrl = CFG_VSCALE_LN_EN | CFG_IOPAD_DUMB24; 822*96f60e37SRussell King spin_lock_init(&dcrtc->irq_lock); 823*96f60e37SRussell King dcrtc->irq_ena = CLEAN_SPU_IRQ_ISR; 824*96f60e37SRussell King INIT_LIST_HEAD(&dcrtc->vbl_list); 825*96f60e37SRussell King init_waitqueue_head(&dcrtc->frame_wait); 826*96f60e37SRussell King 827*96f60e37SRussell King /* Initialize some registers which we don't otherwise set */ 828*96f60e37SRussell King writel_relaxed(0x00000001, dcrtc->base + LCD_CFG_SCLK_DIV); 829*96f60e37SRussell King writel_relaxed(0x00000000, dcrtc->base + LCD_SPU_BLANKCOLOR); 830*96f60e37SRussell King writel_relaxed(dcrtc->spu_iopad_ctrl, 831*96f60e37SRussell King dcrtc->base + LCD_SPU_IOPAD_CONTROL); 832*96f60e37SRussell King writel_relaxed(0x00000000, dcrtc->base + LCD_SPU_SRAM_PARA0); 833*96f60e37SRussell King writel_relaxed(CFG_PDWN256x32 | CFG_PDWN256x24 | CFG_PDWN256x8 | 834*96f60e37SRussell King CFG_PDWN32x32 | CFG_PDWN16x66 | CFG_PDWN32x66 | 835*96f60e37SRussell King CFG_PDWN64x66, dcrtc->base + LCD_SPU_SRAM_PARA1); 836*96f60e37SRussell King writel_relaxed(0x2032ff81, dcrtc->base + LCD_SPU_DMA_CTRL1); 837*96f60e37SRussell King writel_relaxed(0x00000000, dcrtc->base + LCD_SPU_GRA_OVSA_HPXL_VLN); 838*96f60e37SRussell King 839*96f60e37SRussell King if (priv->variant->crtc_init) { 840*96f60e37SRussell King ret = priv->variant->crtc_init(dcrtc); 841*96f60e37SRussell King if (ret) { 842*96f60e37SRussell King kfree(dcrtc); 843*96f60e37SRussell King return ret; 844*96f60e37SRussell King } 845*96f60e37SRussell King } 846*96f60e37SRussell King 847*96f60e37SRussell King /* Ensure AXI pipeline is enabled */ 848*96f60e37SRussell King armada_updatel(CFG_ARBFAST_ENA, 0, dcrtc->base + LCD_SPU_DMA_CTRL0); 849*96f60e37SRussell King 850*96f60e37SRussell King priv->dcrtc[dcrtc->num] = dcrtc; 851*96f60e37SRussell King 852*96f60e37SRussell King drm_crtc_init(dev, &dcrtc->crtc, &armada_crtc_funcs); 853*96f60e37SRussell King drm_crtc_helper_add(&dcrtc->crtc, &armada_crtc_helper_funcs); 854*96f60e37SRussell King 855*96f60e37SRussell King drm_object_attach_property(&dcrtc->crtc.base, priv->csc_yuv_prop, 856*96f60e37SRussell King dcrtc->csc_yuv_mode); 857*96f60e37SRussell King drm_object_attach_property(&dcrtc->crtc.base, priv->csc_rgb_prop, 858*96f60e37SRussell King dcrtc->csc_rgb_mode); 859*96f60e37SRussell King 860*96f60e37SRussell King return armada_overlay_plane_create(dev, 1 << dcrtc->num); 861*96f60e37SRussell King } 862