drm/tilcdc: Add tilcdc_crtc_mode_set_nofb()
authorJyri Sarha <jsarha@ti.com>
Thu, 7 Apr 2016 12:09:50 +0000 (15:09 +0300)
committerJyri Sarha <jsarha@ti.com>
Mon, 8 Aug 2016 20:05:02 +0000 (23:05 +0300)
Add tilcdc_crtc_mode_set_nofb(). The mode_set_nofb() semantics do not
fit well to LCDC, because of the mandatory framebuffer. However, when
the primary plane is required in the check phase, it and the
framebuffer can be found from the atomic state struct.

Signed-off-by: Jyri Sarha <jsarha@ti.com>
drivers/gpu/drm/tilcdc/tilcdc_crtc.c

index e762b4ed9308dbb3709575006e20bf2f20772137..eae002050f8016be931de4c6010d3c22f0217f7c 100644 (file)
@@ -303,6 +303,177 @@ static void tilcdc_crtc_commit(struct drm_crtc *crtc)
        tilcdc_crtc_dpms(crtc, DRM_MODE_DPMS_ON);
 }
 
+static void tilcdc_crtc_mode_set_nofb(struct drm_crtc *crtc)
+{
+       struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc);
+       struct drm_device *dev = crtc->dev;
+       struct tilcdc_drm_private *priv = dev->dev_private;
+       const struct tilcdc_panel_info *info = tilcdc_crtc->info;
+       uint32_t reg, hbp, hfp, hsw, vbp, vfp, vsw;
+       struct drm_display_mode *mode = &crtc->state->adjusted_mode;
+       struct drm_framebuffer *fb = crtc->primary->state->fb;
+
+       if (WARN_ON(!info))
+               return;
+
+       if (WARN_ON(!fb))
+               return;
+
+       pm_runtime_get_sync(dev->dev);
+
+       /* Configure the Burst Size and fifo threshold of DMA: */
+       reg = tilcdc_read(dev, LCDC_DMA_CTRL_REG) & ~0x00000770;
+       switch (info->dma_burst_sz) {
+       case 1:
+               reg |= LCDC_DMA_BURST_SIZE(LCDC_DMA_BURST_1);
+               break;
+       case 2:
+               reg |= LCDC_DMA_BURST_SIZE(LCDC_DMA_BURST_2);
+               break;
+       case 4:
+               reg |= LCDC_DMA_BURST_SIZE(LCDC_DMA_BURST_4);
+               break;
+       case 8:
+               reg |= LCDC_DMA_BURST_SIZE(LCDC_DMA_BURST_8);
+               break;
+       case 16:
+               reg |= LCDC_DMA_BURST_SIZE(LCDC_DMA_BURST_16);
+               break;
+       default:
+               dev_err(dev->dev, "invalid burst size\n");
+               return;
+       }
+       reg |= (info->fifo_th << 8);
+       tilcdc_write(dev, LCDC_DMA_CTRL_REG, reg);
+
+       /* Configure timings: */
+       hbp = mode->htotal - mode->hsync_end;
+       hfp = mode->hsync_start - mode->hdisplay;
+       hsw = mode->hsync_end - mode->hsync_start;
+       vbp = mode->vtotal - mode->vsync_end;
+       vfp = mode->vsync_start - mode->vdisplay;
+       vsw = mode->vsync_end - mode->vsync_start;
+
+       DBG("%dx%d, hbp=%u, hfp=%u, hsw=%u, vbp=%u, vfp=%u, vsw=%u",
+           mode->hdisplay, mode->vdisplay, hbp, hfp, hsw, vbp, vfp, vsw);
+
+       /* Set AC Bias Period and Number of Transitions per Interrupt: */
+       reg = tilcdc_read(dev, LCDC_RASTER_TIMING_2_REG) & ~0x000fff00;
+       reg |= LCDC_AC_BIAS_FREQUENCY(info->ac_bias) |
+               LCDC_AC_BIAS_TRANSITIONS_PER_INT(info->ac_bias_intrpt);
+
+       /*
+        * subtract one from hfp, hbp, hsw because the hardware uses
+        * a value of 0 as 1
+        */
+       if (priv->rev == 2) {
+               /* clear bits we're going to set */
+               reg &= ~0x78000033;
+               reg |= ((hfp-1) & 0x300) >> 8;
+               reg |= ((hbp-1) & 0x300) >> 4;
+               reg |= ((hsw-1) & 0x3c0) << 21;
+       }
+       tilcdc_write(dev, LCDC_RASTER_TIMING_2_REG, reg);
+
+       reg = (((mode->hdisplay >> 4) - 1) << 4) |
+               (((hbp-1) & 0xff) << 24) |
+               (((hfp-1) & 0xff) << 16) |
+               (((hsw-1) & 0x3f) << 10);
+       if (priv->rev == 2)
+               reg |= (((mode->hdisplay >> 4) - 1) & 0x40) >> 3;
+       tilcdc_write(dev, LCDC_RASTER_TIMING_0_REG, reg);
+
+       reg = ((mode->vdisplay - 1) & 0x3ff) |
+               ((vbp & 0xff) << 24) |
+               ((vfp & 0xff) << 16) |
+               (((vsw-1) & 0x3f) << 10);
+       tilcdc_write(dev, LCDC_RASTER_TIMING_1_REG, reg);
+
+       /*
+        * be sure to set Bit 10 for the V2 LCDC controller,
+        * otherwise limited to 1024 pixels width, stopping
+        * 1920x1080 being supported.
+        */
+       if (priv->rev == 2) {
+               if ((mode->vdisplay - 1) & 0x400) {
+                       tilcdc_set(dev, LCDC_RASTER_TIMING_2_REG,
+                               LCDC_LPP_B10);
+               } else {
+                       tilcdc_clear(dev, LCDC_RASTER_TIMING_2_REG,
+                               LCDC_LPP_B10);
+               }
+       }
+
+       /* Configure display type: */
+       reg = tilcdc_read(dev, LCDC_RASTER_CTRL_REG) &
+               ~(LCDC_TFT_MODE | LCDC_MONO_8BIT_MODE | LCDC_MONOCHROME_MODE |
+                 LCDC_V2_TFT_24BPP_MODE | LCDC_V2_TFT_24BPP_UNPACK |
+                 0x000ff000 /* Palette Loading Delay bits */);
+       reg |= LCDC_TFT_MODE; /* no monochrome/passive support */
+       if (info->tft_alt_mode)
+               reg |= LCDC_TFT_ALT_ENABLE;
+       if (priv->rev == 2) {
+               unsigned int depth, bpp;
+
+               drm_fb_get_bpp_depth(fb->pixel_format, &depth, &bpp);
+               switch (bpp) {
+               case 16:
+                       break;
+               case 32:
+                       reg |= LCDC_V2_TFT_24BPP_UNPACK;
+                       /* fallthrough */
+               case 24:
+                       reg |= LCDC_V2_TFT_24BPP_MODE;
+                       break;
+               default:
+                       dev_err(dev->dev, "invalid pixel format\n");
+                       return;
+               }
+       }
+       reg |= info->fdd < 12;
+       tilcdc_write(dev, LCDC_RASTER_CTRL_REG, reg);
+
+       if (info->invert_pxl_clk)
+               tilcdc_set(dev, LCDC_RASTER_TIMING_2_REG, LCDC_INVERT_PIXEL_CLOCK);
+       else
+               tilcdc_clear(dev, LCDC_RASTER_TIMING_2_REG, LCDC_INVERT_PIXEL_CLOCK);
+
+       if (info->sync_ctrl)
+               tilcdc_set(dev, LCDC_RASTER_TIMING_2_REG, LCDC_SYNC_CTRL);
+       else
+               tilcdc_clear(dev, LCDC_RASTER_TIMING_2_REG, LCDC_SYNC_CTRL);
+
+       if (info->sync_edge)
+               tilcdc_set(dev, LCDC_RASTER_TIMING_2_REG, LCDC_SYNC_EDGE);
+       else
+               tilcdc_clear(dev, LCDC_RASTER_TIMING_2_REG, LCDC_SYNC_EDGE);
+
+       if (mode->flags & DRM_MODE_FLAG_NHSYNC)
+               tilcdc_set(dev, LCDC_RASTER_TIMING_2_REG, LCDC_INVERT_HSYNC);
+       else
+               tilcdc_clear(dev, LCDC_RASTER_TIMING_2_REG, LCDC_INVERT_HSYNC);
+
+       if (mode->flags & DRM_MODE_FLAG_NVSYNC)
+               tilcdc_set(dev, LCDC_RASTER_TIMING_2_REG, LCDC_INVERT_VSYNC);
+       else
+               tilcdc_clear(dev, LCDC_RASTER_TIMING_2_REG, LCDC_INVERT_VSYNC);
+
+       if (info->raster_order)
+               tilcdc_set(dev, LCDC_RASTER_CTRL_REG, LCDC_RASTER_ORDER);
+       else
+               tilcdc_clear(dev, LCDC_RASTER_CTRL_REG, LCDC_RASTER_ORDER);
+
+       drm_framebuffer_reference(fb);
+
+       set_scanout(crtc, fb);
+
+       tilcdc_crtc_update_clk(crtc);
+
+       pm_runtime_put_sync(dev->dev);
+
+       crtc->hwmode = crtc->state->adjusted_mode;
+}
+
 static int tilcdc_crtc_mode_set(struct drm_crtc *crtc,
                struct drm_display_mode *mode,
                struct drm_display_mode *adjusted_mode,
@@ -519,6 +690,7 @@ static const struct drm_crtc_helper_funcs tilcdc_crtc_helper_funcs = {
                .commit         = tilcdc_crtc_commit,
                .mode_set       = tilcdc_crtc_mode_set,
                .mode_set_base  = tilcdc_crtc_mode_set_base,
+               .mode_set_nofb  = tilcdc_crtc_mode_set_nofb,
 };
 
 int tilcdc_crtc_max_width(struct drm_crtc *crtc)