|
|
@@ -18,6 +18,7 @@
|
|
|
#include "armada_fb.h"
|
|
|
#include "armada_gem.h"
|
|
|
#include "armada_hw.h"
|
|
|
+#include "armada_trace.h"
|
|
|
|
|
|
struct armada_frame_work {
|
|
|
struct armada_plane_work work;
|
|
|
@@ -164,19 +165,37 @@ static void armada_drm_crtc_update(struct armada_crtc *dcrtc)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+void armada_drm_plane_calc_addrs(u32 *addrs, struct drm_framebuffer *fb,
|
|
|
+ int x, int y)
|
|
|
+{
|
|
|
+ u32 addr = drm_fb_obj(fb)->dev_addr;
|
|
|
+ u32 pixel_format = fb->pixel_format;
|
|
|
+ int num_planes = drm_format_num_planes(pixel_format);
|
|
|
+ int i;
|
|
|
+
|
|
|
+ if (num_planes > 3)
|
|
|
+ num_planes = 3;
|
|
|
+
|
|
|
+ for (i = 0; i < num_planes; i++)
|
|
|
+ addrs[i] = addr + fb->offsets[i] + y * fb->pitches[i] +
|
|
|
+ x * drm_format_plane_cpp(pixel_format, i);
|
|
|
+ for (; i < 3; i++)
|
|
|
+ addrs[i] = 0;
|
|
|
+}
|
|
|
+
|
|
|
static unsigned armada_drm_crtc_calc_fb(struct drm_framebuffer *fb,
|
|
|
int x, int y, struct armada_regs *regs, bool interlaced)
|
|
|
{
|
|
|
- struct armada_gem_object *obj = drm_fb_obj(fb);
|
|
|
unsigned pitch = fb->pitches[0];
|
|
|
- unsigned offset = y * pitch + x * fb->bits_per_pixel / 8;
|
|
|
- uint32_t addr_odd, addr_even;
|
|
|
+ u32 addrs[3], addr_odd, addr_even;
|
|
|
unsigned i = 0;
|
|
|
|
|
|
DRM_DEBUG_DRIVER("pitch %u x %d y %d bpp %d\n",
|
|
|
pitch, x, y, fb->bits_per_pixel);
|
|
|
|
|
|
- addr_odd = addr_even = obj->dev_addr + offset;
|
|
|
+ armada_drm_plane_calc_addrs(addrs, fb, x, y);
|
|
|
+
|
|
|
+ addr_odd = addr_even = addrs[0];
|
|
|
|
|
|
if (interlaced) {
|
|
|
addr_even += pitch;
|
|
|
@@ -192,17 +211,18 @@ static unsigned armada_drm_crtc_calc_fb(struct drm_framebuffer *fb,
|
|
|
}
|
|
|
|
|
|
static void armada_drm_plane_work_run(struct armada_crtc *dcrtc,
|
|
|
- struct armada_plane *plane)
|
|
|
+ struct drm_plane *plane)
|
|
|
{
|
|
|
- struct armada_plane_work *work = xchg(&plane->work, NULL);
|
|
|
+ struct armada_plane *dplane = drm_to_armada_plane(plane);
|
|
|
+ struct armada_plane_work *work = xchg(&dplane->work, NULL);
|
|
|
|
|
|
/* Handle any pending frame work. */
|
|
|
if (work) {
|
|
|
- work->fn(dcrtc, plane, work);
|
|
|
+ work->fn(dcrtc, dplane, work);
|
|
|
drm_crtc_vblank_put(&dcrtc->crtc);
|
|
|
}
|
|
|
|
|
|
- wake_up(&plane->frame_wait);
|
|
|
+ wake_up(&dplane->frame_wait);
|
|
|
}
|
|
|
|
|
|
int armada_drm_plane_work_queue(struct armada_crtc *dcrtc,
|
|
|
@@ -307,14 +327,12 @@ static void armada_drm_crtc_finish_fb(struct armada_crtc *dcrtc,
|
|
|
|
|
|
static void armada_drm_vblank_off(struct armada_crtc *dcrtc)
|
|
|
{
|
|
|
- struct armada_plane *plane = drm_to_armada_plane(dcrtc->crtc.primary);
|
|
|
-
|
|
|
/*
|
|
|
* Tell the DRM core that vblank IRQs aren't going to happen for
|
|
|
* a while. This cleans up any pending vblank events for us.
|
|
|
*/
|
|
|
drm_crtc_vblank_off(&dcrtc->crtc);
|
|
|
- armada_drm_plane_work_run(dcrtc, plane);
|
|
|
+ armada_drm_plane_work_run(dcrtc, dcrtc->crtc.primary);
|
|
|
}
|
|
|
|
|
|
void armada_drm_crtc_gamma_set(struct drm_crtc *crtc, u16 r, u16 g, u16 b,
|
|
|
@@ -416,10 +434,8 @@ static void armada_drm_crtc_irq(struct armada_crtc *dcrtc, u32 stat)
|
|
|
|
|
|
spin_lock(&dcrtc->irq_lock);
|
|
|
ovl_plane = dcrtc->plane;
|
|
|
- if (ovl_plane) {
|
|
|
- struct armada_plane *plane = drm_to_armada_plane(ovl_plane);
|
|
|
- armada_drm_plane_work_run(dcrtc, plane);
|
|
|
- }
|
|
|
+ if (ovl_plane)
|
|
|
+ armada_drm_plane_work_run(dcrtc, ovl_plane);
|
|
|
|
|
|
if (stat & GRA_FRAME_IRQ && dcrtc->interlaced) {
|
|
|
int i = stat & GRA_FRAME_IRQ0 ? 0 : 1;
|
|
|
@@ -449,10 +465,8 @@ static void armada_drm_crtc_irq(struct armada_crtc *dcrtc, u32 stat)
|
|
|
|
|
|
spin_unlock(&dcrtc->irq_lock);
|
|
|
|
|
|
- if (stat & GRA_FRAME_IRQ) {
|
|
|
- struct armada_plane *plane = drm_to_armada_plane(dcrtc->crtc.primary);
|
|
|
- armada_drm_plane_work_run(dcrtc, plane);
|
|
|
- }
|
|
|
+ if (stat & GRA_FRAME_IRQ)
|
|
|
+ armada_drm_plane_work_run(dcrtc, dcrtc->crtc.primary);
|
|
|
}
|
|
|
|
|
|
static irqreturn_t armada_drm_irq(int irq, void *arg)
|
|
|
@@ -466,6 +480,8 @@ static irqreturn_t armada_drm_irq(int irq, void *arg)
|
|
|
*/
|
|
|
writel_relaxed(0, dcrtc->base + LCD_SPU_IRQ_ISR);
|
|
|
|
|
|
+ trace_armada_drm_irq(&dcrtc->crtc, stat);
|
|
|
+
|
|
|
/* Mask out those interrupts we haven't enabled */
|
|
|
v = stat & dcrtc->irq_ena;
|
|
|
|
|
|
@@ -531,6 +547,35 @@ static uint32_t armada_drm_crtc_calculate_csc(struct armada_crtc *dcrtc)
|
|
|
return val;
|
|
|
}
|
|
|
|
|
|
+static void armada_drm_primary_set(struct drm_crtc *crtc,
|
|
|
+ struct drm_plane *plane, int x, int y)
|
|
|
+{
|
|
|
+ struct armada_plane_state *state = &drm_to_armada_plane(plane)->state;
|
|
|
+ struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc);
|
|
|
+ struct armada_regs regs[8];
|
|
|
+ bool interlaced = dcrtc->interlaced;
|
|
|
+ unsigned i;
|
|
|
+ u32 ctrl0;
|
|
|
+
|
|
|
+ i = armada_drm_crtc_calc_fb(plane->fb, x, y, regs, interlaced);
|
|
|
+
|
|
|
+ armada_reg_queue_set(regs, i, state->dst_yx, LCD_SPU_GRA_OVSA_HPXL_VLN);
|
|
|
+ armada_reg_queue_set(regs, i, state->src_hw, LCD_SPU_GRA_HPXL_VLN);
|
|
|
+ armada_reg_queue_set(regs, i, state->dst_hw, LCD_SPU_GZM_HPXL_VLN);
|
|
|
+
|
|
|
+ ctrl0 = state->ctrl0;
|
|
|
+ if (interlaced)
|
|
|
+ ctrl0 |= CFG_GRA_FTOGGLE;
|
|
|
+
|
|
|
+ armada_reg_queue_mod(regs, i, ctrl0, CFG_GRAFORMAT |
|
|
|
+ CFG_GRA_MOD(CFG_SWAPRB | CFG_SWAPUV |
|
|
|
+ CFG_SWAPYU | CFG_YUV2RGB) |
|
|
|
+ CFG_PALETTE_ENA | CFG_GRA_FTOGGLE,
|
|
|
+ LCD_SPU_DMA_CTRL0);
|
|
|
+ armada_reg_queue_end(regs, i);
|
|
|
+ armada_drm_crtc_update_regs(dcrtc, regs);
|
|
|
+}
|
|
|
+
|
|
|
/* The mode_config.mutex will be held for this call */
|
|
|
static int armada_drm_crtc_mode_set(struct drm_crtc *crtc,
|
|
|
struct drm_display_mode *mode, struct drm_display_mode *adj,
|
|
|
@@ -547,9 +592,20 @@ static int armada_drm_crtc_mode_set(struct drm_crtc *crtc,
|
|
|
|
|
|
interlaced = !!(adj->flags & DRM_MODE_FLAG_INTERLACE);
|
|
|
|
|
|
- i = armada_drm_crtc_calc_fb(dcrtc->crtc.primary->fb,
|
|
|
- x, y, regs, interlaced);
|
|
|
+ val = CFG_GRA_ENA | CFG_GRA_HSMOOTH;
|
|
|
+ val |= CFG_GRA_FMT(drm_fb_to_armada_fb(dcrtc->crtc.primary->fb)->fmt);
|
|
|
+ val |= CFG_GRA_MOD(drm_fb_to_armada_fb(dcrtc->crtc.primary->fb)->mod);
|
|
|
+
|
|
|
+ if (drm_fb_to_armada_fb(dcrtc->crtc.primary->fb)->fmt > CFG_420)
|
|
|
+ val |= CFG_PALETTE_ENA;
|
|
|
+
|
|
|
+ drm_to_armada_plane(crtc->primary)->state.ctrl0 = val;
|
|
|
+ drm_to_armada_plane(crtc->primary)->state.src_hw =
|
|
|
+ drm_to_armada_plane(crtc->primary)->state.dst_hw =
|
|
|
+ adj->crtc_vdisplay << 16 | adj->crtc_hdisplay;
|
|
|
+ drm_to_armada_plane(crtc->primary)->state.dst_yx = 0;
|
|
|
|
|
|
+ i = 0;
|
|
|
rm = adj->crtc_hsync_start - adj->crtc_hdisplay;
|
|
|
lm = adj->crtc_htotal - adj->crtc_hsync_end;
|
|
|
bm = adj->crtc_vsync_start - adj->crtc_vdisplay;
|
|
|
@@ -625,8 +681,6 @@ static int armada_drm_crtc_mode_set(struct drm_crtc *crtc,
|
|
|
val = adj->crtc_vdisplay << 16 | adj->crtc_hdisplay;
|
|
|
|
|
|
armada_reg_queue_set(regs, i, val, LCD_SPU_V_H_ACTIVE);
|
|
|
- armada_reg_queue_set(regs, i, val, LCD_SPU_GRA_HPXL_VLN);
|
|
|
- armada_reg_queue_set(regs, i, val, LCD_SPU_GZM_HPXL_VLN);
|
|
|
armada_reg_queue_set(regs, i, (lm << 16) | rm, LCD_SPU_H_PORCH);
|
|
|
armada_reg_queue_set(regs, i, dcrtc->v[0].spu_v_porch, LCD_SPU_V_PORCH);
|
|
|
armada_reg_queue_set(regs, i, dcrtc->v[0].spu_v_h_total,
|
|
|
@@ -638,22 +692,6 @@ static int armada_drm_crtc_mode_set(struct drm_crtc *crtc,
|
|
|
ADV_VSYNCOFFEN, LCD_SPU_ADV_REG);
|
|
|
}
|
|
|
|
|
|
- val = CFG_GRA_ENA | CFG_GRA_HSMOOTH;
|
|
|
- val |= CFG_GRA_FMT(drm_fb_to_armada_fb(dcrtc->crtc.primary->fb)->fmt);
|
|
|
- val |= CFG_GRA_MOD(drm_fb_to_armada_fb(dcrtc->crtc.primary->fb)->mod);
|
|
|
-
|
|
|
- if (drm_fb_to_armada_fb(dcrtc->crtc.primary->fb)->fmt > CFG_420)
|
|
|
- val |= CFG_PALETTE_ENA;
|
|
|
-
|
|
|
- if (interlaced)
|
|
|
- val |= CFG_GRA_FTOGGLE;
|
|
|
-
|
|
|
- armada_reg_queue_mod(regs, i, val, CFG_GRAFORMAT |
|
|
|
- CFG_GRA_MOD(CFG_SWAPRB | CFG_SWAPUV |
|
|
|
- CFG_SWAPYU | CFG_YUV2RGB) |
|
|
|
- CFG_PALETTE_ENA | CFG_GRA_FTOGGLE,
|
|
|
- LCD_SPU_DMA_CTRL0);
|
|
|
-
|
|
|
val = adj->flags & DRM_MODE_FLAG_NVSYNC ? CFG_VSYNC_INV : 0;
|
|
|
armada_reg_queue_mod(regs, i, val, CFG_VSYNC_INV, LCD_SPU_DMA_CTRL1);
|
|
|
|
|
|
@@ -662,6 +700,8 @@ static int armada_drm_crtc_mode_set(struct drm_crtc *crtc,
|
|
|
armada_reg_queue_end(regs, i);
|
|
|
|
|
|
armada_drm_crtc_update_regs(dcrtc, regs);
|
|
|
+
|
|
|
+ armada_drm_primary_set(crtc, crtc->primary, x, y);
|
|
|
spin_unlock_irqrestore(&dcrtc->irq_lock, flags);
|
|
|
|
|
|
armada_drm_crtc_update(dcrtc);
|
|
|
@@ -1038,7 +1078,7 @@ static int armada_drm_crtc_page_flip(struct drm_crtc *crtc,
|
|
|
* interrupt, so complete it now.
|
|
|
*/
|
|
|
if (dpms_blanked(dcrtc->dpms))
|
|
|
- armada_drm_plane_work_run(dcrtc, drm_to_armada_plane(dcrtc->crtc.primary));
|
|
|
+ armada_drm_plane_work_run(dcrtc, dcrtc->crtc.primary);
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
@@ -1172,7 +1212,6 @@ static int armada_drm_crtc_create(struct drm_device *drm, struct device *dev,
|
|
|
CFG_PDWN32x32 | CFG_PDWN16x66 | CFG_PDWN32x66 |
|
|
|
CFG_PDWN64x66, dcrtc->base + LCD_SPU_SRAM_PARA1);
|
|
|
writel_relaxed(0x2032ff81, dcrtc->base + LCD_SPU_DMA_CTRL1);
|
|
|
- writel_relaxed(0x00000000, dcrtc->base + LCD_SPU_GRA_OVSA_HPXL_VLN);
|
|
|
writel_relaxed(dcrtc->irq_ena, dcrtc->base + LCD_SPU_IRQ_ENA);
|
|
|
writel_relaxed(0, dcrtc->base + LCD_SPU_IRQ_ISR);
|
|
|
|