drm/nouveau/volt: implement voltage control in core
authorBen Skeggs <bskeggs@redhat.com>
Thu, 7 Feb 2013 23:34:56 +0000 (09:34 +1000)
committerBen Skeggs <bskeggs@redhat.com>
Fri, 8 Nov 2013 05:40:17 +0000 (15:40 +1000)
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
drivers/gpu/drm/nouveau/Makefile
drivers/gpu/drm/nouveau/core/engine/device/nv40.c
drivers/gpu/drm/nouveau/core/engine/device/nv50.c
drivers/gpu/drm/nouveau/core/engine/device/nvc0.c
drivers/gpu/drm/nouveau/core/engine/device/nve0.c
drivers/gpu/drm/nouveau/core/include/subdev/volt.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/volt/base.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/volt/gpio.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/volt/nv40.c [new file with mode: 0644]

index 7d6173f..a6a7166 100644 (file)
@@ -162,6 +162,9 @@ nouveau-y += core/subdev/vm/nv41.o
 nouveau-y += core/subdev/vm/nv44.o
 nouveau-y += core/subdev/vm/nv50.o
 nouveau-y += core/subdev/vm/nvc0.o
+nouveau-y += core/subdev/volt/base.o
+nouveau-y += core/subdev/volt/gpio.o
+nouveau-y += core/subdev/volt/nv40.o
 
 nouveau-y += core/engine/falcon.o
 nouveau-y += core/engine/xtensa.o
index 97458cb..c8c41e9 100644 (file)
@@ -35,6 +35,7 @@
 #include <subdev/fb.h>
 #include <subdev/instmem.h>
 #include <subdev/vm.h>
+#include <subdev/volt.h>
 
 #include <engine/device.h>
 #include <engine/dmaobj.h>
@@ -63,6 +64,7 @@ nv40_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_FB     ] =  nv40_fb_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
                device->oclass[NVDEV_ENGINE_FIFO   ] =  nv40_fifo_oclass;
                device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
@@ -85,6 +87,7 @@ nv40_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_FB     ] =  nv41_fb_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv41_vmmgr_oclass;
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
                device->oclass[NVDEV_ENGINE_FIFO   ] =  nv40_fifo_oclass;
                device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
@@ -107,6 +110,7 @@ nv40_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_FB     ] =  nv41_fb_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv41_vmmgr_oclass;
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
                device->oclass[NVDEV_ENGINE_FIFO   ] =  nv40_fifo_oclass;
                device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
@@ -129,6 +133,7 @@ nv40_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_FB     ] =  nv41_fb_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv41_vmmgr_oclass;
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
                device->oclass[NVDEV_ENGINE_FIFO   ] =  nv40_fifo_oclass;
                device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
@@ -151,6 +156,7 @@ nv40_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_FB     ] =  nv40_fb_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
                device->oclass[NVDEV_ENGINE_FIFO   ] =  nv40_fifo_oclass;
                device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
@@ -173,6 +179,7 @@ nv40_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_FB     ] =  nv47_fb_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv41_vmmgr_oclass;
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
                device->oclass[NVDEV_ENGINE_FIFO   ] =  nv40_fifo_oclass;
                device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
@@ -195,6 +202,7 @@ nv40_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_FB     ] =  nv49_fb_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv41_vmmgr_oclass;
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
                device->oclass[NVDEV_ENGINE_FIFO   ] =  nv40_fifo_oclass;
                device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
@@ -217,6 +225,7 @@ nv40_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_FB     ] =  nv49_fb_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv41_vmmgr_oclass;
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
                device->oclass[NVDEV_ENGINE_FIFO   ] =  nv40_fifo_oclass;
                device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
@@ -239,6 +248,7 @@ nv40_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_FB     ] =  nv44_fb_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv44_vmmgr_oclass;
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
                device->oclass[NVDEV_ENGINE_FIFO   ] =  nv40_fifo_oclass;
                device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
@@ -261,6 +271,7 @@ nv40_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_FB     ] =  nv46_fb_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv44_vmmgr_oclass;
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
                device->oclass[NVDEV_ENGINE_FIFO   ] =  nv40_fifo_oclass;
                device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
@@ -283,6 +294,7 @@ nv40_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_FB     ] =  nv44_fb_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv44_vmmgr_oclass;
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
                device->oclass[NVDEV_ENGINE_FIFO   ] =  nv40_fifo_oclass;
                device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
@@ -305,6 +317,7 @@ nv40_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_FB     ] =  nv46_fb_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv44_vmmgr_oclass;
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
                device->oclass[NVDEV_ENGINE_FIFO   ] =  nv40_fifo_oclass;
                device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
@@ -327,6 +340,7 @@ nv40_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_FB     ] =  nv4e_fb_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv44_vmmgr_oclass;
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
                device->oclass[NVDEV_ENGINE_FIFO   ] =  nv40_fifo_oclass;
                device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
@@ -349,6 +363,7 @@ nv40_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_FB     ] =  nv46_fb_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv44_vmmgr_oclass;
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
                device->oclass[NVDEV_ENGINE_FIFO   ] =  nv40_fifo_oclass;
                device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
@@ -371,6 +386,7 @@ nv40_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_FB     ] =  nv46_fb_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv44_vmmgr_oclass;
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
                device->oclass[NVDEV_ENGINE_FIFO   ] =  nv40_fifo_oclass;
                device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
@@ -393,6 +409,7 @@ nv40_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_FB     ] =  nv46_fb_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv44_vmmgr_oclass;
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
                device->oclass[NVDEV_ENGINE_FIFO   ] =  nv40_fifo_oclass;
                device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
index 671a6f4..cc1b139 100644 (file)
@@ -37,6 +37,7 @@
 #include <subdev/vm.h>
 #include <subdev/bar.h>
 #include <subdev/pwr.h>
+#include <subdev/volt.h>
 
 #include <engine/device.h>
 #include <engine/dmaobj.h>
@@ -72,6 +73,7 @@ nv50_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv50_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_BAR    ] = &nv50_bar_oclass;
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv50_dmaeng_oclass;
                device->oclass[NVDEV_ENGINE_FIFO   ] =  nv50_fifo_oclass;
                device->oclass[NVDEV_ENGINE_SW     ] =  nv50_software_oclass;
@@ -96,6 +98,7 @@ nv50_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv50_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_BAR    ] = &nv50_bar_oclass;
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv50_dmaeng_oclass;
                device->oclass[NVDEV_ENGINE_FIFO   ] =  nv84_fifo_oclass;
                device->oclass[NVDEV_ENGINE_SW     ] =  nv50_software_oclass;
@@ -123,6 +126,7 @@ nv50_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv50_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_BAR    ] = &nv50_bar_oclass;
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv50_dmaeng_oclass;
                device->oclass[NVDEV_ENGINE_FIFO   ] =  nv84_fifo_oclass;
                device->oclass[NVDEV_ENGINE_SW     ] =  nv50_software_oclass;
@@ -150,6 +154,7 @@ nv50_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv50_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_BAR    ] = &nv50_bar_oclass;
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv50_dmaeng_oclass;
                device->oclass[NVDEV_ENGINE_FIFO   ] =  nv84_fifo_oclass;
                device->oclass[NVDEV_ENGINE_SW     ] =  nv50_software_oclass;
@@ -177,6 +182,7 @@ nv50_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv50_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_BAR    ] = &nv50_bar_oclass;
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv50_dmaeng_oclass;
                device->oclass[NVDEV_ENGINE_FIFO   ] =  nv84_fifo_oclass;
                device->oclass[NVDEV_ENGINE_SW     ] =  nv50_software_oclass;
@@ -204,6 +210,7 @@ nv50_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv50_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_BAR    ] = &nv50_bar_oclass;
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv50_dmaeng_oclass;
                device->oclass[NVDEV_ENGINE_FIFO   ] =  nv84_fifo_oclass;
                device->oclass[NVDEV_ENGINE_SW     ] =  nv50_software_oclass;
@@ -231,6 +238,7 @@ nv50_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv50_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_BAR    ] = &nv50_bar_oclass;
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv50_dmaeng_oclass;
                device->oclass[NVDEV_ENGINE_FIFO   ] =  nv84_fifo_oclass;
                device->oclass[NVDEV_ENGINE_SW     ] =  nv50_software_oclass;
@@ -258,6 +266,7 @@ nv50_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv50_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_BAR    ] = &nv50_bar_oclass;
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv50_dmaeng_oclass;
                device->oclass[NVDEV_ENGINE_FIFO   ] =  nv84_fifo_oclass;
                device->oclass[NVDEV_ENGINE_SW     ] =  nv50_software_oclass;
@@ -285,6 +294,7 @@ nv50_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv50_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_BAR    ] = &nv50_bar_oclass;
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv50_dmaeng_oclass;
                device->oclass[NVDEV_ENGINE_FIFO   ] =  nv84_fifo_oclass;
                device->oclass[NVDEV_ENGINE_SW     ] =  nv50_software_oclass;
@@ -312,6 +322,7 @@ nv50_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv50_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_BAR    ] = &nv50_bar_oclass;
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv50_dmaeng_oclass;
                device->oclass[NVDEV_ENGINE_FIFO   ] =  nv84_fifo_oclass;
                device->oclass[NVDEV_ENGINE_SW     ] =  nv50_software_oclass;
@@ -340,6 +351,7 @@ nv50_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv50_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_BAR    ] = &nv50_bar_oclass;
                device->oclass[NVDEV_SUBDEV_PWR    ] = &nva3_pwr_oclass;
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv50_dmaeng_oclass;
                device->oclass[NVDEV_ENGINE_FIFO   ] =  nv84_fifo_oclass;
                device->oclass[NVDEV_ENGINE_SW     ] =  nv50_software_oclass;
@@ -369,6 +381,7 @@ nv50_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv50_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_BAR    ] = &nv50_bar_oclass;
                device->oclass[NVDEV_SUBDEV_PWR    ] = &nva3_pwr_oclass;
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv50_dmaeng_oclass;
                device->oclass[NVDEV_ENGINE_FIFO   ] =  nv84_fifo_oclass;
                device->oclass[NVDEV_ENGINE_SW     ] =  nv50_software_oclass;
@@ -397,6 +410,7 @@ nv50_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv50_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_BAR    ] = &nv50_bar_oclass;
                device->oclass[NVDEV_SUBDEV_PWR    ] = &nva3_pwr_oclass;
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv50_dmaeng_oclass;
                device->oclass[NVDEV_ENGINE_FIFO   ] =  nv84_fifo_oclass;
                device->oclass[NVDEV_ENGINE_SW     ] =  nv50_software_oclass;
@@ -425,6 +439,7 @@ nv50_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv50_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_BAR    ] = &nv50_bar_oclass;
                device->oclass[NVDEV_SUBDEV_PWR    ] = &nva3_pwr_oclass;
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv50_dmaeng_oclass;
                device->oclass[NVDEV_ENGINE_FIFO   ] =  nv84_fifo_oclass;
                device->oclass[NVDEV_ENGINE_SW     ] =  nv50_software_oclass;
index 94d5090..606598f 100644 (file)
@@ -39,6 +39,7 @@
 #include <subdev/vm.h>
 #include <subdev/bar.h>
 #include <subdev/pwr.h>
+#include <subdev/volt.h>
 
 #include <engine/device.h>
 #include <engine/dmaobj.h>
@@ -75,6 +76,7 @@ nvc0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_BAR    ] = &nvc0_bar_oclass;
                device->oclass[NVDEV_SUBDEV_PWR    ] = &nvc0_pwr_oclass;
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvc0_dmaeng_oclass;
                device->oclass[NVDEV_ENGINE_FIFO   ] =  nvc0_fifo_oclass;
                device->oclass[NVDEV_ENGINE_SW     ] =  nvc0_software_oclass;
@@ -106,6 +108,7 @@ nvc0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_BAR    ] = &nvc0_bar_oclass;
                device->oclass[NVDEV_SUBDEV_PWR    ] = &nvc0_pwr_oclass;
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvc0_dmaeng_oclass;
                device->oclass[NVDEV_ENGINE_FIFO   ] =  nvc0_fifo_oclass;
                device->oclass[NVDEV_ENGINE_SW     ] =  nvc0_software_oclass;
@@ -137,6 +140,7 @@ nvc0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_BAR    ] = &nvc0_bar_oclass;
                device->oclass[NVDEV_SUBDEV_PWR    ] = &nvc0_pwr_oclass;
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvc0_dmaeng_oclass;
                device->oclass[NVDEV_ENGINE_FIFO   ] =  nvc0_fifo_oclass;
                device->oclass[NVDEV_ENGINE_SW     ] =  nvc0_software_oclass;
@@ -167,6 +171,7 @@ nvc0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_BAR    ] = &nvc0_bar_oclass;
                device->oclass[NVDEV_SUBDEV_PWR    ] = &nvc0_pwr_oclass;
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvc0_dmaeng_oclass;
                device->oclass[NVDEV_ENGINE_FIFO   ] =  nvc0_fifo_oclass;
                device->oclass[NVDEV_ENGINE_SW     ] =  nvc0_software_oclass;
@@ -198,6 +203,7 @@ nvc0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_BAR    ] = &nvc0_bar_oclass;
                device->oclass[NVDEV_SUBDEV_PWR    ] = &nvc0_pwr_oclass;
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvc0_dmaeng_oclass;
                device->oclass[NVDEV_ENGINE_FIFO   ] =  nvc0_fifo_oclass;
                device->oclass[NVDEV_ENGINE_SW     ] =  nvc0_software_oclass;
@@ -229,6 +235,7 @@ nvc0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_BAR    ] = &nvc0_bar_oclass;
                device->oclass[NVDEV_SUBDEV_PWR    ] = &nvc0_pwr_oclass;
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvc0_dmaeng_oclass;
                device->oclass[NVDEV_ENGINE_FIFO   ] =  nvc0_fifo_oclass;
                device->oclass[NVDEV_ENGINE_SW     ] =  nvc0_software_oclass;
@@ -259,6 +266,7 @@ nvc0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_BAR    ] = &nvc0_bar_oclass;
                device->oclass[NVDEV_SUBDEV_PWR    ] = &nvc0_pwr_oclass;
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvc0_dmaeng_oclass;
                device->oclass[NVDEV_ENGINE_FIFO   ] =  nvc0_fifo_oclass;
                device->oclass[NVDEV_ENGINE_SW     ] =  nvc0_software_oclass;
@@ -290,6 +298,7 @@ nvc0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_BAR    ] = &nvc0_bar_oclass;
                device->oclass[NVDEV_SUBDEV_PWR    ] = &nvd0_pwr_oclass;
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvd0_dmaeng_oclass;
                device->oclass[NVDEV_ENGINE_FIFO   ] =  nvc0_fifo_oclass;
                device->oclass[NVDEV_ENGINE_SW     ] =  nvc0_software_oclass;
index f3a7c1b..4107b67 100644 (file)
@@ -39,6 +39,7 @@
 #include <subdev/vm.h>
 #include <subdev/bar.h>
 #include <subdev/pwr.h>
+#include <subdev/volt.h>
 
 #include <engine/device.h>
 #include <engine/dmaobj.h>
@@ -75,6 +76,7 @@ nve0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_BAR    ] = &nvc0_bar_oclass;
                device->oclass[NVDEV_SUBDEV_PWR    ] = &nvd0_pwr_oclass;
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvd0_dmaeng_oclass;
                device->oclass[NVDEV_ENGINE_FIFO   ] =  nve0_fifo_oclass;
                device->oclass[NVDEV_ENGINE_SW     ] =  nvc0_software_oclass;
@@ -107,6 +109,7 @@ nve0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_BAR    ] = &nvc0_bar_oclass;
                device->oclass[NVDEV_SUBDEV_PWR    ] = &nvd0_pwr_oclass;
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvd0_dmaeng_oclass;
                device->oclass[NVDEV_ENGINE_FIFO   ] =  nve0_fifo_oclass;
                device->oclass[NVDEV_ENGINE_SW     ] =  nvc0_software_oclass;
@@ -139,6 +142,7 @@ nve0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_BAR    ] = &nvc0_bar_oclass;
                device->oclass[NVDEV_SUBDEV_PWR    ] = &nvd0_pwr_oclass;
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvd0_dmaeng_oclass;
                device->oclass[NVDEV_ENGINE_FIFO   ] =  nve0_fifo_oclass;
                device->oclass[NVDEV_ENGINE_SW     ] =  nvc0_software_oclass;
@@ -171,6 +175,7 @@ nve0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_BAR    ] = &nvc0_bar_oclass;
                device->oclass[NVDEV_SUBDEV_PWR    ] = &nvd0_pwr_oclass;
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvd0_dmaeng_oclass;
                device->oclass[NVDEV_ENGINE_FIFO   ] =  nve0_fifo_oclass;
                device->oclass[NVDEV_ENGINE_SW     ] =  nvc0_software_oclass;
@@ -205,6 +210,7 @@ nve0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_BAR    ] = &nvc0_bar_oclass;
                device->oclass[NVDEV_SUBDEV_PWR    ] = &nv108_pwr_oclass;
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvd0_dmaeng_oclass;
 #if 0
                device->oclass[NVDEV_ENGINE_FIFO   ] =  nve0_fifo_oclass;
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/volt.h b/drivers/gpu/drm/nouveau/core/include/subdev/volt.h
new file mode 100644 (file)
index 0000000..820b62f
--- /dev/null
@@ -0,0 +1,60 @@
+#ifndef __NOUVEAU_VOLT_H__
+#define __NOUVEAU_VOLT_H__
+
+#include <core/subdev.h>
+#include <core/device.h>
+
+struct nouveau_voltage {
+       u32 uv;
+       u8  id;
+};
+
+struct nouveau_volt {
+       struct nouveau_subdev base;
+
+       int (*vid_get)(struct nouveau_volt *);
+       int (*get)(struct nouveau_volt *);
+       int (*vid_set)(struct nouveau_volt *, u8 vid);
+       int (*set)(struct nouveau_volt *, u32 uv);
+       int (*set_id)(struct nouveau_volt *, u8 id, int condition);
+
+       u8 vid_mask;
+       u8 vid_nr;
+       struct {
+               u32 uv;
+               u8 vid;
+       } vid[256];
+};
+
+static inline struct nouveau_volt *
+nouveau_volt(void *obj)
+{
+       return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_VOLT];
+}
+
+#define nouveau_volt_create(p, e, o, d)                                        \
+       nouveau_volt_create_((p), (e), (o), sizeof(**d), (void **)d)
+#define nouveau_volt_destroy(p) ({                                             \
+       struct nouveau_volt *v = (p);                                          \
+       _nouveau_volt_dtor(nv_object(v));                                      \
+})
+#define nouveau_volt_init(p) ({                                                \
+       struct nouveau_volt *v = (p);                                          \
+       _nouveau_volt_init(nv_object(v));                                      \
+})
+#define nouveau_volt_fini(p,s)                                                 \
+       nouveau_subdev_fini((p), (s))
+
+int  nouveau_volt_create_(struct nouveau_object *, struct nouveau_object *,
+                         struct nouveau_oclass *, int, void **);
+void _nouveau_volt_dtor(struct nouveau_object *);
+int  _nouveau_volt_init(struct nouveau_object *);
+#define _nouveau_volt_fini _nouveau_subdev_fini
+
+extern struct nouveau_oclass nv40_volt_oclass;
+
+int nouveau_voltgpio_init(struct nouveau_volt *);
+int nouveau_voltgpio_get(struct nouveau_volt *);
+int nouveau_voltgpio_set(struct nouveau_volt *, u8);
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/volt/base.c b/drivers/gpu/drm/nouveau/core/subdev/volt/base.c
new file mode 100644 (file)
index 0000000..32794a9
--- /dev/null
@@ -0,0 +1,198 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include <subdev/volt.h>
+
+#include <subdev/bios.h>
+#include <subdev/bios/vmap.h>
+#include <subdev/bios/volt.h>
+
+static int
+nouveau_volt_get(struct nouveau_volt *volt)
+{
+       if (volt->vid_get) {
+               int ret = volt->vid_get(volt), i;
+               if (ret >= 0) {
+                       for (i = 0; i < volt->vid_nr; i++) {
+                               if (volt->vid[i].vid == ret)
+                                       return volt->vid[i].uv;
+                       }
+                       ret = -EINVAL;
+               }
+               return ret;
+       }
+       return -ENODEV;
+}
+
+static int
+nouveau_volt_set(struct nouveau_volt *volt, u32 uv)
+{
+       if (volt->vid_set) {
+               int i, ret = -EINVAL;
+               for (i = 0; i < volt->vid_nr; i++) {
+                       if (volt->vid[i].uv == uv) {
+                               ret = volt->vid_set(volt, volt->vid[i].vid);
+                               nv_debug(volt, "set %duv: %d\n", uv, ret);
+                               break;
+                       }
+               }
+               return ret;
+       }
+       return -ENODEV;
+}
+
+static int
+nouveau_volt_map(struct nouveau_volt *volt, u8 id)
+{
+       struct nouveau_bios *bios = nouveau_bios(volt);
+       struct nvbios_vmap_entry info;
+       u8  ver, len;
+       u16 vmap;
+
+       vmap = nvbios_vmap_entry_parse(bios, id, &ver, &len, &info);
+       if (vmap) {
+               if (info.link != 0xff) {
+                       int ret = nouveau_volt_map(volt, info.link);
+                       if (ret < 0)
+                               return ret;
+                       info.min += ret;
+               }
+               return info.min;
+       }
+
+       return id ? id * 10000 : -ENODEV;
+}
+
+static int
+nouveau_volt_set_id(struct nouveau_volt *volt, u8 id, int condition)
+{
+       int ret = nouveau_volt_map(volt, id);
+       if (ret >= 0) {
+               int prev = nouveau_volt_get(volt);
+               if (!condition || prev < 0 ||
+                   (condition < 0 && ret < prev) ||
+                   (condition > 0 && ret > prev)) {
+                       ret = nouveau_volt_set(volt, ret);
+               } else {
+                       ret = 0;
+               }
+       }
+       return ret;
+}
+
+int
+_nouveau_volt_init(struct nouveau_object *object)
+{
+       struct nouveau_volt *volt = (void *)object;
+       int ret;
+
+       ret = nouveau_subdev_init(&volt->base);
+       if (ret)
+               return ret;
+
+       ret = volt->get(volt);
+       if (ret < 0) {
+               if (ret != -ENODEV)
+                       nv_debug(volt, "current voltage unknown\n");
+               return 0;
+       }
+
+       nv_info(volt, "GPU voltage: %duv\n", ret);
+       return 0;
+}
+
+void
+_nouveau_volt_dtor(struct nouveau_object *object)
+{
+       struct nouveau_volt *volt = (void *)object;
+       nouveau_subdev_destroy(&volt->base);
+}
+
+int
+nouveau_volt_create_(struct nouveau_object *parent,
+                    struct nouveau_object *engine,
+                    struct nouveau_oclass *oclass, int length, void **pobject)
+{
+       struct nouveau_bios *bios = nouveau_bios(parent);
+       struct nouveau_volt *volt;
+       struct nvbios_volt_entry ivid;
+       struct nvbios_volt info;
+       u8  ver, hdr, cnt, len;
+       u16 data;
+       int ret, i;
+
+       ret = nouveau_subdev_create_(parent, engine, oclass, 0, "VOLT",
+                                    "voltage", length, pobject);
+       volt = *pobject;
+       if (ret)
+               return ret;
+
+       volt->get = nouveau_volt_get;
+       volt->set = nouveau_volt_set;
+       volt->set_id = nouveau_volt_set_id;
+
+       data = nvbios_volt_parse(bios, &ver, &hdr, &cnt, &len, &info);
+       if (data && info.vidmask && info.base && info.step) {
+               for (i = 0; i < info.vidmask + 1; i++) {
+                       if (info.base >= info.min &&
+                           info.base <= info.max) {
+                               volt->vid[volt->vid_nr].uv = info.base;
+                               volt->vid[volt->vid_nr].vid = i;
+                               volt->vid_nr++;
+                       }
+                       info.base += info.step;
+               }
+               volt->vid_mask = info.vidmask;
+       } else
+       if (data && info.vidmask) {
+               for (i = 0; i < cnt; i++) {
+                       data = nvbios_volt_entry_parse(bios, i, &ver, &hdr,
+                                                     &ivid);
+                       if (data) {
+                               volt->vid[volt->vid_nr].uv = ivid.voltage;
+                               volt->vid[volt->vid_nr].vid = ivid.vid;
+                               volt->vid_nr++;
+                       }
+               }
+               volt->vid_mask = info.vidmask;
+       }
+
+       if (volt->vid_nr) {
+               for (i = 0; i < volt->vid_nr; i++) {
+                       nv_debug(volt, "VID %02x: %duv\n",
+                                volt->vid[i].vid, volt->vid[i].uv);
+               }
+
+               /*XXX: this is an assumption.. there probably exists boards
+                * out there with i2c-connected voltage controllers too..
+                */
+               ret = nouveau_voltgpio_init(volt);
+               if (ret == 0) {
+                       volt->vid_get = nouveau_voltgpio_get;
+                       volt->vid_set = nouveau_voltgpio_set;
+               }
+       }
+
+       return ret;
+}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/volt/gpio.c b/drivers/gpu/drm/nouveau/core/subdev/volt/gpio.c
new file mode 100644 (file)
index 0000000..755fa91
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include <subdev/volt.h>
+#include <subdev/gpio.h>
+#include <subdev/bios/gpio.h>
+
+static const u8 tags[] = {
+       DCB_GPIO_VID0, DCB_GPIO_VID1, DCB_GPIO_VID2, DCB_GPIO_VID3,
+       DCB_GPIO_VID4, DCB_GPIO_VID5, DCB_GPIO_VID6, DCB_GPIO_VID7,
+};
+
+int
+nouveau_voltgpio_get(struct nouveau_volt *volt)
+{
+       struct nouveau_gpio *gpio = nouveau_gpio(volt);
+       u8 vid = 0;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(tags); i++) {
+               if (volt->vid_mask & (1 << i)) {
+                       int ret = gpio->get(gpio, 0, tags[i], 0xff);
+                       if (ret < 0)
+                               return ret;
+                       vid |= ret << i;
+               }
+       }
+
+       return vid;
+}
+
+int
+nouveau_voltgpio_set(struct nouveau_volt *volt, u8 vid)
+{
+       struct nouveau_gpio *gpio = nouveau_gpio(volt);
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(tags); i++, vid >>= 1) {
+               if (volt->vid_mask & (1 << i)) {
+                       int ret = gpio->set(gpio, 0, tags[i], 0xff, vid & 1);
+                       if (ret < 0)
+                               return ret;
+               }
+       }
+
+       return 0;
+}
+
+int
+nouveau_voltgpio_init(struct nouveau_volt *volt)
+{
+       struct nouveau_gpio *gpio = nouveau_gpio(volt);
+       struct dcb_gpio_func func;
+       int i;
+
+       /* check we have gpio function info for each vid bit.  on some
+        * boards (ie. nvs295) the vid mask has more bits than there
+        * are valid gpio functions... from traces, nvidia appear to
+        * just touch the existing ones, so let's mask off the invalid
+        * bits and continue with life
+        */
+       for (i = 0; i < ARRAY_SIZE(tags); i++) {
+               if (volt->vid_mask & (1 << i)) {
+                       int ret = gpio->find(gpio, 0, tags[i], 0xff, &func);
+                       if (ret) {
+                               if (ret != -ENOENT)
+                                       return ret;
+                               nv_debug(volt, "VID bit %d has no GPIO\n", i);
+                               volt->vid_mask &= ~(1 << i);
+                       }
+               }
+       }
+
+       return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/volt/nv40.c b/drivers/gpu/drm/nouveau/core/subdev/volt/nv40.c
new file mode 100644 (file)
index 0000000..87d5358
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include <subdev/volt.h>
+
+struct nv40_volt_priv {
+       struct nouveau_volt base;
+};
+
+static int
+nv40_volt_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+              struct nouveau_oclass *oclass, void *data, u32 size,
+              struct nouveau_object **pobject)
+{
+       struct nv40_volt_priv *priv;
+       int ret;
+
+       ret = nouveau_volt_create(parent, engine, oclass, &priv);
+       *pobject = nv_object(priv);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+struct nouveau_oclass
+nv40_volt_oclass = {
+       .handle = NV_SUBDEV(VOLT, 0x40),
+       .ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = nv40_volt_ctor,
+               .dtor = _nouveau_volt_dtor,
+               .init = _nouveau_volt_init,
+               .fini = _nouveau_volt_fini,
+       },
+};