aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@arm.linux.org.uk>2013-05-19 05:55:17 -0400
committerRussell King <rmk+kernel@arm.linux.org.uk>2013-10-18 10:53:30 -0400
commit662af0d8228ced3c7b3d3012a73dce929fc27574 (patch)
tree5aeb260ed1d1573415a46b84b025b12050c9be86
parent96f60e37dc66091bde8d5de136ff6fda09f2d799 (diff)
DRM: Armada: Add support for ARGB 32x64 or 64x32 hardware cursors
This patch adds ARGB hardware cursor support to the DRM driver for the Marvell Armada SoCs. ARGB cursors are supported at either 32x64 or 64x32 resolutions. Tested-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> Reviewed-by: Rob Clark <robdclark@gmail.com> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
-rw-r--r--drivers/gpu/drm/armada/armada_510.c1
-rw-r--r--drivers/gpu/drm/armada/armada_crtc.c245
-rw-r--r--drivers/gpu/drm/armada/armada_crtc.h9
-rw-r--r--drivers/gpu/drm/armada/armada_drm.h1
-rw-r--r--drivers/gpu/drm/armada/armada_hw.h6
5 files changed, 256 insertions, 6 deletions
diff --git a/drivers/gpu/drm/armada/armada_510.c b/drivers/gpu/drm/armada/armada_510.c
index a016888acd29..59948eff6095 100644
--- a/drivers/gpu/drm/armada/armada_510.c
+++ b/drivers/gpu/drm/armada/armada_510.c
@@ -80,6 +80,7 @@ static int armada510_crtc_compute_clock(struct armada_crtc *dcrtc,
80 80
81const struct armada_variant armada510_ops = { 81const struct armada_variant armada510_ops = {
82 .has_spu_adv_reg = true, 82 .has_spu_adv_reg = true,
83 .spu_adv_reg = ADV_HWC32ENABLE | ADV_HWC32ARGB | ADV_HWC32BLEND,
83 .init = armada510_init, 84 .init = armada510_init,
84 .crtc_init = armada510_crtc_init, 85 .crtc_init = armada510_crtc_init,
85 .crtc_compute_clock = armada510_crtc_compute_clock, 86 .crtc_compute_clock = armada510_crtc_compute_clock,
diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c
index 7b379fdb4e8c..e8605bf738b3 100644
--- a/drivers/gpu/drm/armada/armada_crtc.c
+++ b/drivers/gpu/drm/armada/armada_crtc.c
@@ -381,8 +381,21 @@ void armada_drm_crtc_irq(struct armada_crtc *dcrtc, u32 stat)
381 val = readl_relaxed(base + LCD_SPU_ADV_REG); 381 val = readl_relaxed(base + LCD_SPU_ADV_REG);
382 val &= ~(ADV_VSYNC_L_OFF | ADV_VSYNC_H_OFF | ADV_VSYNCOFFEN); 382 val &= ~(ADV_VSYNC_L_OFF | ADV_VSYNC_H_OFF | ADV_VSYNCOFFEN);
383 val |= dcrtc->v[i].spu_adv_reg; 383 val |= dcrtc->v[i].spu_adv_reg;
384 writel_relaxed(val, dcrtc->base + LCD_SPU_ADV_REG); 384 writel_relaxed(val, base + LCD_SPU_ADV_REG);
385 } 385 }
386
387 if (stat & DUMB_FRAMEDONE && dcrtc->cursor_update) {
388 writel_relaxed(dcrtc->cursor_hw_pos,
389 base + LCD_SPU_HWC_OVSA_HPXL_VLN);
390 writel_relaxed(dcrtc->cursor_hw_sz,
391 base + LCD_SPU_HWC_HPXL_VLN);
392 armada_updatel(CFG_HWC_ENA,
393 CFG_HWC_ENA | CFG_HWC_1BITMOD | CFG_HWC_1BITENA,
394 base + LCD_SPU_DMA_CTRL0);
395 dcrtc->cursor_update = false;
396 armada_drm_crtc_disable_irq(dcrtc, DUMB_FRAMEDONE_ENA);
397 }
398
386 spin_unlock(&dcrtc->irq_lock); 399 spin_unlock(&dcrtc->irq_lock);
387 400
388 if (stat & GRA_FRAME_IRQ) { 401 if (stat & GRA_FRAME_IRQ) {
@@ -522,7 +535,8 @@ static int armada_drm_crtc_mode_set(struct drm_crtc *crtc,
522 adj->crtc_htotal; 535 adj->crtc_htotal;
523 dcrtc->v[1].spu_v_porch = tm << 16 | bm; 536 dcrtc->v[1].spu_v_porch = tm << 16 | bm;
524 val = adj->crtc_hsync_start; 537 val = adj->crtc_hsync_start;
525 dcrtc->v[1].spu_adv_reg = val << 20 | val | ADV_VSYNCOFFEN; 538 dcrtc->v[1].spu_adv_reg = val << 20 | val | ADV_VSYNCOFFEN |
539 priv->variant->spu_adv_reg;
526 540
527 if (interlaced) { 541 if (interlaced) {
528 /* Odd interlaced frame */ 542 /* Odd interlaced frame */
@@ -530,7 +544,8 @@ static int armada_drm_crtc_mode_set(struct drm_crtc *crtc,
530 (1 << 16); 544 (1 << 16);
531 dcrtc->v[0].spu_v_porch = dcrtc->v[1].spu_v_porch + 1; 545 dcrtc->v[0].spu_v_porch = dcrtc->v[1].spu_v_porch + 1;
532 val = adj->crtc_hsync_start - adj->crtc_htotal / 2; 546 val = adj->crtc_hsync_start - adj->crtc_htotal / 2;
533 dcrtc->v[0].spu_adv_reg = val << 20 | val | ADV_VSYNCOFFEN; 547 dcrtc->v[0].spu_adv_reg = val << 20 | val | ADV_VSYNCOFFEN |
548 priv->variant->spu_adv_reg;
534 } else { 549 } else {
535 dcrtc->v[0] = dcrtc->v[1]; 550 dcrtc->v[0] = dcrtc->v[1];
536 } 551 }
@@ -545,10 +560,11 @@ static int armada_drm_crtc_mode_set(struct drm_crtc *crtc,
545 armada_reg_queue_set(regs, i, dcrtc->v[0].spu_v_h_total, 560 armada_reg_queue_set(regs, i, dcrtc->v[0].spu_v_h_total,
546 LCD_SPUT_V_H_TOTAL); 561 LCD_SPUT_V_H_TOTAL);
547 562
548 if (priv->variant->has_spu_adv_reg) 563 if (priv->variant->has_spu_adv_reg) {
549 armada_reg_queue_mod(regs, i, dcrtc->v[0].spu_adv_reg, 564 armada_reg_queue_mod(regs, i, dcrtc->v[0].spu_adv_reg,
550 ADV_VSYNC_L_OFF | ADV_VSYNC_H_OFF | 565 ADV_VSYNC_L_OFF | ADV_VSYNC_H_OFF |
551 ADV_VSYNCOFFEN, LCD_SPU_ADV_REG); 566 ADV_VSYNCOFFEN, LCD_SPU_ADV_REG);
567 }
552 568
553 val = CFG_GRA_ENA | CFG_GRA_HSMOOTH; 569 val = CFG_GRA_ENA | CFG_GRA_HSMOOTH;
554 val |= CFG_GRA_FMT(drm_fb_to_armada_fb(dcrtc->crtc.fb)->fmt); 570 val |= CFG_GRA_FMT(drm_fb_to_armada_fb(dcrtc->crtc.fb)->fmt);
@@ -640,11 +656,230 @@ static const struct drm_crtc_helper_funcs armada_crtc_helper_funcs = {
640 .disable = armada_drm_crtc_disable, 656 .disable = armada_drm_crtc_disable,
641}; 657};
642 658
659static void armada_load_cursor_argb(void __iomem *base, uint32_t *pix,
660 unsigned stride, unsigned width, unsigned height)
661{
662 uint32_t addr;
663 unsigned y;
664
665 addr = SRAM_HWC32_RAM1;
666 for (y = 0; y < height; y++) {
667 uint32_t *p = &pix[y * stride];
668 unsigned x;
669
670 for (x = 0; x < width; x++, p++) {
671 uint32_t val = *p;
672
673 val = (val & 0xff00ff00) |
674 (val & 0x000000ff) << 16 |
675 (val & 0x00ff0000) >> 16;
676
677 writel_relaxed(val,
678 base + LCD_SPU_SRAM_WRDAT);
679 writel_relaxed(addr | SRAM_WRITE,
680 base + LCD_SPU_SRAM_CTRL);
681 addr += 1;
682 if ((addr & 0x00ff) == 0)
683 addr += 0xf00;
684 if ((addr & 0x30ff) == 0)
685 addr = SRAM_HWC32_RAM2;
686 }
687 }
688}
689
690static void armada_drm_crtc_cursor_tran(void __iomem *base)
691{
692 unsigned addr;
693
694 for (addr = 0; addr < 256; addr++) {
695 /* write the default value */
696 writel_relaxed(0x55555555, base + LCD_SPU_SRAM_WRDAT);
697 writel_relaxed(addr | SRAM_WRITE | SRAM_HWC32_TRAN,
698 base + LCD_SPU_SRAM_CTRL);
699 }
700}
701
702static int armada_drm_crtc_cursor_update(struct armada_crtc *dcrtc, bool reload)
703{
704 uint32_t xoff, xscr, w = dcrtc->cursor_w, s;
705 uint32_t yoff, yscr, h = dcrtc->cursor_h;
706 uint32_t para1;
707
708 /*
709 * Calculate the visible width and height of the cursor,
710 * screen position, and the position in the cursor bitmap.
711 */
712 if (dcrtc->cursor_x < 0) {
713 xoff = -dcrtc->cursor_x;
714 xscr = 0;
715 w -= min(xoff, w);
716 } else if (dcrtc->cursor_x + w > dcrtc->crtc.mode.hdisplay) {
717 xoff = 0;
718 xscr = dcrtc->cursor_x;
719 w = max_t(int, dcrtc->crtc.mode.hdisplay - dcrtc->cursor_x, 0);
720 } else {
721 xoff = 0;
722 xscr = dcrtc->cursor_x;
723 }
724
725 if (dcrtc->cursor_y < 0) {
726 yoff = -dcrtc->cursor_y;
727 yscr = 0;
728 h -= min(yoff, h);
729 } else if (dcrtc->cursor_y + h > dcrtc->crtc.mode.vdisplay) {
730 yoff = 0;
731 yscr = dcrtc->cursor_y;
732 h = max_t(int, dcrtc->crtc.mode.vdisplay - dcrtc->cursor_y, 0);
733 } else {
734 yoff = 0;
735 yscr = dcrtc->cursor_y;
736 }
737
738 /* On interlaced modes, the vertical cursor size must be halved */
739 s = dcrtc->cursor_w;
740 if (dcrtc->interlaced) {
741 s *= 2;
742 yscr /= 2;
743 h /= 2;
744 }
745
746 if (!dcrtc->cursor_obj || !h || !w) {
747 spin_lock_irq(&dcrtc->irq_lock);
748 armada_drm_crtc_disable_irq(dcrtc, DUMB_FRAMEDONE_ENA);
749 dcrtc->cursor_update = false;
750 armada_updatel(0, CFG_HWC_ENA, dcrtc->base + LCD_SPU_DMA_CTRL0);
751 spin_unlock_irq(&dcrtc->irq_lock);
752 return 0;
753 }
754
755 para1 = readl_relaxed(dcrtc->base + LCD_SPU_SRAM_PARA1);
756 armada_updatel(CFG_CSB_256x32, CFG_CSB_256x32 | CFG_PDWN256x32,
757 dcrtc->base + LCD_SPU_SRAM_PARA1);
758
759 /*
760 * Initialize the transparency if the SRAM was powered down.
761 * We must also reload the cursor data as well.
762 */
763 if (!(para1 & CFG_CSB_256x32)) {
764 armada_drm_crtc_cursor_tran(dcrtc->base);
765 reload = true;
766 }
767
768 if (dcrtc->cursor_hw_sz != (h << 16 | w)) {
769 spin_lock_irq(&dcrtc->irq_lock);
770 armada_drm_crtc_disable_irq(dcrtc, DUMB_FRAMEDONE_ENA);
771 dcrtc->cursor_update = false;
772 armada_updatel(0, CFG_HWC_ENA, dcrtc->base + LCD_SPU_DMA_CTRL0);
773 spin_unlock_irq(&dcrtc->irq_lock);
774 reload = true;
775 }
776 if (reload) {
777 struct armada_gem_object *obj = dcrtc->cursor_obj;
778 uint32_t *pix;
779 /* Set the top-left corner of the cursor image */
780 pix = obj->addr;
781 pix += yoff * s + xoff;
782 armada_load_cursor_argb(dcrtc->base, pix, s, w, h);
783 }
784
785 /* Reload the cursor position, size and enable in the IRQ handler */
786 spin_lock_irq(&dcrtc->irq_lock);
787 dcrtc->cursor_hw_pos = yscr << 16 | xscr;
788 dcrtc->cursor_hw_sz = h << 16 | w;
789 dcrtc->cursor_update = true;
790 armada_drm_crtc_enable_irq(dcrtc, DUMB_FRAMEDONE_ENA);
791 spin_unlock_irq(&dcrtc->irq_lock);
792
793 return 0;
794}
795
796static void cursor_update(void *data)
797{
798 armada_drm_crtc_cursor_update(data, true);
799}
800
801static int armada_drm_crtc_cursor_set(struct drm_crtc *crtc,
802 struct drm_file *file, uint32_t handle, uint32_t w, uint32_t h)
803{
804 struct drm_device *dev = crtc->dev;
805 struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc);
806 struct armada_private *priv = crtc->dev->dev_private;
807 struct armada_gem_object *obj = NULL;
808 int ret;
809
810 /* If no cursor support, replicate drm's return value */
811 if (!priv->variant->has_spu_adv_reg)
812 return -ENXIO;
813
814 if (handle && w > 0 && h > 0) {
815 /* maximum size is 64x32 or 32x64 */
816 if (w > 64 || h > 64 || (w > 32 && h > 32))
817 return -ENOMEM;
818
819 obj = armada_gem_object_lookup(dev, file, handle);
820 if (!obj)
821 return -ENOENT;
822
823 /* Must be a kernel-mapped object */
824 if (!obj->addr) {
825 drm_gem_object_unreference_unlocked(&obj->obj);
826 return -EINVAL;
827 }
828
829 if (obj->obj.size < w * h * 4) {
830 DRM_ERROR("buffer is too small\n");
831 drm_gem_object_unreference_unlocked(&obj->obj);
832 return -ENOMEM;
833 }
834 }
835
836 mutex_lock(&dev->struct_mutex);
837 if (dcrtc->cursor_obj) {
838 dcrtc->cursor_obj->update = NULL;
839 dcrtc->cursor_obj->update_data = NULL;
840 drm_gem_object_unreference(&dcrtc->cursor_obj->obj);
841 }
842 dcrtc->cursor_obj = obj;
843 dcrtc->cursor_w = w;
844 dcrtc->cursor_h = h;
845 ret = armada_drm_crtc_cursor_update(dcrtc, true);
846 if (obj) {
847 obj->update_data = dcrtc;
848 obj->update = cursor_update;
849 }
850 mutex_unlock(&dev->struct_mutex);
851
852 return ret;
853}
854
855static int armada_drm_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
856{
857 struct drm_device *dev = crtc->dev;
858 struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc);
859 struct armada_private *priv = crtc->dev->dev_private;
860 int ret;
861
862 /* If no cursor support, replicate drm's return value */
863 if (!priv->variant->has_spu_adv_reg)
864 return -EFAULT;
865
866 mutex_lock(&dev->struct_mutex);
867 dcrtc->cursor_x = x;
868 dcrtc->cursor_y = y;
869 ret = armada_drm_crtc_cursor_update(dcrtc, false);
870 mutex_unlock(&dev->struct_mutex);
871
872 return ret;
873}
874
643static void armada_drm_crtc_destroy(struct drm_crtc *crtc) 875static void armada_drm_crtc_destroy(struct drm_crtc *crtc)
644{ 876{
645 struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); 877 struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc);
646 struct armada_private *priv = crtc->dev->dev_private; 878 struct armada_private *priv = crtc->dev->dev_private;
647 879
880 if (dcrtc->cursor_obj)
881 drm_gem_object_unreference(&dcrtc->cursor_obj->obj);
882
648 priv->dcrtc[dcrtc->num] = NULL; 883 priv->dcrtc[dcrtc->num] = NULL;
649 drm_crtc_cleanup(&dcrtc->crtc); 884 drm_crtc_cleanup(&dcrtc->crtc);
650 885
@@ -750,6 +985,8 @@ armada_drm_crtc_set_property(struct drm_crtc *crtc,
750} 985}
751 986
752static struct drm_crtc_funcs armada_crtc_funcs = { 987static struct drm_crtc_funcs armada_crtc_funcs = {
988 .cursor_set = armada_drm_crtc_cursor_set,
989 .cursor_move = armada_drm_crtc_cursor_move,
753 .destroy = armada_drm_crtc_destroy, 990 .destroy = armada_drm_crtc_destroy,
754 .set_config = drm_crtc_helper_set_config, 991 .set_config = drm_crtc_helper_set_config,
755 .page_flip = armada_drm_crtc_page_flip, 992 .page_flip = armada_drm_crtc_page_flip,
diff --git a/drivers/gpu/drm/armada/armada_crtc.h b/drivers/gpu/drm/armada/armada_crtc.h
index 972da535921d..9c10a07e7492 100644
--- a/drivers/gpu/drm/armada/armada_crtc.h
+++ b/drivers/gpu/drm/armada/armada_crtc.h
@@ -44,11 +44,20 @@ struct armada_crtc {
44 uint32_t spu_adv_reg; 44 uint32_t spu_adv_reg;
45 } v[2]; 45 } v[2];
46 bool interlaced; 46 bool interlaced;
47 bool cursor_update;
47 uint8_t csc_yuv_mode; 48 uint8_t csc_yuv_mode;
48 uint8_t csc_rgb_mode; 49 uint8_t csc_rgb_mode;
49 50
50 struct drm_plane *plane; 51 struct drm_plane *plane;
51 52
53 struct armada_gem_object *cursor_obj;
54 int cursor_x;
55 int cursor_y;
56 uint32_t cursor_hw_pos;
57 uint32_t cursor_hw_sz;
58 uint32_t cursor_w;
59 uint32_t cursor_h;
60
52 int dpms; 61 int dpms;
53 uint32_t cfg_dumb_ctrl; 62 uint32_t cfg_dumb_ctrl;
54 uint32_t dumb_ctrl; 63 uint32_t dumb_ctrl;
diff --git a/drivers/gpu/drm/armada/armada_drm.h b/drivers/gpu/drm/armada/armada_drm.h
index e8c4f80c61d4..eef09ec9a5ff 100644
--- a/drivers/gpu/drm/armada/armada_drm.h
+++ b/drivers/gpu/drm/armada/armada_drm.h
@@ -60,6 +60,7 @@ struct armada_private;
60 60
61struct armada_variant { 61struct armada_variant {
62 bool has_spu_adv_reg; 62 bool has_spu_adv_reg;
63 uint32_t spu_adv_reg;
63 int (*init)(struct armada_private *, struct device *); 64 int (*init)(struct armada_private *, struct device *);
64 int (*crtc_init)(struct armada_crtc *); 65 int (*crtc_init)(struct armada_crtc *);
65 int (*crtc_compute_clock)(struct armada_crtc *, 66 int (*crtc_compute_clock)(struct armada_crtc *,
diff --git a/drivers/gpu/drm/armada/armada_hw.h b/drivers/gpu/drm/armada/armada_hw.h
index 216a4b50c36b..27319a8335e2 100644
--- a/drivers/gpu/drm/armada/armada_hw.h
+++ b/drivers/gpu/drm/armada/armada_hw.h
@@ -168,8 +168,10 @@ enum {
168 SRAM_READ = 0 << 14, 168 SRAM_READ = 0 << 14,
169 SRAM_WRITE = 2 << 14, 169 SRAM_WRITE = 2 << 14,
170 SRAM_INIT = 3 << 14, 170 SRAM_INIT = 3 << 14,
171 SRAM_HWC32_RAMR = 0xc << 8, 171 SRAM_HWC32_RAM1 = 0xc << 8,
172 SRAM_HWC32_RAMG = 0xd << 8, 172 SRAM_HWC32_RAM2 = 0xd << 8,
173 SRAM_HWC32_RAMR = SRAM_HWC32_RAM1,
174 SRAM_HWC32_RAMG = SRAM_HWC32_RAM2,
173 SRAM_HWC32_RAMB = 0xe << 8, 175 SRAM_HWC32_RAMB = 0xe << 8,
174 SRAM_HWC32_TRAN = 0xf << 8, 176 SRAM_HWC32_TRAN = 0xf << 8,
175 SRAM_HWC = 0xf << 8, 177 SRAM_HWC = 0xf << 8,