diff options
author | Ben Skeggs <bskeggs@redhat.com> | 2011-07-06 20:47:10 -0400 |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2011-09-20 02:07:01 -0400 |
commit | 3a89cd029267739bc9f16e86e2d4156b68dc9ca2 (patch) | |
tree | 720ac2a54decd29c9b8d12c9e8cac577dcfac31d /drivers/gpu/drm/nouveau/nvd0_display.c | |
parent | b6d8e7ec38843edfc4a4491b746a17ff517ab4be (diff) |
drm/nvd0/disp: initial attempt at modeset irq handling
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/nouveau/nvd0_display.c')
-rw-r--r-- | drivers/gpu/drm/nouveau/nvd0_display.c | 130 |
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 | ||
48 | static struct nvd0_display * | 56 | static 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 | *****************************************************************************/ |
867 | static struct dcb_entry * | ||
868 | lookup_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 | |||
859 | static void | 891 | static void |
860 | nvd0_display_unk1_handler(struct drm_device *dev) | 892 | nvd0_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) | |||
870 | static void | 948 | static void |
871 | nvd0_display_unk2_handler(struct drm_device *dev) | 949 | nvd0_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 | |||
992 | ack: | ||
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) | |||
881 | static void | 998 | static void |
882 | nvd0_display_unk4_handler(struct drm_device *dev) | 999 | nvd0_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 | |||
1016 | ack: | ||
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); |