drm/nouveau: run perflvl and M table scripts on mem clock change
authorBen Skeggs <bskeggs@redhat.com>
Mon, 27 Sep 2010 00:13:23 +0000 (10:13 +1000)
committerBen Skeggs <bskeggs@redhat.com>
Mon, 4 Oct 2010 23:57:49 +0000 (09:57 +1000)
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
drivers/gpu/drm/nouveau/nouveau_drv.h
drivers/gpu/drm/nouveau/nouveau_perf.c
drivers/gpu/drm/nouveau/nv50_pm.c

index 01ee63a..ef74d40 100644 (file)
@@ -385,6 +385,8 @@ struct nouveau_pm_level {
 
        u8 voltage;
        u8 fanspeed;
+
+       u16 memscript;
 };
 
 struct nouveau_pm_temp_sensor_constants {
index 6b641b6..5a95be6 100644 (file)
@@ -160,6 +160,7 @@ nouveau_perf_init(struct drm_device *dev)
                        perflvl->memory = ROM16(entry[12]) * 1000;
                        break;
                case 0x30:
+                       perflvl->memscript = ROM16(entry[2]);
                case 0x35:
                        perflvl->fanspeed = entry[6];
                        perflvl->voltage = entry[7];
index eaf69c8..2a9fabd 100644 (file)
@@ -24,6 +24,7 @@
 
 #include "drmP.h"
 #include "nouveau_drv.h"
+#include "nouveau_bios.h"
 #include "nouveau_pm.h"
 
 /*XXX: boards using limits 0x40 need fixing, the register layout
@@ -33,6 +34,7 @@
  */
 
 struct nv50_pm_state {
+       struct nouveau_pm_level *perflvl;
        struct pll_lims pll;
        enum pll_types type;
        int N, M, P;
@@ -77,6 +79,7 @@ nv50_pm_clock_pre(struct drm_device *dev, struct nouveau_pm_level *perflvl,
        if (!state)
                return ERR_PTR(-ENOMEM);
        state->type = id;
+       state->perflvl = perflvl;
 
        ret = get_pll_limits(dev, id, &state->pll);
        if (ret < 0) {
@@ -98,11 +101,30 @@ void
 nv50_pm_clock_set(struct drm_device *dev, void *pre_state)
 {
        struct nv50_pm_state *state = pre_state;
+       struct nouveau_pm_level *perflvl = state->perflvl;
        u32 reg = state->pll.reg, tmp;
+       struct bit_entry BIT_M;
+       u16 script;
        int N = state->N;
        int M = state->M;
        int P = state->P;
 
+       if (state->type == PLL_MEMORY && perflvl->memscript &&
+           bit_table(dev, 'M', &BIT_M) == 0 &&
+           BIT_M.version == 1 && BIT_M.length >= 0x0b) {
+               script = ROM16(BIT_M.data[0x05]);
+               if (script)
+                       nouveau_bios_run_init_table(dev, script, NULL);
+               script = ROM16(BIT_M.data[0x07]);
+               if (script)
+                       nouveau_bios_run_init_table(dev, script, NULL);
+               script = ROM16(BIT_M.data[0x09]);
+               if (script)
+                       nouveau_bios_run_init_table(dev, script, NULL);
+
+               nouveau_bios_run_init_table(dev, perflvl->memscript, NULL);
+       }
+
        if (state->pll.vco2.maxfreq) {
                if (state->type == PLL_MEMORY) {
                        nv_wr32(dev, 0x100210, 0);