Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 442b626e authored by Ben Skeggs's avatar Ben Skeggs
Browse files

drm/nv04-nv40: import initial pm backend



Currently just hooked up to the already-existing nouveau_hw, which should
handle all relevant chipsets as well as we currently can.

This will likely be eventually split out and improved into chipset specific
code at a later point.

Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
parent 02c30ca0
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -25,7 +25,7 @@ nouveau-y := nouveau_drv.o nouveau_state.o nouveau_channel.o nouveau_mem.o \
             nv04_crtc.o nv04_display.o nv04_cursor.o nv04_fbcon.o \
             nv10_gpio.o nv50_gpio.o \
	     nv50_calc.o \
	     nv50_pm.o
	     nv04_pm.o nv50_pm.o

nouveau-$(CONFIG_DRM_NOUVEAU_DEBUG) += nouveau_debugfs.o
nouveau-$(CONFIG_COMPAT) += nouveau_ioc32.o
+6 −2
Original line number Diff line number Diff line
@@ -431,7 +431,8 @@ nouveau_hw_get_pllvals(struct drm_device *dev, enum pll_types plltype,
	struct pll_lims pll_lim;
	int ret;

	BUG_ON(reg1 == 0);
	if (reg1 == 0)
		return -ENOENT;

	pll1 = nvReadMC(dev, reg1);

@@ -480,6 +481,7 @@ int
nouveau_hw_get_clock(struct drm_device *dev, enum pll_types plltype)
{
	struct nouveau_pll_vals pllvals;
	int ret;

	if (plltype == PLL_MEMORY &&
	    (dev->pci_device & 0x0ff0) == CHIPSET_NFORCE) {
@@ -499,7 +501,9 @@ nouveau_hw_get_clock(struct drm_device *dev, enum pll_types plltype)
		return clock;
	}

	nouveau_hw_get_pllvals(dev, plltype, &pllvals);
	ret = nouveau_hw_get_pllvals(dev, plltype, &pllvals);
	if (ret)
		return ret;

	return nouveau_hw_pllvals_to_clk(&pllvals);
}
+5 −0
Original line number Diff line number Diff line
@@ -41,6 +41,11 @@ int nouveau_voltage_gpio_set(struct drm_device *, int voltage);
void nouveau_perf_init(struct drm_device *);
void nouveau_perf_fini(struct drm_device *);

/* nv04_pm.c */
int nv04_pm_clock_get(struct drm_device *, u32 id);
void *nv04_pm_clock_pre(struct drm_device *, u32 id, int khz);
void nv04_pm_clock_set(struct drm_device *, void *);

/* nv50_pm.c */
int nv50_pm_clock_get(struct drm_device *, u32 id);
void *nv50_pm_clock_pre(struct drm_device *, u32 id, int khz);
+19 −0
Original line number Diff line number Diff line
@@ -96,6 +96,9 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
		engine->gpio.get		= NULL;
		engine->gpio.set		= NULL;
		engine->gpio.irq_enable		= NULL;
		engine->pm.clock_get		= nv04_pm_clock_get;
		engine->pm.clock_pre		= nv04_pm_clock_pre;
		engine->pm.clock_set		= nv04_pm_clock_set;
		break;
	case 0x10:
		engine->instmem.init		= nv04_instmem_init;
@@ -147,6 +150,9 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
		engine->gpio.get		= nv10_gpio_get;
		engine->gpio.set		= nv10_gpio_set;
		engine->gpio.irq_enable		= NULL;
		engine->pm.clock_get		= nv04_pm_clock_get;
		engine->pm.clock_pre		= nv04_pm_clock_pre;
		engine->pm.clock_set		= nv04_pm_clock_set;
		break;
	case 0x20:
		engine->instmem.init		= nv04_instmem_init;
@@ -198,6 +204,9 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
		engine->gpio.get		= nv10_gpio_get;
		engine->gpio.set		= nv10_gpio_set;
		engine->gpio.irq_enable		= NULL;
		engine->pm.clock_get		= nv04_pm_clock_get;
		engine->pm.clock_pre		= nv04_pm_clock_pre;
		engine->pm.clock_set		= nv04_pm_clock_set;
		break;
	case 0x30:
		engine->instmem.init		= nv04_instmem_init;
@@ -249,6 +258,11 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
		engine->gpio.get		= nv10_gpio_get;
		engine->gpio.set		= nv10_gpio_set;
		engine->gpio.irq_enable		= NULL;
		engine->pm.clock_get		= nv04_pm_clock_get;
		engine->pm.clock_pre		= nv04_pm_clock_pre;
		engine->pm.clock_set		= nv04_pm_clock_set;
		engine->pm.voltage_get		= nouveau_voltage_gpio_get;
		engine->pm.voltage_set		= nouveau_voltage_gpio_set;
		break;
	case 0x40:
	case 0x60:
@@ -301,6 +315,11 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
		engine->gpio.get		= nv10_gpio_get;
		engine->gpio.set		= nv10_gpio_set;
		engine->gpio.irq_enable		= NULL;
		engine->pm.clock_get		= nv04_pm_clock_get;
		engine->pm.clock_pre		= nv04_pm_clock_pre;
		engine->pm.clock_set		= nv04_pm_clock_set;
		engine->pm.voltage_get		= nouveau_voltage_gpio_get;
		engine->pm.voltage_set		= nouveau_voltage_gpio_set;
		break;
	case 0x50:
	case 0x80: /* gotta love NVIDIA's consistency.. */
+79 −0
Original line number Diff line number Diff line
/*
 * Copyright 2010 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 "drmP.h"
#include "nouveau_drv.h"
#include "nouveau_hw.h"

struct nv04_pm_state {
	struct pll_lims pll;
	struct nouveau_pll_vals calc;
};

int
nv04_pm_clock_get(struct drm_device *dev, u32 id)
{
	return nouveau_hw_get_clock(dev, id);
}

void *
nv04_pm_clock_pre(struct drm_device *dev, u32 id, int khz)
{
	struct nv04_pm_state *state;
	int ret;

	state = kzalloc(sizeof(*state), GFP_KERNEL);
	if (!state)
		return ERR_PTR(-ENOMEM);

	ret = get_pll_limits(dev, id, &state->pll);
	if (ret) {
		kfree(state);
		return ERR_PTR(ret);
	}

	ret = nouveau_calc_pll_mnp(dev, &state->pll, khz, &state->calc);
	if (!ret) {
		kfree(state);
		return ERR_PTR(-EINVAL);
	}

	return state;
}

void
nv04_pm_clock_set(struct drm_device *dev, void *pre_state)
{
	struct drm_nouveau_private *dev_priv = dev->dev_private;
	struct nv04_pm_state *state = pre_state;
	u32 reg = state->pll.reg;

	/* thank the insane nouveau_hw_setpll() interface for this */
	if (dev_priv->card_type >= NV_40)
		reg += 4;

	nouveau_hw_setpll(dev, reg, &state->calc);
	kfree(state);
}