aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm
diff options
context:
space:
mode:
authorBen Skeggs <bskeggs@redhat.com>2011-07-06 20:47:10 -0400
committerBen Skeggs <bskeggs@redhat.com>2011-09-20 02:07:01 -0400
commit3a89cd029267739bc9f16e86e2d4156b68dc9ca2 (patch)
tree720ac2a54decd29c9b8d12c9e8cac577dcfac31d /drivers/gpu/drm
parentb6d8e7ec38843edfc4a4491b746a17ff517ab4be (diff)
drm/nvd0/disp: initial attempt at modeset irq handling
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Diffstat (limited to 'drivers/gpu/drm')
-rw-r--r--drivers/gpu/drm/nouveau/nvd0_display.c130
1 files changed, 130 insertions, 0 deletions
diff --git a/drivers/gpu/drm/nouveau/nvd0_display.c b/drivers/gpu/drm/nouveau/nvd0_display.c
index 08a54b7b6efc..b869ba0fb6cf 100644
--- a/drivers/gpu/drm/nouveau/nvd0_display.c
+++ b/drivers/gpu/drm/nouveau/nvd0_display.c
@@ -32,6 +32,7 @@
32#include "nouveau_encoder.h" 32#include "nouveau_encoder.h"
33#include "nouveau_crtc.h" 33#include "nouveau_crtc.h"
34#include "nouveau_fb.h" 34#include "nouveau_fb.h"
35#include "nv50_display.h"
35 36
36#define MEM_SYNC 0xe0000001 37#define MEM_SYNC 0xe0000001
37#define MEM_VRAM 0xe0010000 38#define MEM_VRAM 0xe0010000
@@ -43,6 +44,13 @@ struct nvd0_display {
43 dma_addr_t handle; 44 dma_addr_t handle;
44 u32 *ptr; 45 u32 *ptr;
45 } evo[1]; 46 } evo[1];
47 struct {
48 struct dcb_entry *dis;
49 struct dcb_entry *ena;
50 int crtc;
51 int pclk;
52 u16 script;
53 } irq;
46}; 54};
47 55
48static struct nvd0_display * 56static struct nvd0_display *
@@ -856,12 +864,82 @@ nvd0_sor_create(struct drm_connector *connector, struct dcb_entry *dcbe)
856/****************************************************************************** 864/******************************************************************************
857 * IRQ 865 * IRQ
858 *****************************************************************************/ 866 *****************************************************************************/
867static struct dcb_entry *
868lookup_dcb(struct drm_device *dev, int id, u32 mc)
869{
870 struct drm_nouveau_private *dev_priv = dev->dev_private;
871 int type, or, i;
872
873 if (id < 4) {
874 type = OUTPUT_ANALOG;
875 or = id;
876 } else {
877 type = OUTPUT_TMDS;
878 or = id - 4;
879 }
880
881 for (i = 0; i < dev_priv->vbios.dcb.entries; i++) {
882 struct dcb_entry *dcb = &dev_priv->vbios.dcb.entry[i];
883 if (dcb->type == type && (dcb->or & (1 << or)))
884 return dcb;
885 }
886
887 NV_INFO(dev, "PDISP: DCB for %d/0x%08x not found\n", id, mc);
888 return NULL;
889}
890
859static void 891static void
860nvd0_display_unk1_handler(struct drm_device *dev) 892nvd0_display_unk1_handler(struct drm_device *dev)
861{ 893{
894 struct nvd0_display *disp = nvd0_display(dev);
895 struct dcb_entry *dcb;
896 u32 unkn, crtc = 0;
897 int i;
898
862 NV_INFO(dev, "PDISP: 1 0x%08x 0x%08x 0x%08x\n", nv_rd32(dev, 0x6101d0), 899 NV_INFO(dev, "PDISP: 1 0x%08x 0x%08x 0x%08x\n", nv_rd32(dev, 0x6101d0),
863 nv_rd32(dev, 0x6101d4), nv_rd32(dev, 0x6109d4)); 900 nv_rd32(dev, 0x6101d4), nv_rd32(dev, 0x6109d4));
864 901
902 unkn = nv_rd32(dev, 0x6101d4);
903 if (!unkn) {
904 unkn = nv_rd32(dev, 0x6109d4);
905 crtc = 1;
906 }
907
908 disp->irq.ena = NULL;
909 disp->irq.dis = NULL;
910 disp->irq.crtc = crtc;
911 disp->irq.pclk = nv_rd32(dev, 0x660450 + (disp->irq.crtc * 0x300));
912 disp->irq.pclk /= 1000;
913
914 for (i = 0; i < 8; i++) {
915 u32 mcc = nv_rd32(dev, 0x640180 + (i * 0x20));
916 u32 mcp = nv_rd32(dev, 0x660180 + (i * 0x20));
917
918 if (mcc & (1 << crtc))
919 disp->irq.dis = lookup_dcb(dev, i, mcc);
920
921 if (mcp & (1 << crtc)) {
922 disp->irq.ena = lookup_dcb(dev, i, mcp);
923 switch (disp->irq.ena->type) {
924 case OUTPUT_ANALOG:
925 disp->irq.script = 0x00ff;
926 break;
927 case OUTPUT_TMDS:
928 disp->irq.script = (mcp & 0x00000f00) >> 8;
929 if (disp->irq.pclk >= 165000)
930 disp->irq.script |= 0x0100;
931 break;
932 default:
933 disp->irq.script = 0xbeef;
934 break;
935 }
936 }
937 }
938
939 dcb = disp->irq.dis;
940 if (dcb)
941 nouveau_bios_run_display_table(dev, 0x0000, -1, dcb, crtc);
942
865 nv_wr32(dev, 0x6101d4, 0x00000000); 943 nv_wr32(dev, 0x6101d4, 0x00000000);
866 nv_wr32(dev, 0x6109d4, 0x00000000); 944 nv_wr32(dev, 0x6109d4, 0x00000000);
867 nv_wr32(dev, 0x6101d0, 0x80000000); 945 nv_wr32(dev, 0x6101d0, 0x80000000);
@@ -870,9 +948,48 @@ nvd0_display_unk1_handler(struct drm_device *dev)
870static void 948static void
871nvd0_display_unk2_handler(struct drm_device *dev) 949nvd0_display_unk2_handler(struct drm_device *dev)
872{ 950{
951 struct nvd0_display *disp = nvd0_display(dev);
952 struct dcb_entry *dcb;
953 int crtc = disp->irq.crtc;
954 int pclk = disp->irq.pclk;
955 int or;
956 u32 tmp;
957
873 NV_INFO(dev, "PDISP: 2 0x%08x 0x%08x 0x%08x\n", nv_rd32(dev, 0x6101d0), 958 NV_INFO(dev, "PDISP: 2 0x%08x 0x%08x 0x%08x\n", nv_rd32(dev, 0x6101d0),
874 nv_rd32(dev, 0x6101d4), nv_rd32(dev, 0x6109d4)); 959 nv_rd32(dev, 0x6101d4), nv_rd32(dev, 0x6109d4));
875 960
961 dcb = disp->irq.dis;
962 disp->irq.dis = NULL;
963 if (dcb)
964 nouveau_bios_run_display_table(dev, 0x0000, -2, dcb, crtc);
965
966 nv50_crtc_set_clock(dev, crtc, pclk);
967
968 dcb = disp->irq.ena;
969 if (!dcb)
970 goto ack;
971 or = ffs(dcb->or) - 1;
972
973 nouveau_bios_run_display_table(dev, disp->irq.script, pclk, dcb, crtc);
974
975 nv_wr32(dev, 0x612200 + (crtc * 0x800), 0x00000000);
976 switch (dcb->type) {
977 case OUTPUT_ANALOG:
978 nv_wr32(dev, 0x612280 + (or * 0x800), 0x00000000);
979 break;
980 case OUTPUT_TMDS:
981 if (disp->irq.pclk >= 165000)
982 tmp = 0x00000101;
983 else
984 tmp = 0x00000000;
985
986 nv_mask(dev, 0x612300 + (or * 0x800), 0x00000707, tmp);
987 break;
988 default:
989 break;
990 }
991
992ack:
876 nv_wr32(dev, 0x6101d4, 0x00000000); 993 nv_wr32(dev, 0x6101d4, 0x00000000);
877 nv_wr32(dev, 0x6109d4, 0x00000000); 994 nv_wr32(dev, 0x6109d4, 0x00000000);
878 nv_wr32(dev, 0x6101d0, 0x80000000); 995 nv_wr32(dev, 0x6101d0, 0x80000000);
@@ -881,9 +998,22 @@ nvd0_display_unk2_handler(struct drm_device *dev)
881static void 998static void
882nvd0_display_unk4_handler(struct drm_device *dev) 999nvd0_display_unk4_handler(struct drm_device *dev)
883{ 1000{
1001 struct nvd0_display *disp = nvd0_display(dev);
1002 struct dcb_entry *dcb;
1003 int crtc = disp->irq.crtc;
1004 int pclk = disp->irq.pclk;
1005
884 NV_INFO(dev, "PDISP: 4 0x%08x 0x%08x 0x%08x\n", nv_rd32(dev, 0x6101d0), 1006 NV_INFO(dev, "PDISP: 4 0x%08x 0x%08x 0x%08x\n", nv_rd32(dev, 0x6101d0),
885 nv_rd32(dev, 0x6101d4), nv_rd32(dev, 0x6109d4)); 1007 nv_rd32(dev, 0x6101d4), nv_rd32(dev, 0x6109d4));
886 1008
1009 dcb = disp->irq.ena;
1010 disp->irq.ena = NULL;
1011 if (!dcb)
1012 goto ack;
1013
1014 nouveau_bios_run_display_table(dev, disp->irq.script, pclk, dcb, crtc);
1015
1016ack:
887 nv_wr32(dev, 0x6101d4, 0x00000000); 1017 nv_wr32(dev, 0x6101d4, 0x00000000);
888 nv_wr32(dev, 0x6109d4, 0x00000000); 1018 nv_wr32(dev, 0x6109d4, 0x00000000);
889 nv_wr32(dev, 0x6101d0, 0x80000000); 1019 nv_wr32(dev, 0x6101d0, 0x80000000);