Merge remote branch 'nouveau/for-airlied' of ../drm-nouveau-next into drm-core-next

* 'nouveau/for-airlied' of ../drm-nouveau-next: (77 commits)
  drm/nouveau: set TASK_(UN)INTERRUPTIBLE before schedule_timeout()
  drm/nv50: fix some not-error error messages
  drm/nouveau: introduce gpio engine
  drm/nv50: correct wait condition for instmem flush
  drm/nouveau: Fix TV-out detection on unposted cards lacking a usable DCB table.
  drm/nouveau: Get rid of the remaining VGA CRTC locking.
  drm/nouveau: Move display init to a new nouveau_engine.
  drm/nouveau: Put back the old 2-messages I2C slave test.
  drm/nouveau: Reset AGP before running the init scripts.
  drm/nv30: Init the PFB+0x3xx memory timing regs.
  drm/nouveau: disable hotplug detect around DP link training
  drm/nv50: add function to control GPIO IRQ reporting
  drm/nouveau: add nv_mask register accessor
  drm/nouveau: fix build without CONFIG_ACPI
  drm/nouveau: Reset CRTC owner to 0 before BIOS init.
  drm/nouveau: No need to lock/unlock the VGA CRTC regs all the time.
  drm/nouveau: Remove useless CRTC_OWNER logging.
  drm/nouveau: Add some generic I2C gadget detection code.
  drm/i2c/ch7006: Don't assume that the specified config points to static memory.
  drm/nv04-nv3x: Implement init-compute-mem.
  ...

Conflicts:
	drivers/gpu/drm/nouveau/nouveau_bios.c
This commit is contained in:
Dave Airlie 2010-08-02 10:31:47 +10:00
commit d6486813d2
55 changed files with 2099 additions and 1987 deletions

View file

@ -33,7 +33,7 @@ static void ch7006_encoder_set_config(struct drm_encoder *encoder,
{
struct ch7006_priv *priv = to_ch7006_priv(encoder);
priv->params = params;
priv->params = *(struct ch7006_encoder_params *)params;
}
static void ch7006_encoder_destroy(struct drm_encoder *encoder)
@ -114,7 +114,7 @@ static void ch7006_encoder_mode_set(struct drm_encoder *encoder,
{
struct i2c_client *client = drm_i2c_encoder_get_client(encoder);
struct ch7006_priv *priv = to_ch7006_priv(encoder);
struct ch7006_encoder_params *params = priv->params;
struct ch7006_encoder_params *params = &priv->params;
struct ch7006_state *state = &priv->state;
uint8_t *regs = state->regs;
struct ch7006_mode *mode = priv->mode;
@ -428,6 +428,22 @@ static int ch7006_remove(struct i2c_client *client)
return 0;
}
static int ch7006_suspend(struct i2c_client *client, pm_message_t mesg)
{
ch7006_dbg(client, "\n");
return 0;
}
static int ch7006_resume(struct i2c_client *client)
{
ch7006_dbg(client, "\n");
ch7006_write(client, 0x3d, 0x0);
return 0;
}
static int ch7006_encoder_init(struct i2c_client *client,
struct drm_device *dev,
struct drm_encoder_slave *encoder)
@ -487,6 +503,8 @@ static struct drm_i2c_encoder_driver ch7006_driver = {
.i2c_driver = {
.probe = ch7006_probe,
.remove = ch7006_remove,
.suspend = ch7006_suspend,
.resume = ch7006_resume,
.driver = {
.name = "ch7006",

View file

@ -77,7 +77,7 @@ struct ch7006_state {
};
struct ch7006_priv {
struct ch7006_encoder_params *params;
struct ch7006_encoder_params params;
struct ch7006_mode *mode;
struct ch7006_state state;

View file

@ -9,10 +9,10 @@ nouveau-y := nouveau_drv.o nouveau_state.o nouveau_channel.o nouveau_mem.o \
nouveau_bo.o nouveau_fence.o nouveau_gem.o nouveau_ttm.o \
nouveau_hw.o nouveau_calc.o nouveau_bios.o nouveau_i2c.o \
nouveau_display.o nouveau_connector.o nouveau_fbcon.o \
nouveau_dp.o nouveau_grctx.o \
nouveau_dp.o \
nv04_timer.o \
nv04_mc.o nv40_mc.o nv50_mc.o \
nv04_fb.o nv10_fb.o nv40_fb.o nv50_fb.o \
nv04_fb.o nv10_fb.o nv30_fb.o nv40_fb.o nv50_fb.o \
nv04_fifo.o nv10_fifo.o nv40_fifo.o nv50_fifo.o \
nv04_graph.o nv10_graph.o nv20_graph.o \
nv40_graph.o nv50_graph.o \
@ -22,7 +22,7 @@ nouveau-y := nouveau_drv.o nouveau_state.o nouveau_channel.o nouveau_mem.o \
nv50_cursor.o nv50_display.o nv50_fbcon.o \
nv04_dac.o nv04_dfp.o nv04_tv.o nv17_tv.o nv17_tv_modes.o \
nv04_crtc.o nv04_display.o nv04_cursor.o nv04_fbcon.o \
nv17_gpio.o nv50_gpio.o \
nv10_gpio.o nv50_gpio.o \
nv50_calc.o
nouveau-$(CONFIG_DRM_NOUVEAU_DEBUG) += nouveau_debugfs.o

View file

@ -3,6 +3,7 @@
#include <linux/slab.h>
#include <acpi/acpi_drivers.h>
#include <acpi/acpi_bus.h>
#include <acpi/video.h>
#include "drmP.h"
#include "drm.h"
@ -11,6 +12,7 @@
#include "nouveau_drv.h"
#include "nouveau_drm.h"
#include "nv50_display.h"
#include "nouveau_connector.h"
#include <linux/vga_switcheroo.h>
@ -42,7 +44,7 @@ static const char nouveau_dsm_muid[] = {
0xB3, 0x4D, 0x7E, 0x5F, 0xEA, 0x12, 0x9F, 0xD4,
};
static int nouveau_dsm(acpi_handle handle, int func, int arg, int *result)
static int nouveau_dsm(acpi_handle handle, int func, int arg, uint32_t *result)
{
struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
struct acpi_object_list input;
@ -259,3 +261,37 @@ int nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len)
{
return nouveau_rom_call(nouveau_dsm_priv.rom_handle, bios, offset, len);
}
int
nouveau_acpi_edid(struct drm_device *dev, struct drm_connector *connector)
{
struct nouveau_connector *nv_connector = nouveau_connector(connector);
struct acpi_device *acpidev;
acpi_handle handle;
int type, ret;
void *edid;
switch (connector->connector_type) {
case DRM_MODE_CONNECTOR_LVDS:
case DRM_MODE_CONNECTOR_eDP:
type = ACPI_VIDEO_DISPLAY_LCD;
break;
default:
return -EINVAL;
}
handle = DEVICE_ACPI_HANDLE(&dev->pdev->dev);
if (!handle)
return -ENODEV;
ret = acpi_bus_get_device(handle, &acpidev);
if (ret)
return -ENODEV;
ret = acpi_video_get_edid(acpidev, type, -1, &edid);
if (ret < 0)
return ret;
nv_connector->edid = edid;
return 0;
}

File diff suppressed because it is too large Load diff

View file

@ -81,6 +81,7 @@ struct dcb_connector_table_entry {
enum dcb_connector_type type;
uint8_t index2;
uint8_t gpio_tag;
void *drm;
};
struct dcb_connector_table {
@ -117,6 +118,7 @@ struct dcb_entry {
struct {
struct sor_conf sor;
bool use_straps_for_mode;
bool use_acpi_for_edid;
bool use_power_scripts;
} lvdsconf;
struct {
@ -249,8 +251,6 @@ struct nvbios {
struct {
int crtchead;
/* these need remembering across suspend */
uint32_t saved_nv_pfb_cfg0;
} state;
struct {

View file

@ -461,9 +461,9 @@ nouveau_bo_move_accel_cleanup(struct nouveau_channel *chan,
return ret;
ret = ttm_bo_move_accel_cleanup(&nvbo->bo, fence, NULL,
evict, no_wait_reserve, no_wait_gpu, new_mem);
if (nvbo->channel && nvbo->channel != chan)
ret = nouveau_fence_wait(fence, NULL, false, false);
evict || (nvbo->channel &&
nvbo->channel != chan),
no_wait_reserve, no_wait_gpu, new_mem);
nouveau_fence_unref((void *)&fence);
return ret;
}
@ -711,8 +711,7 @@ nouveau_bo_move(struct ttm_buffer_object *bo, bool evict, bool intr,
return ret;
/* Software copy if the card isn't up and running yet. */
if (dev_priv->init_state != NOUVEAU_CARD_INIT_DONE ||
!dev_priv->channel) {
if (!dev_priv->channel) {
ret = ttm_bo_move_memcpy(bo, evict, no_wait_reserve, no_wait_gpu, new_mem);
goto out;
}

View file

@ -200,7 +200,7 @@ nv04_update_arb(struct drm_device *dev, int VClk, int bpp,
struct nv_sim_state sim_data;
int MClk = nouveau_hw_get_clock(dev, MPLL);
int NVClk = nouveau_hw_get_clock(dev, NVPLL);
uint32_t cfg1 = nvReadFB(dev, NV_PFB_CFG1);
uint32_t cfg1 = nvReadFB(dev, NV04_PFB_CFG1);
sim_data.pclk_khz = VClk;
sim_data.mclk_khz = MClk;
@ -218,7 +218,7 @@ nv04_update_arb(struct drm_device *dev, int VClk, int bpp,
sim_data.mem_latency = 3;
sim_data.mem_page_miss = 10;
} else {
sim_data.memory_type = nvReadFB(dev, NV_PFB_CFG0) & 0x1;
sim_data.memory_type = nvReadFB(dev, NV04_PFB_CFG0) & 0x1;
sim_data.memory_width = (nvReadEXTDEV(dev, NV_PEXTDEV_BOOT_0) & 0x10) ? 128 : 64;
sim_data.mem_latency = cfg1 & 0xf;
sim_data.mem_page_miss = ((cfg1 >> 4) & 0xf) + ((cfg1 >> 31) & 0x1);

View file

@ -258,9 +258,7 @@ nouveau_channel_free(struct nouveau_channel *chan)
nouveau_debugfs_channel_fini(chan);
/* Give outstanding push buffers a chance to complete */
spin_lock_irqsave(&chan->fence.lock, flags);
nouveau_fence_update(chan);
spin_unlock_irqrestore(&chan->fence.lock, flags);
if (chan->fence.sequence != chan->fence.sequence_ack) {
struct nouveau_fence *fence = NULL;
@ -369,8 +367,6 @@ nouveau_ioctl_fifo_alloc(struct drm_device *dev, void *data,
struct nouveau_channel *chan;
int ret;
NOUVEAU_CHECK_INITIALISED_WITH_RETURN;
if (dev_priv->engine.graph.accel_blocked)
return -ENODEV;
@ -419,7 +415,6 @@ nouveau_ioctl_fifo_free(struct drm_device *dev, void *data,
struct drm_nouveau_channel_free *cfree = data;
struct nouveau_channel *chan;
NOUVEAU_CHECK_INITIALISED_WITH_RETURN;
NOUVEAU_GET_USER_CHANNEL_WITH_RETURN(cfree->channel, file_priv, chan);
nouveau_channel_free(chan);

View file

@ -102,63 +102,15 @@ nouveau_connector_destroy(struct drm_connector *drm_connector)
kfree(drm_connector);
}
static void
nouveau_connector_ddc_prepare(struct drm_connector *connector, int *flags)
{
struct drm_nouveau_private *dev_priv = connector->dev->dev_private;
if (dev_priv->card_type >= NV_50)
return;
*flags = 0;
if (NVLockVgaCrtcs(dev_priv->dev, false))
*flags |= 1;
if (nv_heads_tied(dev_priv->dev))
*flags |= 2;
if (*flags & 2)
NVSetOwner(dev_priv->dev, 0); /* necessary? */
}
static void
nouveau_connector_ddc_finish(struct drm_connector *connector, int flags)
{
struct drm_nouveau_private *dev_priv = connector->dev->dev_private;
if (dev_priv->card_type >= NV_50)
return;
if (flags & 2)
NVSetOwner(dev_priv->dev, 4);
if (flags & 1)
NVLockVgaCrtcs(dev_priv->dev, true);
}
static struct nouveau_i2c_chan *
nouveau_connector_ddc_detect(struct drm_connector *connector,
struct nouveau_encoder **pnv_encoder)
{
struct drm_device *dev = connector->dev;
uint8_t out_buf[] = { 0x0, 0x0}, buf[2];
int ret, flags, i;
struct i2c_msg msgs[] = {
{
.addr = 0x50,
.flags = 0,
.len = 1,
.buf = out_buf,
},
{
.addr = 0x50,
.flags = I2C_M_RD,
.len = 1,
.buf = buf,
}
};
int i;
for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
struct nouveau_i2c_chan *i2c = NULL;
struct nouveau_i2c_chan *i2c;
struct nouveau_encoder *nv_encoder;
struct drm_mode_object *obj;
int id;
@ -171,17 +123,9 @@ nouveau_connector_ddc_detect(struct drm_connector *connector,
if (!obj)
continue;
nv_encoder = nouveau_encoder(obj_to_encoder(obj));
i2c = nouveau_i2c_find(dev, nv_encoder->dcb->i2c_index);
if (nv_encoder->dcb->i2c_index < 0xf)
i2c = nouveau_i2c_find(dev, nv_encoder->dcb->i2c_index);
if (!i2c)
continue;
nouveau_connector_ddc_prepare(connector, &flags);
ret = i2c_transfer(&i2c->adapter, msgs, 2);
nouveau_connector_ddc_finish(connector, flags);
if (ret == 2) {
if (i2c && nouveau_probe_i2c_addr(i2c, 0x50)) {
*pnv_encoder = nv_encoder;
return i2c;
}
@ -234,21 +178,7 @@ nouveau_connector_detect(struct drm_connector *connector)
struct nouveau_connector *nv_connector = nouveau_connector(connector);
struct nouveau_encoder *nv_encoder = NULL;
struct nouveau_i2c_chan *i2c;
int type, flags;
if (nv_connector->dcb->type == DCB_CONNECTOR_LVDS)
nv_encoder = find_encoder_by_type(connector, OUTPUT_LVDS);
if (nv_encoder && nv_connector->native_mode) {
unsigned status = connector_status_connected;
#if defined(CONFIG_ACPI_BUTTON) || \
(defined(CONFIG_ACPI_BUTTON_MODULE) && defined(MODULE))
if (!nouveau_ignorelid && !acpi_lid_open())
status = connector_status_unknown;
#endif
nouveau_connector_set_encoder(connector, nv_encoder);
return status;
}
int type;
/* Cleanup the previous EDID block. */
if (nv_connector->edid) {
@ -259,9 +189,7 @@ nouveau_connector_detect(struct drm_connector *connector)
i2c = nouveau_connector_ddc_detect(connector, &nv_encoder);
if (i2c) {
nouveau_connector_ddc_prepare(connector, &flags);
nv_connector->edid = drm_get_edid(connector, &i2c->adapter);
nouveau_connector_ddc_finish(connector, flags);
drm_mode_connector_update_edid_property(connector,
nv_connector->edid);
if (!nv_connector->edid) {
@ -321,6 +249,85 @@ detect_analog:
return connector_status_disconnected;
}
static enum drm_connector_status
nouveau_connector_detect_lvds(struct drm_connector *connector)
{
struct drm_device *dev = connector->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_connector *nv_connector = nouveau_connector(connector);
struct nouveau_encoder *nv_encoder = NULL;
enum drm_connector_status status = connector_status_disconnected;
/* Cleanup the previous EDID block. */
if (nv_connector->edid) {
drm_mode_connector_update_edid_property(connector, NULL);
kfree(nv_connector->edid);
nv_connector->edid = NULL;
}
nv_encoder = find_encoder_by_type(connector, OUTPUT_LVDS);
if (!nv_encoder)
return connector_status_disconnected;
/* Try retrieving EDID via DDC */
if (!dev_priv->vbios.fp_no_ddc) {
status = nouveau_connector_detect(connector);
if (status == connector_status_connected)
goto out;
}
/* On some laptops (Sony, i'm looking at you) there appears to
* be no direct way of accessing the panel's EDID. The only
* option available to us appears to be to ask ACPI for help..
*
* It's important this check's before trying straps, one of the
* said manufacturer's laptops are configured in such a way
* the nouveau decides an entry in the VBIOS FP mode table is
* valid - it's not (rh#613284)
*/
if (nv_encoder->dcb->lvdsconf.use_acpi_for_edid) {
if (!nouveau_acpi_edid(dev, connector)) {
status = connector_status_connected;
goto out;
}
}
/* If no EDID found above, and the VBIOS indicates a hardcoded
* modeline is avalilable for the panel, set it as the panel's
* native mode and exit.
*/
if (nouveau_bios_fp_mode(dev, NULL) && (dev_priv->vbios.fp_no_ddc ||
nv_encoder->dcb->lvdsconf.use_straps_for_mode)) {
status = connector_status_connected;
goto out;
}
/* Still nothing, some VBIOS images have a hardcoded EDID block
* stored for the panel stored in them.
*/
if (!dev_priv->vbios.fp_no_ddc) {
struct edid *edid =
(struct edid *)nouveau_bios_embedded_edid(dev);
if (edid) {
nv_connector->edid = kmalloc(EDID_LENGTH, GFP_KERNEL);
*(nv_connector->edid) = *edid;
status = connector_status_connected;
}
}
out:
#if defined(CONFIG_ACPI_BUTTON) || \
(defined(CONFIG_ACPI_BUTTON_MODULE) && defined(MODULE))
if (status == connector_status_connected &&
!nouveau_ignorelid && !acpi_lid_open())
status = connector_status_unknown;
#endif
drm_mode_connector_update_edid_property(connector, nv_connector->edid);
nouveau_connector_set_encoder(connector, nv_encoder);
return status;
}
static void
nouveau_connector_force(struct drm_connector *connector)
{
@ -441,7 +448,8 @@ nouveau_connector_native_mode(struct drm_connector *connector)
int high_w = 0, high_h = 0, high_v = 0;
list_for_each_entry(mode, &nv_connector->base.probed_modes, head) {
if (helper->mode_valid(connector, mode) != MODE_OK)
if (helper->mode_valid(connector, mode) != MODE_OK ||
(mode->flags & DRM_MODE_FLAG_INTERLACE))
continue;
/* Use preferred mode if there is one.. */
@ -534,21 +542,27 @@ static int
nouveau_connector_get_modes(struct drm_connector *connector)
{
struct drm_device *dev = connector->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_connector *nv_connector = nouveau_connector(connector);
struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder;
int ret = 0;
/* If we're not LVDS, destroy the previous native mode, the attached
* monitor could have changed.
/* destroy the native mode, the attached monitor could have changed.
*/
if (nv_connector->dcb->type != DCB_CONNECTOR_LVDS &&
nv_connector->native_mode) {
if (nv_connector->native_mode) {
drm_mode_destroy(dev, nv_connector->native_mode);
nv_connector->native_mode = NULL;
}
if (nv_connector->edid)
ret = drm_add_edid_modes(connector, nv_connector->edid);
else
if (nv_encoder->dcb->type == OUTPUT_LVDS &&
(nv_encoder->dcb->lvdsconf.use_straps_for_mode ||
dev_priv->vbios.fp_no_ddc) && nouveau_bios_fp_mode(dev, NULL)) {
nv_connector->native_mode = drm_mode_create(dev);
nouveau_bios_fp_mode(dev, nv_connector->native_mode);
}
/* Find the native mode if this is a digital panel, if we didn't
* find any modes through DDC previously add the native mode to
@ -569,7 +583,8 @@ nouveau_connector_get_modes(struct drm_connector *connector)
ret = get_slave_funcs(nv_encoder)->
get_modes(to_drm_encoder(nv_encoder), connector);
if (nv_encoder->dcb->type == OUTPUT_LVDS)
if (nv_connector->dcb->type == DCB_CONNECTOR_LVDS ||
nv_connector->dcb->type == DCB_CONNECTOR_eDP)
ret += nouveau_connector_scaler_modes_add(connector);
return ret;
@ -643,6 +658,44 @@ nouveau_connector_best_encoder(struct drm_connector *connector)
return NULL;
}
void
nouveau_connector_set_polling(struct drm_connector *connector)
{
struct drm_device *dev = connector->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct drm_crtc *crtc;
bool spare_crtc = false;
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
spare_crtc |= !crtc->enabled;
connector->polled = 0;
switch (connector->connector_type) {
case DRM_MODE_CONNECTOR_VGA:
case DRM_MODE_CONNECTOR_TV:
if (dev_priv->card_type >= NV_50 ||
(nv_gf4_disp_arch(dev) && spare_crtc))
connector->polled = DRM_CONNECTOR_POLL_CONNECT;
break;
case DRM_MODE_CONNECTOR_DVII:
case DRM_MODE_CONNECTOR_DVID:
case DRM_MODE_CONNECTOR_HDMIA:
case DRM_MODE_CONNECTOR_DisplayPort:
case DRM_MODE_CONNECTOR_eDP:
if (dev_priv->card_type >= NV_50)
connector->polled = DRM_CONNECTOR_POLL_HPD;
else if (connector->connector_type == DRM_MODE_CONNECTOR_DVID ||
spare_crtc)
connector->polled = DRM_CONNECTOR_POLL_CONNECT;
break;
default:
break;
}
}
static const struct drm_connector_helper_funcs
nouveau_connector_helper_funcs = {
.get_modes = nouveau_connector_get_modes,
@ -662,148 +715,74 @@ nouveau_connector_funcs = {
.force = nouveau_connector_force
};
static int
nouveau_connector_create_lvds(struct drm_device *dev,
struct drm_connector *connector)
{
struct nouveau_connector *nv_connector = nouveau_connector(connector);
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_i2c_chan *i2c = NULL;
struct nouveau_encoder *nv_encoder;
struct drm_display_mode native, *mode, *temp;
bool dummy, if_is_24bit = false;
int ret, flags;
nv_encoder = find_encoder_by_type(connector, OUTPUT_LVDS);
if (!nv_encoder)
return -ENODEV;
ret = nouveau_bios_parse_lvds_table(dev, 0, &dummy, &if_is_24bit);
if (ret) {
NV_ERROR(dev, "Error parsing LVDS table, disabling LVDS\n");
return ret;
}
nv_connector->use_dithering = !if_is_24bit;
/* Firstly try getting EDID over DDC, if allowed and I2C channel
* is available.
*/
if (!dev_priv->vbios.fp_no_ddc && nv_encoder->dcb->i2c_index < 0xf)
i2c = nouveau_i2c_find(dev, nv_encoder->dcb->i2c_index);
if (i2c) {
nouveau_connector_ddc_prepare(connector, &flags);
nv_connector->edid = drm_get_edid(connector, &i2c->adapter);
nouveau_connector_ddc_finish(connector, flags);
}
/* If no EDID found above, and the VBIOS indicates a hardcoded
* modeline is avalilable for the panel, set it as the panel's
* native mode and exit.
*/
if (!nv_connector->edid && nouveau_bios_fp_mode(dev, &native) &&
(nv_encoder->dcb->lvdsconf.use_straps_for_mode ||
dev_priv->vbios.fp_no_ddc)) {
nv_connector->native_mode = drm_mode_duplicate(dev, &native);
goto out;
}
/* Still nothing, some VBIOS images have a hardcoded EDID block
* stored for the panel stored in them.
*/
if (!nv_connector->edid && !nv_connector->native_mode &&
!dev_priv->vbios.fp_no_ddc) {
struct edid *edid =
(struct edid *)nouveau_bios_embedded_edid(dev);
if (edid) {
nv_connector->edid = kmalloc(EDID_LENGTH, GFP_KERNEL);
*(nv_connector->edid) = *edid;
}
}
if (!nv_connector->edid)
goto out;
/* We didn't find/use a panel mode from the VBIOS, so parse the EDID
* block and look for the preferred mode there.
*/
ret = drm_add_edid_modes(connector, nv_connector->edid);
if (ret == 0)
goto out;
nv_connector->detected_encoder = nv_encoder;
nv_connector->native_mode = nouveau_connector_native_mode(connector);
list_for_each_entry_safe(mode, temp, &connector->probed_modes, head)
drm_mode_remove(connector, mode);
out:
if (!nv_connector->native_mode) {
NV_ERROR(dev, "LVDS present in DCB table, but couldn't "
"determine its native mode. Disabling.\n");
return -ENODEV;
}
drm_mode_connector_update_edid_property(connector, nv_connector->edid);
return 0;
}
int
nouveau_connector_create(struct drm_device *dev,
struct dcb_connector_table_entry *dcb)
static const struct drm_connector_funcs
nouveau_connector_funcs_lvds = {
.dpms = drm_helper_connector_dpms,
.save = NULL,
.restore = NULL,
.detect = nouveau_connector_detect_lvds,
.destroy = nouveau_connector_destroy,
.fill_modes = drm_helper_probe_single_connector_modes,
.set_property = nouveau_connector_set_property,
.force = nouveau_connector_force
};
struct drm_connector *
nouveau_connector_create(struct drm_device *dev, int index)
{
const struct drm_connector_funcs *funcs = &nouveau_connector_funcs;
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_connector *nv_connector = NULL;
struct dcb_connector_table_entry *dcb = NULL;
struct drm_connector *connector;
struct drm_encoder *encoder;
int ret, type;
int type, ret = 0;
NV_DEBUG_KMS(dev, "\n");
if (index >= dev_priv->vbios.dcb.connector.entries)
return ERR_PTR(-EINVAL);
dcb = &dev_priv->vbios.dcb.connector.entry[index];
if (dcb->drm)
return dcb->drm;
switch (dcb->type) {
case DCB_CONNECTOR_NONE:
return 0;
case DCB_CONNECTOR_VGA:
NV_INFO(dev, "Detected a VGA connector\n");
type = DRM_MODE_CONNECTOR_VGA;
break;
case DCB_CONNECTOR_TV_0:
case DCB_CONNECTOR_TV_1:
case DCB_CONNECTOR_TV_3:
NV_INFO(dev, "Detected a TV connector\n");
type = DRM_MODE_CONNECTOR_TV;
break;
case DCB_CONNECTOR_DVI_I:
NV_INFO(dev, "Detected a DVI-I connector\n");
type = DRM_MODE_CONNECTOR_DVII;
break;
case DCB_CONNECTOR_DVI_D:
NV_INFO(dev, "Detected a DVI-D connector\n");
type = DRM_MODE_CONNECTOR_DVID;
break;
case DCB_CONNECTOR_HDMI_0:
case DCB_CONNECTOR_HDMI_1:
NV_INFO(dev, "Detected a HDMI connector\n");
type = DRM_MODE_CONNECTOR_HDMIA;
break;
case DCB_CONNECTOR_LVDS:
NV_INFO(dev, "Detected a LVDS connector\n");
type = DRM_MODE_CONNECTOR_LVDS;
funcs = &nouveau_connector_funcs_lvds;
break;
case DCB_CONNECTOR_DP:
NV_INFO(dev, "Detected a DisplayPort connector\n");
type = DRM_MODE_CONNECTOR_DisplayPort;
break;
case DCB_CONNECTOR_eDP:
NV_INFO(dev, "Detected an eDP connector\n");
type = DRM_MODE_CONNECTOR_eDP;
break;
default:
NV_ERROR(dev, "unknown connector type: 0x%02x!!\n", dcb->type);
return -EINVAL;
return ERR_PTR(-EINVAL);
}
nv_connector = kzalloc(sizeof(*nv_connector), GFP_KERNEL);
if (!nv_connector)
return -ENOMEM;
return ERR_PTR(-ENOMEM);
nv_connector->dcb = dcb;
connector = &nv_connector->base;
@ -811,27 +790,21 @@ nouveau_connector_create(struct drm_device *dev,
connector->interlace_allowed = false;
connector->doublescan_allowed = false;
drm_connector_init(dev, connector, &nouveau_connector_funcs, type);
drm_connector_init(dev, connector, funcs, type);
drm_connector_helper_add(connector, &nouveau_connector_helper_funcs);
/* attach encoders */
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
/* Check if we need dithering enabled */
if (dcb->type == DCB_CONNECTOR_LVDS) {
bool dummy, is_24bit = false;
if (nv_encoder->dcb->connector != dcb->index)
continue;
ret = nouveau_bios_parse_lvds_table(dev, 0, &dummy, &is_24bit);
if (ret) {
NV_ERROR(dev, "Error parsing LVDS table, disabling "
"LVDS\n");
goto fail;
}
if (get_slave_funcs(nv_encoder))
get_slave_funcs(nv_encoder)->create_resources(encoder, connector);
drm_mode_connector_attach_encoder(connector, encoder);
}
if (!connector->encoder_ids[0]) {
NV_WARN(dev, " no encoders, ignoring\n");
drm_connector_cleanup(connector);
kfree(connector);
return 0;
nv_connector->use_dithering = !is_24bit;
}
/* Init DVI-I specific properties */
@ -841,12 +814,8 @@ nouveau_connector_create(struct drm_device *dev,
drm_connector_attach_property(connector, dev->mode_config.dvi_i_select_subconnector_property, 0);
}
if (dcb->type != DCB_CONNECTOR_LVDS)
nv_connector->use_dithering = false;
switch (dcb->type) {
case DCB_CONNECTOR_VGA:
connector->polled = DRM_CONNECTOR_POLL_CONNECT;
if (dev_priv->card_type >= NV_50) {
drm_connector_attach_property(connector,
dev->mode_config.scaling_mode_property,
@ -858,17 +827,6 @@ nouveau_connector_create(struct drm_device *dev,
case DCB_CONNECTOR_TV_3:
nv_connector->scaling_mode = DRM_MODE_SCALE_NONE;
break;
case DCB_CONNECTOR_DP:
case DCB_CONNECTOR_eDP:
case DCB_CONNECTOR_HDMI_0:
case DCB_CONNECTOR_HDMI_1:
case DCB_CONNECTOR_DVI_I:
case DCB_CONNECTOR_DVI_D:
if (dev_priv->card_type >= NV_50)
connector->polled = DRM_CONNECTOR_POLL_HPD;
else
connector->polled = DRM_CONNECTOR_POLL_CONNECT;
/* fall-through */
default:
nv_connector->scaling_mode = DRM_MODE_SCALE_FULLSCREEN;
@ -882,15 +840,15 @@ nouveau_connector_create(struct drm_device *dev,
break;
}
nouveau_connector_set_polling(connector);
drm_sysfs_connector_add(connector);
dcb->drm = connector;
return dcb->drm;
if (dcb->type == DCB_CONNECTOR_LVDS) {
ret = nouveau_connector_create_lvds(dev, connector);
if (ret) {
connector->funcs->destroy(connector);
return ret;
}
}
fail:
drm_connector_cleanup(connector);
kfree(connector);
return ERR_PTR(ret);
return 0;
}

View file

@ -49,7 +49,10 @@ static inline struct nouveau_connector *nouveau_connector(
return container_of(con, struct nouveau_connector, base);
}
int nouveau_connector_create(struct drm_device *,
struct dcb_connector_table_entry *);
struct drm_connector *
nouveau_connector_create(struct drm_device *, int index);
void
nouveau_connector_set_polling(struct drm_connector *);
#endif /* __NOUVEAU_CONNECTOR_H__ */

View file

@ -92,11 +92,9 @@ nouveau_dma_init(struct nouveau_channel *chan)
return ret;
/* Map M2MF notifier object - fbcon. */
if (drm_core_check_feature(dev, DRIVER_MODESET)) {
ret = nouveau_bo_map(chan->notifier_bo);
if (ret)
return ret;
}
ret = nouveau_bo_map(chan->notifier_bo);
if (ret)
return ret;
/* Insert NOPS for NOUVEAU_DMA_SKIPS */
ret = RING_SPACE(chan, NOUVEAU_DMA_SKIPS);

View file

@ -23,8 +23,10 @@
*/
#include "drmP.h"
#include "nouveau_drv.h"
#include "nouveau_i2c.h"
#include "nouveau_connector.h"
#include "nouveau_encoder.h"
static int
@ -270,13 +272,39 @@ bool
nouveau_dp_link_train(struct drm_encoder *encoder)
{
struct drm_device *dev = encoder->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio;
struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
uint8_t config[4];
uint8_t status[3];
struct nouveau_connector *nv_connector;
struct bit_displayport_encoder_table *dpe;
int dpe_headerlen;
uint8_t config[4], status[3];
bool cr_done, cr_max_vs, eq_done;
int ret = 0, i, tries, voltage;
NV_DEBUG_KMS(dev, "link training!!\n");
nv_connector = nouveau_encoder_connector_get(nv_encoder);
if (!nv_connector)
return false;
dpe = nouveau_bios_dp_table(dev, nv_encoder->dcb, &dpe_headerlen);
if (!dpe) {
NV_ERROR(dev, "SOR-%d: no DP encoder table!\n", nv_encoder->or);
return false;
}
/* disable hotplug detect, this flips around on some panels during
* link training.
*/
pgpio->irq_enable(dev, nv_connector->dcb->gpio_tag, false);
if (dpe->script0) {
NV_DEBUG_KMS(dev, "SOR-%d: running DP script 0\n", nv_encoder->or);
nouveau_bios_run_init_table(dev, le16_to_cpu(dpe->script0),
nv_encoder->dcb);
}
train:
cr_done = eq_done = false;
@ -403,6 +431,15 @@ stop:
}
}
if (dpe->script1) {
NV_DEBUG_KMS(dev, "SOR-%d: running DP script 1\n", nv_encoder->or);
nouveau_bios_run_init_table(dev, le16_to_cpu(dpe->script1),
nv_encoder->dcb);
}
/* re-enable hotplug detect */
pgpio->irq_enable(dev, nv_connector->dcb->gpio_tag, true);
return eq_done;
}

View file

@ -35,10 +35,6 @@
#include "drm_pciids.h"
MODULE_PARM_DESC(ctxfw, "Use external firmware blob for grctx init (NV40)");
int nouveau_ctxfw = 0;
module_param_named(ctxfw, nouveau_ctxfw, int, 0400);
MODULE_PARM_DESC(noagp, "Disable AGP");
int nouveau_noagp;
module_param_named(noagp, nouveau_noagp, int, 0400);
@ -56,7 +52,7 @@ int nouveau_vram_pushbuf;
module_param_named(vram_pushbuf, nouveau_vram_pushbuf, int, 0400);
MODULE_PARM_DESC(vram_notify, "Force DMA notifiers to be in VRAM");
int nouveau_vram_notify = 1;
int nouveau_vram_notify = 0;
module_param_named(vram_notify, nouveau_vram_notify, int, 0400);
MODULE_PARM_DESC(duallink, "Allow dual-link TMDS (>=GeForce 8)");
@ -155,9 +151,6 @@ nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state)
struct drm_crtc *crtc;
int ret, i;
if (!drm_core_check_feature(dev, DRIVER_MODESET))
return -ENODEV;
if (pm_state.event == PM_EVENT_PRETHAW)
return 0;
@ -257,9 +250,6 @@ nouveau_pci_resume(struct pci_dev *pdev)
struct drm_crtc *crtc;
int ret, i;
if (!drm_core_check_feature(dev, DRIVER_MODESET))
return -ENODEV;
nouveau_fbcon_save_disable_accel(dev);
NV_INFO(dev, "We're back, enabling device...\n");
@ -269,6 +259,13 @@ nouveau_pci_resume(struct pci_dev *pdev)
return -1;
pci_set_master(dev->pdev);
/* Make sure the AGP controller is in a consistent state */
if (dev_priv->gart_info.type == NOUVEAU_GART_AGP)
nouveau_mem_reset_agp(dev);
/* Make the CRTCs accessible */
engine->display.early_init(dev);
NV_INFO(dev, "POSTing device...\n");
ret = nouveau_run_vbios_init(dev);
if (ret)
@ -323,7 +320,6 @@ nouveau_pci_resume(struct pci_dev *pdev)
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
int ret;
ret = nouveau_bo_pin(nv_crtc->cursor.nvbo, TTM_PL_FLAG_VRAM);
if (!ret)
@ -332,11 +328,7 @@ nouveau_pci_resume(struct pci_dev *pdev)
NV_ERROR(dev, "Could not pin/map cursor.\n");
}
if (dev_priv->card_type < NV_50) {
nv04_display_restore(dev);
NVLockVgaCrtcs(dev, false);
} else
nv50_display_init(dev);
engine->display.init(dev);
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
@ -371,7 +363,8 @@ nouveau_pci_resume(struct pci_dev *pdev)
static struct drm_driver driver = {
.driver_features =
DRIVER_USE_AGP | DRIVER_PCI_DMA | DRIVER_SG |
DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_GEM,
DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_GEM |
DRIVER_MODESET,
.load = nouveau_load,
.firstopen = nouveau_firstopen,
.lastclose = nouveau_lastclose,
@ -438,16 +431,18 @@ static int __init nouveau_init(void)
nouveau_modeset = 1;
}
if (nouveau_modeset == 1) {
driver.driver_features |= DRIVER_MODESET;
nouveau_register_dsm_handler();
}
if (!nouveau_modeset)
return 0;
nouveau_register_dsm_handler();
return drm_init(&driver);
}
static void __exit nouveau_exit(void)
{
if (!nouveau_modeset)
return;
drm_exit(&driver);
nouveau_unregister_dsm_handler();
}

View file

@ -123,14 +123,6 @@ nvbo_kmap_obj_iovirtual(struct nouveau_bo *nvbo)
return ioptr;
}
struct mem_block {
struct mem_block *next;
struct mem_block *prev;
uint64_t start;
uint64_t size;
struct drm_file *file_priv; /* NULL: free, -1: heap, other: real files */
};
enum nouveau_flags {
NV_NFORCE = 0x10000000,
NV_NFORCE2 = 0x20000000
@ -149,7 +141,7 @@ struct nouveau_gpuobj {
struct list_head list;
struct nouveau_channel *im_channel;
struct mem_block *im_pramin;
struct drm_mm_node *im_pramin;
struct nouveau_bo *im_backing;
uint32_t im_backing_start;
uint32_t *im_backing_suspend;
@ -196,7 +188,7 @@ struct nouveau_channel {
struct list_head pending;
uint32_t sequence;
uint32_t sequence_ack;
uint32_t last_sequence_irq;
atomic_t last_sequence_irq;
} fence;
/* DMA push buffer */
@ -206,7 +198,7 @@ struct nouveau_channel {
/* Notifier memory */
struct nouveau_bo *notifier_bo;
struct mem_block *notifier_heap;
struct drm_mm notifier_heap;
/* PFIFO context */
struct nouveau_gpuobj_ref *ramfc;
@ -224,7 +216,7 @@ struct nouveau_channel {
/* Objects */
struct nouveau_gpuobj_ref *ramin; /* Private instmem */
struct mem_block *ramin_heap; /* Private PRAMIN heap */
struct drm_mm ramin_heap; /* Private PRAMIN heap */
struct nouveau_gpuobj_ref *ramht; /* Hash table */
struct list_head ramht_refs; /* Objects referenced by RAMHT */
@ -277,8 +269,7 @@ struct nouveau_instmem_engine {
void (*clear)(struct drm_device *, struct nouveau_gpuobj *);
int (*bind)(struct drm_device *, struct nouveau_gpuobj *);
int (*unbind)(struct drm_device *, struct nouveau_gpuobj *);
void (*prepare_access)(struct drm_device *, bool write);
void (*finish_access)(struct drm_device *);
void (*flush)(struct drm_device *);
};
struct nouveau_mc_engine {
@ -303,10 +294,11 @@ struct nouveau_fb_engine {
};
struct nouveau_fifo_engine {
void *priv;
int channels;
struct nouveau_gpuobj_ref *playlist[2];
int cur_playlist;
int (*init)(struct drm_device *);
void (*takedown)(struct drm_device *);
@ -339,10 +331,11 @@ struct nouveau_pgraph_object_class {
struct nouveau_pgraph_engine {
struct nouveau_pgraph_object_class *grclass;
bool accel_blocked;
void *ctxprog;
void *ctxvals;
int grctx_size;
/* NV2x/NV3x context table (0x400780) */
struct nouveau_gpuobj_ref *ctx_table;
int (*init)(struct drm_device *);
void (*takedown)(struct drm_device *);
@ -358,6 +351,24 @@ struct nouveau_pgraph_engine {
uint32_t size, uint32_t pitch);
};
struct nouveau_display_engine {
int (*early_init)(struct drm_device *);
void (*late_takedown)(struct drm_device *);
int (*create)(struct drm_device *);
int (*init)(struct drm_device *);
void (*destroy)(struct drm_device *);
};
struct nouveau_gpio_engine {
int (*init)(struct drm_device *);
void (*takedown)(struct drm_device *);
int (*get)(struct drm_device *, enum dcb_gpio_tag);
int (*set)(struct drm_device *, enum dcb_gpio_tag, int state);
void (*irq_enable)(struct drm_device *, enum dcb_gpio_tag, bool on);
};
struct nouveau_engine {
struct nouveau_instmem_engine instmem;
struct nouveau_mc_engine mc;
@ -365,6 +376,8 @@ struct nouveau_engine {
struct nouveau_fb_engine fb;
struct nouveau_pgraph_engine graph;
struct nouveau_fifo_engine fifo;
struct nouveau_display_engine display;
struct nouveau_gpio_engine gpio;
};
struct nouveau_pll_vals {
@ -500,11 +513,6 @@ enum nouveau_card_type {
struct drm_nouveau_private {
struct drm_device *dev;
enum {
NOUVEAU_CARD_INIT_DOWN,
NOUVEAU_CARD_INIT_DONE,
NOUVEAU_CARD_INIT_FAILED
} init_state;
/* the card type, takes NV_* as values */
enum nouveau_card_type card_type;
@ -533,8 +541,6 @@ struct drm_nouveau_private {
atomic_t validate_sequence;
} ttm;
struct fb_info *fbdev_info;
int fifo_alloc_count;
struct nouveau_channel *fifos[NOUVEAU_MAX_CHANNEL_NR];
@ -595,11 +601,7 @@ struct drm_nouveau_private {
struct nouveau_gpuobj *vm_vram_pt[NV50_VM_VRAM_NR];
int vm_vram_pt_nr;
struct mem_block *ramin_heap;
/* context table pointed to be NV_PGRAPH_CHANNEL_CTX_TABLE (0x400780) */
uint32_t ctx_table_size;
struct nouveau_gpuobj_ref *ctx_table;
struct drm_mm ramin_heap;
struct list_head gpuobj_list;
@ -618,6 +620,11 @@ struct drm_nouveau_private {
struct backlight_device *backlight;
struct nouveau_channel *evo;
struct {
struct dcb_entry *dcb;
u16 script;
u32 pclk;
} evo_irq;
struct {
struct dentry *channel_root;
@ -652,14 +659,6 @@ nouveau_bo_ref(struct nouveau_bo *ref, struct nouveau_bo **pnvbo)
return 0;
}
#define NOUVEAU_CHECK_INITIALISED_WITH_RETURN do { \
struct drm_nouveau_private *nv = dev->dev_private; \
if (nv->init_state != NOUVEAU_CARD_INIT_DONE) { \
NV_ERROR(dev, "called without init\n"); \
return -EINVAL; \
} \
} while (0)
#define NOUVEAU_GET_USER_CHANNEL_WITH_RETURN(id, cl, ch) do { \
struct drm_nouveau_private *nv = dev->dev_private; \
if (!nouveau_channel_owner(dev, (cl), (id))) { \
@ -682,7 +681,6 @@ extern int nouveau_tv_disable;
extern char *nouveau_tv_norm;
extern int nouveau_reg_debug;
extern char *nouveau_vbios;
extern int nouveau_ctxfw;
extern int nouveau_ignorelid;
extern int nouveau_nofbaccel;
extern int nouveau_noaccel;
@ -707,17 +705,10 @@ extern bool nouveau_wait_for_idle(struct drm_device *);
extern int nouveau_card_init(struct drm_device *);
/* nouveau_mem.c */
extern int nouveau_mem_init_heap(struct mem_block **, uint64_t start,
uint64_t size);
extern struct mem_block *nouveau_mem_alloc_block(struct mem_block *,
uint64_t size, int align2,
struct drm_file *, int tail);
extern void nouveau_mem_takedown(struct mem_block **heap);
extern void nouveau_mem_free_block(struct mem_block *);
extern int nouveau_mem_detect(struct drm_device *dev);
extern void nouveau_mem_release(struct drm_file *, struct mem_block *heap);
extern int nouveau_mem_init(struct drm_device *);
extern int nouveau_mem_init_agp(struct drm_device *);
extern int nouveau_mem_reset_agp(struct drm_device *);
extern void nouveau_mem_close(struct drm_device *);
extern struct nouveau_tile_reg *nv10_mem_set_tiling(struct drm_device *dev,
uint32_t addr,
@ -857,11 +848,13 @@ void nouveau_register_dsm_handler(void);
void nouveau_unregister_dsm_handler(void);
int nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len);
bool nouveau_acpi_rom_supported(struct pci_dev *pdev);
int nouveau_acpi_edid(struct drm_device *, struct drm_connector *);
#else
static inline void nouveau_register_dsm_handler(void) {}
static inline void nouveau_unregister_dsm_handler(void) {}
static inline bool nouveau_acpi_rom_supported(struct pci_dev *pdev) { return false; }
static inline int nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len) { return -EINVAL; }
static inline int nouveau_acpi_edid(struct drm_device *dev, struct drm_connector *connector) { return -EINVAL; }
#endif
/* nouveau_backlight.c */
@ -924,6 +917,10 @@ extern void nv10_fb_takedown(struct drm_device *);
extern void nv10_fb_set_region_tiling(struct drm_device *, int, uint32_t,
uint32_t, uint32_t);
/* nv30_fb.c */
extern int nv30_fb_init(struct drm_device *);
extern void nv30_fb_takedown(struct drm_device *);
/* nv40_fb.c */
extern int nv40_fb_init(struct drm_device *);
extern void nv40_fb_takedown(struct drm_device *);
@ -1035,12 +1032,6 @@ extern int nv50_graph_unload_context(struct drm_device *);
extern void nv50_graph_context_switch(struct drm_device *);
extern int nv50_grctx_init(struct nouveau_grctx *);
/* nouveau_grctx.c */
extern int nouveau_grctx_prog_load(struct drm_device *);
extern void nouveau_grctx_vals_load(struct drm_device *,
struct nouveau_gpuobj *);
extern void nouveau_grctx_fini(struct drm_device *);
/* nv04_instmem.c */
extern int nv04_instmem_init(struct drm_device *);
extern void nv04_instmem_takedown(struct drm_device *);
@ -1051,8 +1042,7 @@ extern int nv04_instmem_populate(struct drm_device *, struct nouveau_gpuobj *,
extern void nv04_instmem_clear(struct drm_device *, struct nouveau_gpuobj *);
extern int nv04_instmem_bind(struct drm_device *, struct nouveau_gpuobj *);
extern int nv04_instmem_unbind(struct drm_device *, struct nouveau_gpuobj *);
extern void nv04_instmem_prepare_access(struct drm_device *, bool write);
extern void nv04_instmem_finish_access(struct drm_device *);
extern void nv04_instmem_flush(struct drm_device *);
/* nv50_instmem.c */
extern int nv50_instmem_init(struct drm_device *);
@ -1064,8 +1054,9 @@ extern int nv50_instmem_populate(struct drm_device *, struct nouveau_gpuobj *,
extern void nv50_instmem_clear(struct drm_device *, struct nouveau_gpuobj *);
extern int nv50_instmem_bind(struct drm_device *, struct nouveau_gpuobj *);
extern int nv50_instmem_unbind(struct drm_device *, struct nouveau_gpuobj *);
extern void nv50_instmem_prepare_access(struct drm_device *, bool write);
extern void nv50_instmem_finish_access(struct drm_device *);
extern void nv50_instmem_flush(struct drm_device *);
extern void nv84_instmem_flush(struct drm_device *);
extern void nv50_vm_flush(struct drm_device *, int engine);
/* nv04_mc.c */
extern int nv04_mc_init(struct drm_device *);
@ -1088,13 +1079,14 @@ extern long nouveau_compat_ioctl(struct file *file, unsigned int cmd,
unsigned long arg);
/* nv04_dac.c */
extern int nv04_dac_create(struct drm_device *dev, struct dcb_entry *entry);
extern int nv04_dac_create(struct drm_connector *, struct dcb_entry *);
extern uint32_t nv17_dac_sample_load(struct drm_encoder *encoder);
extern int nv04_dac_output_offset(struct drm_encoder *encoder);
extern void nv04_dac_update_dacclk(struct drm_encoder *encoder, bool enable);
extern bool nv04_dac_in_use(struct drm_encoder *encoder);
/* nv04_dfp.c */
extern int nv04_dfp_create(struct drm_device *dev, struct dcb_entry *entry);
extern int nv04_dfp_create(struct drm_connector *, struct dcb_entry *);
extern int nv04_dfp_get_bound_head(struct drm_device *dev, struct dcb_entry *dcbent);
extern void nv04_dfp_bind_head(struct drm_device *dev, struct dcb_entry *dcbent,
int head, bool dl);
@ -1103,15 +1095,17 @@ extern void nv04_dfp_update_fp_control(struct drm_encoder *encoder, int mode);
/* nv04_tv.c */
extern int nv04_tv_identify(struct drm_device *dev, int i2c_index);
extern int nv04_tv_create(struct drm_device *dev, struct dcb_entry *entry);
extern int nv04_tv_create(struct drm_connector *, struct dcb_entry *);
/* nv17_tv.c */
extern int nv17_tv_create(struct drm_device *dev, struct dcb_entry *entry);
extern int nv17_tv_create(struct drm_connector *, struct dcb_entry *);
/* nv04_display.c */
extern int nv04_display_early_init(struct drm_device *);
extern void nv04_display_late_takedown(struct drm_device *);
extern int nv04_display_create(struct drm_device *);
extern int nv04_display_init(struct drm_device *);
extern void nv04_display_destroy(struct drm_device *);
extern void nv04_display_restore(struct drm_device *);
/* nv04_crtc.c */
extern int nv04_crtc_create(struct drm_device *, int index);
@ -1147,7 +1141,6 @@ extern int nouveau_fence_wait(void *obj, void *arg, bool lazy, bool intr);
extern int nouveau_fence_flush(void *obj, void *arg);
extern void nouveau_fence_unref(void **obj);
extern void *nouveau_fence_ref(void *obj);
extern void nouveau_fence_handler(struct drm_device *dev, int channel);
/* nouveau_gem.c */
extern int nouveau_gem_new(struct drm_device *, struct nouveau_channel *,
@ -1167,13 +1160,15 @@ extern int nouveau_gem_ioctl_cpu_fini(struct drm_device *, void *,
extern int nouveau_gem_ioctl_info(struct drm_device *, void *,
struct drm_file *);
/* nv17_gpio.c */
int nv17_gpio_get(struct drm_device *dev, enum dcb_gpio_tag tag);
int nv17_gpio_set(struct drm_device *dev, enum dcb_gpio_tag tag, int state);
/* nv10_gpio.c */
int nv10_gpio_get(struct drm_device *dev, enum dcb_gpio_tag tag);
int nv10_gpio_set(struct drm_device *dev, enum dcb_gpio_tag tag, int state);
/* nv50_gpio.c */
int nv50_gpio_init(struct drm_device *dev);
int nv50_gpio_get(struct drm_device *dev, enum dcb_gpio_tag tag);
int nv50_gpio_set(struct drm_device *dev, enum dcb_gpio_tag tag, int state);
void nv50_gpio_irq_enable(struct drm_device *, enum dcb_gpio_tag, bool on);
/* nv50_calc. */
int nv50_calc_pll(struct drm_device *, struct pll_lims *, int clk,
@ -1220,6 +1215,14 @@ static inline void nv_wr32(struct drm_device *dev, unsigned reg, u32 val)
iowrite32_native(val, dev_priv->mmio + reg);
}
static inline void nv_mask(struct drm_device *dev, u32 reg, u32 mask, u32 val)
{
u32 tmp = nv_rd32(dev, reg);
tmp &= ~mask;
tmp |= val;
nv_wr32(dev, reg, tmp);
}
static inline u8 nv_rd08(struct drm_device *dev, unsigned reg)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;

View file

@ -38,13 +38,15 @@ struct nouveau_encoder {
struct dcb_entry *dcb;
int or;
/* different to drm_encoder.crtc, this reflects what's
* actually programmed on the hw, not the proposed crtc */
struct drm_crtc *crtc;
struct drm_display_mode mode;
int last_dpms;
struct nv04_output_reg restore;
void (*disconnect)(struct nouveau_encoder *encoder);
union {
struct {
int mc_unknown;
@ -71,8 +73,8 @@ static inline struct drm_encoder *to_drm_encoder(struct nouveau_encoder *enc)
struct nouveau_connector *
nouveau_encoder_connector_get(struct nouveau_encoder *encoder);
int nv50_sor_create(struct drm_device *dev, struct dcb_entry *entry);
int nv50_dac_create(struct drm_device *dev, struct dcb_entry *entry);
int nv50_sor_create(struct drm_connector *, struct dcb_entry *);
int nv50_dac_create(struct drm_connector *, struct dcb_entry *);
struct bit_displayport_encoder_table {
uint32_t match;

View file

@ -333,7 +333,7 @@ nouveau_fbcon_output_poll_changed(struct drm_device *dev)
drm_fb_helper_hotplug_event(&dev_priv->nfbdev->helper);
}
int
static int
nouveau_fbcon_destroy(struct drm_device *dev, struct nouveau_fbdev *nfbdev)
{
struct nouveau_framebuffer *nouveau_fb = &nfbdev->nouveau_fb;

View file

@ -67,12 +67,13 @@ nouveau_fence_update(struct nouveau_channel *chan)
if (USE_REFCNT)
sequence = nvchan_rd32(chan, 0x48);
else
sequence = chan->fence.last_sequence_irq;
sequence = atomic_read(&chan->fence.last_sequence_irq);
if (chan->fence.sequence_ack == sequence)
return;
chan->fence.sequence_ack = sequence;
spin_lock(&chan->fence.lock);
list_for_each_safe(entry, tmp, &chan->fence.pending) {
fence = list_entry(entry, struct nouveau_fence, entry);
@ -84,6 +85,7 @@ nouveau_fence_update(struct nouveau_channel *chan)
if (sequence == chan->fence.sequence_ack)
break;
}
spin_unlock(&chan->fence.lock);
}
int
@ -119,7 +121,6 @@ nouveau_fence_emit(struct nouveau_fence *fence)
{
struct drm_nouveau_private *dev_priv = fence->channel->dev->dev_private;
struct nouveau_channel *chan = fence->channel;
unsigned long flags;
int ret;
ret = RING_SPACE(chan, 2);
@ -127,9 +128,7 @@ nouveau_fence_emit(struct nouveau_fence *fence)
return ret;
if (unlikely(chan->fence.sequence == chan->fence.sequence_ack - 1)) {
spin_lock_irqsave(&chan->fence.lock, flags);
nouveau_fence_update(chan);
spin_unlock_irqrestore(&chan->fence.lock, flags);
BUG_ON(chan->fence.sequence ==
chan->fence.sequence_ack - 1);
@ -138,9 +137,9 @@ nouveau_fence_emit(struct nouveau_fence *fence)
fence->sequence = ++chan->fence.sequence;
kref_get(&fence->refcount);
spin_lock_irqsave(&chan->fence.lock, flags);
spin_lock(&chan->fence.lock);
list_add_tail(&fence->entry, &chan->fence.pending);
spin_unlock_irqrestore(&chan->fence.lock, flags);
spin_unlock(&chan->fence.lock);
BEGIN_RING(chan, NvSubSw, USE_REFCNT ? 0x0050 : 0x0150, 1);
OUT_RING(chan, fence->sequence);
@ -173,14 +172,11 @@ nouveau_fence_signalled(void *sync_obj, void *sync_arg)
{
struct nouveau_fence *fence = nouveau_fence(sync_obj);
struct nouveau_channel *chan = fence->channel;
unsigned long flags;
if (fence->signalled)
return true;
spin_lock_irqsave(&chan->fence.lock, flags);
nouveau_fence_update(chan);
spin_unlock_irqrestore(&chan->fence.lock, flags);
return fence->signalled;
}
@ -190,8 +186,6 @@ nouveau_fence_wait(void *sync_obj, void *sync_arg, bool lazy, bool intr)
unsigned long timeout = jiffies + (3 * DRM_HZ);
int ret = 0;
__set_current_state(intr ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE);
while (1) {
if (nouveau_fence_signalled(sync_obj, sync_arg))
break;
@ -201,6 +195,8 @@ nouveau_fence_wait(void *sync_obj, void *sync_arg, bool lazy, bool intr)
break;
}
__set_current_state(intr ? TASK_INTERRUPTIBLE
: TASK_UNINTERRUPTIBLE);
if (lazy)
schedule_timeout(1);
@ -221,27 +217,12 @@ nouveau_fence_flush(void *sync_obj, void *sync_arg)
return 0;
}
void
nouveau_fence_handler(struct drm_device *dev, int channel)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_channel *chan = NULL;
if (channel >= 0 && channel < dev_priv->engine.fifo.channels)
chan = dev_priv->fifos[channel];
if (chan) {
spin_lock_irq(&chan->fence.lock);
nouveau_fence_update(chan);
spin_unlock_irq(&chan->fence.lock);
}
}
int
nouveau_fence_init(struct nouveau_channel *chan)
{
INIT_LIST_HEAD(&chan->fence.pending);
spin_lock_init(&chan->fence.lock);
atomic_set(&chan->fence.last_sequence_irq, 0);
return 0;
}

View file

@ -137,8 +137,6 @@ nouveau_gem_ioctl_new(struct drm_device *dev, void *data,
uint32_t flags = 0;
int ret = 0;
NOUVEAU_CHECK_INITIALISED_WITH_RETURN;
if (unlikely(dev_priv->ttm.bdev.dev_mapping == NULL))
dev_priv->ttm.bdev.dev_mapping = dev_priv->dev->dev_mapping;
@ -577,10 +575,9 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data,
struct drm_nouveau_gem_pushbuf_bo *bo;
struct nouveau_channel *chan;
struct validate_op op;
struct nouveau_fence *fence = 0;
struct nouveau_fence *fence = NULL;
int i, j, ret = 0, do_reloc = 0;
NOUVEAU_CHECK_INITIALISED_WITH_RETURN;
NOUVEAU_GET_USER_CHANNEL_WITH_RETURN(req->channel, file_priv, chan);
req->vram_available = dev_priv->fb_aper_free;
@ -760,8 +757,6 @@ nouveau_gem_ioctl_cpu_prep(struct drm_device *dev, void *data,
bool no_wait = !!(req->flags & NOUVEAU_GEM_CPU_PREP_NOWAIT);
int ret = -EINVAL;
NOUVEAU_CHECK_INITIALISED_WITH_RETURN;
gem = drm_gem_object_lookup(dev, file_priv, req->handle);
if (!gem)
return ret;
@ -800,8 +795,6 @@ nouveau_gem_ioctl_cpu_fini(struct drm_device *dev, void *data,
struct nouveau_bo *nvbo;
int ret = -EINVAL;
NOUVEAU_CHECK_INITIALISED_WITH_RETURN;
gem = drm_gem_object_lookup(dev, file_priv, req->handle);
if (!gem)
return ret;
@ -827,8 +820,6 @@ nouveau_gem_ioctl_info(struct drm_device *dev, void *data,
struct drm_gem_object *gem;
int ret;
NOUVEAU_CHECK_INITIALISED_WITH_RETURN;
gem = drm_gem_object_lookup(dev, file_priv, req->handle);
if (!gem)
return -EINVAL;

View file

@ -1,160 +0,0 @@
/*
* Copyright 2009 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 <linux/firmware.h>
#include <linux/slab.h>
#include "drmP.h"
#include "nouveau_drv.h"
struct nouveau_ctxprog {
uint32_t signature;
uint8_t version;
uint16_t length;
uint32_t data[];
} __attribute__ ((packed));
struct nouveau_ctxvals {
uint32_t signature;
uint8_t version;
uint32_t length;
struct {
uint32_t offset;
uint32_t value;
} data[];
} __attribute__ ((packed));
int
nouveau_grctx_prog_load(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
const int chipset = dev_priv->chipset;
const struct firmware *fw;
const struct nouveau_ctxprog *cp;
const struct nouveau_ctxvals *cv;
char name[32];
int ret, i;
if (pgraph->accel_blocked)
return -ENODEV;
if (!pgraph->ctxprog) {
sprintf(name, "nouveau/nv%02x.ctxprog", chipset);
ret = request_firmware(&fw, name, &dev->pdev->dev);
if (ret) {
NV_ERROR(dev, "No ctxprog for NV%02x\n", chipset);
return ret;
}
pgraph->ctxprog = kmemdup(fw->data, fw->size, GFP_KERNEL);
if (!pgraph->ctxprog) {
NV_ERROR(dev, "OOM copying ctxprog\n");
release_firmware(fw);
return -ENOMEM;
}
cp = pgraph->ctxprog;
if (le32_to_cpu(cp->signature) != 0x5043564e ||
cp->version != 0 ||
le16_to_cpu(cp->length) != ((fw->size - 7) / 4)) {
NV_ERROR(dev, "ctxprog invalid\n");
release_firmware(fw);
nouveau_grctx_fini(dev);
return -EINVAL;
}
release_firmware(fw);
}
if (!pgraph->ctxvals) {
sprintf(name, "nouveau/nv%02x.ctxvals", chipset);
ret = request_firmware(&fw, name, &dev->pdev->dev);
if (ret) {
NV_ERROR(dev, "No ctxvals for NV%02x\n", chipset);
nouveau_grctx_fini(dev);
return ret;
}
pgraph->ctxvals = kmemdup(fw->data, fw->size, GFP_KERNEL);
if (!pgraph->ctxvals) {
NV_ERROR(dev, "OOM copying ctxvals\n");
release_firmware(fw);
nouveau_grctx_fini(dev);
return -ENOMEM;
}
cv = (void *)pgraph->ctxvals;
if (le32_to_cpu(cv->signature) != 0x5643564e ||
cv->version != 0 ||
le32_to_cpu(cv->length) != ((fw->size - 9) / 8)) {
NV_ERROR(dev, "ctxvals invalid\n");
release_firmware(fw);
nouveau_grctx_fini(dev);
return -EINVAL;
}
release_firmware(fw);
}
cp = pgraph->ctxprog;
nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_INDEX, 0);
for (i = 0; i < le16_to_cpu(cp->length); i++)
nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_DATA,
le32_to_cpu(cp->data[i]));
return 0;
}
void
nouveau_grctx_fini(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
if (pgraph->ctxprog) {
kfree(pgraph->ctxprog);
pgraph->ctxprog = NULL;
}
if (pgraph->ctxvals) {
kfree(pgraph->ctxprog);
pgraph->ctxvals = NULL;
}
}
void
nouveau_grctx_vals_load(struct drm_device *dev, struct nouveau_gpuobj *ctx)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
struct nouveau_ctxvals *cv = pgraph->ctxvals;
int i;
if (!cv)
return;
for (i = 0; i < le32_to_cpu(cv->length); i++)
nv_wo32(dev, ctx, le32_to_cpu(cv->data[i].offset),
le32_to_cpu(cv->data[i].value));
}

View file

@ -278,3 +278,45 @@ nouveau_i2c_find(struct drm_device *dev, int index)
return i2c->chan;
}
bool
nouveau_probe_i2c_addr(struct nouveau_i2c_chan *i2c, int addr)
{
uint8_t buf[] = { 0 };
struct i2c_msg msgs[] = {
{
.addr = addr,
.flags = 0,
.len = 1,
.buf = buf,
},
{
.addr = addr,
.flags = I2C_M_RD,
.len = 1,
.buf = buf,
}
};
return i2c_transfer(&i2c->adapter, msgs, 2) == 2;
}
int
nouveau_i2c_identify(struct drm_device *dev, const char *what,
struct i2c_board_info *info, int index)
{
struct nouveau_i2c_chan *i2c = nouveau_i2c_find(dev, index);
int i;
NV_DEBUG(dev, "Probing %ss on I2C bus: %d\n", what, index);
for (i = 0; info[i].addr; i++) {
if (nouveau_probe_i2c_addr(i2c, info[i].addr)) {
NV_INFO(dev, "Detected %s: %s\n", what, info[i].type);
return i;
}
}
NV_DEBUG(dev, "No devices found.\n");
return -ENODEV;
}

View file

@ -45,6 +45,9 @@ struct nouveau_i2c_chan {
int nouveau_i2c_init(struct drm_device *, struct dcb_i2c_entry *, int index);
void nouveau_i2c_fini(struct drm_device *, struct dcb_i2c_entry *);
struct nouveau_i2c_chan *nouveau_i2c_find(struct drm_device *, int index);
bool nouveau_probe_i2c_addr(struct nouveau_i2c_chan *i2c, int addr);
int nouveau_i2c_identify(struct drm_device *dev, const char *what,
struct i2c_board_info *info, int index);
int nouveau_dp_i2c_aux_ch(struct i2c_adapter *, int mode, uint8_t write_byte,
uint8_t *read_byte);

View file

@ -35,162 +35,6 @@
#include "drm_sarea.h"
#include "nouveau_drv.h"
static struct mem_block *
split_block(struct mem_block *p, uint64_t start, uint64_t size,
struct drm_file *file_priv)
{
/* Maybe cut off the start of an existing block */
if (start > p->start) {
struct mem_block *newblock =
kmalloc(sizeof(*newblock), GFP_KERNEL);
if (!newblock)
goto out;
newblock->start = start;
newblock->size = p->size - (start - p->start);
newblock->file_priv = NULL;
newblock->next = p->next;
newblock->prev = p;
p->next->prev = newblock;
p->next = newblock;
p->size -= newblock->size;
p = newblock;
}
/* Maybe cut off the end of an existing block */
if (size < p->size) {
struct mem_block *newblock =
kmalloc(sizeof(*newblock), GFP_KERNEL);
if (!newblock)
goto out;
newblock->start = start + size;
newblock->size = p->size - size;
newblock->file_priv = NULL;
newblock->next = p->next;
newblock->prev = p;
p->next->prev = newblock;
p->next = newblock;
p->size = size;
}
out:
/* Our block is in the middle */
p->file_priv = file_priv;
return p;
}
struct mem_block *
nouveau_mem_alloc_block(struct mem_block *heap, uint64_t size,
int align2, struct drm_file *file_priv, int tail)
{
struct mem_block *p;
uint64_t mask = (1 << align2) - 1;
if (!heap)
return NULL;
if (tail) {
list_for_each_prev(p, heap) {
uint64_t start = ((p->start + p->size) - size) & ~mask;
if (p->file_priv == NULL && start >= p->start &&
start + size <= p->start + p->size)
return split_block(p, start, size, file_priv);
}
} else {
list_for_each(p, heap) {
uint64_t start = (p->start + mask) & ~mask;
if (p->file_priv == NULL &&
start + size <= p->start + p->size)
return split_block(p, start, size, file_priv);
}
}
return NULL;
}
void nouveau_mem_free_block(struct mem_block *p)
{
p->file_priv = NULL;
/* Assumes a single contiguous range. Needs a special file_priv in
* 'heap' to stop it being subsumed.
*/
if (p->next->file_priv == NULL) {
struct mem_block *q = p->next;
p->size += q->size;
p->next = q->next;
p->next->prev = p;
kfree(q);
}
if (p->prev->file_priv == NULL) {
struct mem_block *q = p->prev;
q->size += p->size;
q->next = p->next;
q->next->prev = q;
kfree(p);
}
}
/* Initialize. How to check for an uninitialized heap?
*/
int nouveau_mem_init_heap(struct mem_block **heap, uint64_t start,
uint64_t size)
{
struct mem_block *blocks = kmalloc(sizeof(*blocks), GFP_KERNEL);
if (!blocks)
return -ENOMEM;
*heap = kmalloc(sizeof(**heap), GFP_KERNEL);
if (!*heap) {
kfree(blocks);
return -ENOMEM;
}
blocks->start = start;
blocks->size = size;
blocks->file_priv = NULL;
blocks->next = blocks->prev = *heap;
memset(*heap, 0, sizeof(**heap));
(*heap)->file_priv = (struct drm_file *) -1;
(*heap)->next = (*heap)->prev = blocks;
return 0;
}
/*
* Free all blocks associated with the releasing file_priv
*/
void nouveau_mem_release(struct drm_file *file_priv, struct mem_block *heap)
{
struct mem_block *p;
if (!heap || !heap->next)
return;
list_for_each(p, heap) {
if (p->file_priv == file_priv)
p->file_priv = NULL;
}
/* Assumes a single contiguous range. Needs a special file_priv in
* 'heap' to stop it being subsumed.
*/
list_for_each(p, heap) {
while ((p->file_priv == NULL) &&
(p->next->file_priv == NULL) &&
(p->next != heap)) {
struct mem_block *q = p->next;
p->size += q->size;
p->next = q->next;
p->next->prev = p;
kfree(q);
}
}
}
/*
* NV10-NV40 tiling helpers
*/
@ -299,7 +143,6 @@ nv50_mem_vm_bind_linear(struct drm_device *dev, uint64_t virt, uint32_t size,
phys |= 0x30;
}
dev_priv->engine.instmem.prepare_access(dev, true);
while (size) {
unsigned offset_h = upper_32_bits(phys);
unsigned offset_l = lower_32_bits(phys);
@ -331,36 +174,12 @@ nv50_mem_vm_bind_linear(struct drm_device *dev, uint64_t virt, uint32_t size,
}
}
}
dev_priv->engine.instmem.finish_access(dev);
nv_wr32(dev, 0x100c80, 0x00050001);
if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) {
NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n");
NV_ERROR(dev, "0x100c80 = 0x%08x\n", nv_rd32(dev, 0x100c80));
return -EBUSY;
}
nv_wr32(dev, 0x100c80, 0x00000001);
if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) {
NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n");
NV_ERROR(dev, "0x100c80 = 0x%08x\n", nv_rd32(dev, 0x100c80));
return -EBUSY;
}
nv_wr32(dev, 0x100c80, 0x00040001);
if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) {
NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n");
NV_ERROR(dev, "0x100c80 = 0x%08x\n", nv_rd32(dev, 0x100c80));
return -EBUSY;
}
nv_wr32(dev, 0x100c80, 0x00060001);
if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) {
NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n");
NV_ERROR(dev, "0x100c80 = 0x%08x\n", nv_rd32(dev, 0x100c80));
return -EBUSY;
}
dev_priv->engine.instmem.flush(dev);
nv50_vm_flush(dev, 5);
nv50_vm_flush(dev, 0);
nv50_vm_flush(dev, 4);
nv50_vm_flush(dev, 6);
return 0;
}
@ -374,7 +193,6 @@ nv50_mem_vm_unbind(struct drm_device *dev, uint64_t virt, uint32_t size)
virt -= dev_priv->vm_vram_base;
pages = (size >> 16) << 1;
dev_priv->engine.instmem.prepare_access(dev, true);
while (pages) {
pgt = dev_priv->vm_vram_pt[virt >> 29];
pte = (virt & 0x1ffe0000ULL) >> 15;
@ -388,57 +206,19 @@ nv50_mem_vm_unbind(struct drm_device *dev, uint64_t virt, uint32_t size)
while (pte < end)
nv_wo32(dev, pgt, pte++, 0);
}
dev_priv->engine.instmem.finish_access(dev);
dev_priv->engine.instmem.flush(dev);
nv_wr32(dev, 0x100c80, 0x00050001);
if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) {
NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n");
NV_ERROR(dev, "0x100c80 = 0x%08x\n", nv_rd32(dev, 0x100c80));
return;
}
nv_wr32(dev, 0x100c80, 0x00000001);
if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) {
NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n");
NV_ERROR(dev, "0x100c80 = 0x%08x\n", nv_rd32(dev, 0x100c80));
return;
}
nv_wr32(dev, 0x100c80, 0x00040001);
if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) {
NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n");
NV_ERROR(dev, "0x100c80 = 0x%08x\n", nv_rd32(dev, 0x100c80));
return;
}
nv_wr32(dev, 0x100c80, 0x00060001);
if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) {
NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n");
NV_ERROR(dev, "0x100c80 = 0x%08x\n", nv_rd32(dev, 0x100c80));
}
nv50_vm_flush(dev, 5);
nv50_vm_flush(dev, 0);
nv50_vm_flush(dev, 4);
nv50_vm_flush(dev, 6);
}
/*
* Cleanup everything
*/
void nouveau_mem_takedown(struct mem_block **heap)
{
struct mem_block *p;
if (!*heap)
return;
for (p = (*heap)->next; p != *heap;) {
struct mem_block *q = p;
p = p->next;
kfree(q);
}
kfree(*heap);
*heap = NULL;
}
void nouveau_mem_close(struct drm_device *dev)
void
nouveau_mem_close(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
@ -449,8 +229,7 @@ void nouveau_mem_close(struct drm_device *dev)
nouveau_ttm_global_release(dev_priv);
if (drm_core_has_AGP(dev) && dev->agp &&
drm_core_check_feature(dev, DRIVER_MODESET)) {
if (drm_core_has_AGP(dev) && dev->agp) {
struct drm_agp_mem *entry, *tempe;
/* Remove AGP resources, but leave dev->agp
@ -474,26 +253,26 @@ void nouveau_mem_close(struct drm_device *dev)
drm_mtrr_del(dev_priv->fb_mtrr,
pci_resource_start(dev->pdev, 1),
pci_resource_len(dev->pdev, 1), DRM_MTRR_WC);
dev_priv->fb_mtrr = 0;
dev_priv->fb_mtrr = -1;
}
}
static uint32_t
nouveau_mem_detect_nv04(struct drm_device *dev)
{
uint32_t boot0 = nv_rd32(dev, NV03_BOOT_0);
uint32_t boot0 = nv_rd32(dev, NV04_PFB_BOOT_0);
if (boot0 & 0x00000100)
return (((boot0 >> 12) & 0xf) * 2 + 2) * 1024 * 1024;
switch (boot0 & NV03_BOOT_0_RAM_AMOUNT) {
case NV04_BOOT_0_RAM_AMOUNT_32MB:
switch (boot0 & NV04_PFB_BOOT_0_RAM_AMOUNT) {
case NV04_PFB_BOOT_0_RAM_AMOUNT_32MB:
return 32 * 1024 * 1024;
case NV04_BOOT_0_RAM_AMOUNT_16MB:
case NV04_PFB_BOOT_0_RAM_AMOUNT_16MB:
return 16 * 1024 * 1024;
case NV04_BOOT_0_RAM_AMOUNT_8MB:
case NV04_PFB_BOOT_0_RAM_AMOUNT_8MB:
return 8 * 1024 * 1024;
case NV04_BOOT_0_RAM_AMOUNT_4MB:
case NV04_PFB_BOOT_0_RAM_AMOUNT_4MB:
return 4 * 1024 * 1024;
}
@ -537,12 +316,18 @@ nouveau_mem_detect(struct drm_device *dev)
} else
if (dev_priv->flags & (NV_NFORCE | NV_NFORCE2)) {
dev_priv->vram_size = nouveau_mem_detect_nforce(dev);
} else
if (dev_priv->card_type < NV_50) {
dev_priv->vram_size = nv_rd32(dev, NV04_PFB_FIFO_DATA);
dev_priv->vram_size &= NV10_PFB_FIFO_DATA_RAM_AMOUNT_MB_MASK;
} else {
dev_priv->vram_size = nv_rd32(dev, NV04_FIFO_DATA);
dev_priv->vram_size &= NV10_FIFO_DATA_RAM_AMOUNT_MB_MASK;
if (dev_priv->chipset == 0xaa || dev_priv->chipset == 0xac)
dev_priv->vram_size = nv_rd32(dev, NV04_PFB_FIFO_DATA);
dev_priv->vram_size |= (dev_priv->vram_size & 0xff) << 32;
dev_priv->vram_size &= 0xffffffff00ll;
if (dev_priv->chipset == 0xaa || dev_priv->chipset == 0xac) {
dev_priv->vram_sys_base = nv_rd32(dev, 0x100e10);
dev_priv->vram_sys_base <<= 12;
}
}
NV_INFO(dev, "Detected %dMiB VRAM\n", (int)(dev_priv->vram_size >> 20));
@ -556,18 +341,36 @@ nouveau_mem_detect(struct drm_device *dev)
return -ENOMEM;
}
#if __OS_HAS_AGP
static void nouveau_mem_reset_agp(struct drm_device *dev)
int
nouveau_mem_reset_agp(struct drm_device *dev)
{
uint32_t saved_pci_nv_1, saved_pci_nv_19, pmc_enable;
#if __OS_HAS_AGP
uint32_t saved_pci_nv_1, pmc_enable;
int ret;
/* First of all, disable fast writes, otherwise if it's
* already enabled in the AGP bridge and we disable the card's
* AGP controller we might be locking ourselves out of it. */
if (dev->agp->acquired) {
struct drm_agp_info info;
struct drm_agp_mode mode;
ret = drm_agp_info(dev, &info);
if (ret)
return ret;
mode.mode = info.mode & ~0x10;
ret = drm_agp_enable(dev, mode);
if (ret)
return ret;
}
saved_pci_nv_1 = nv_rd32(dev, NV04_PBUS_PCI_NV_1);
saved_pci_nv_19 = nv_rd32(dev, NV04_PBUS_PCI_NV_19);
/* clear busmaster bit */
nv_wr32(dev, NV04_PBUS_PCI_NV_1, saved_pci_nv_1 & ~0x4);
/* clear SBA and AGP bits */
nv_wr32(dev, NV04_PBUS_PCI_NV_19, saved_pci_nv_19 & 0xfffff0ff);
/* disable AGP */
nv_wr32(dev, NV04_PBUS_PCI_NV_19, 0);
/* power cycle pgraph, if enabled */
pmc_enable = nv_rd32(dev, NV03_PMC_ENABLE);
@ -579,11 +382,12 @@ static void nouveau_mem_reset_agp(struct drm_device *dev)
}
/* and restore (gives effect of resetting AGP) */
nv_wr32(dev, NV04_PBUS_PCI_NV_19, saved_pci_nv_19);
nv_wr32(dev, NV04_PBUS_PCI_NV_1, saved_pci_nv_1);
}
#endif
return 0;
}
int
nouveau_mem_init_agp(struct drm_device *dev)
{
@ -593,11 +397,6 @@ nouveau_mem_init_agp(struct drm_device *dev)
struct drm_agp_mode mode;
int ret;
if (nouveau_noagp)
return 0;
nouveau_mem_reset_agp(dev);
if (!dev->agp->acquired) {
ret = drm_agp_acquire(dev);
if (ret) {
@ -694,7 +493,8 @@ nouveau_mem_init(struct drm_device *dev)
/* GART */
#if !defined(__powerpc__) && !defined(__ia64__)
if (drm_device_is_agp(dev) && dev->agp) {
if (drm_device_is_agp(dev) && dev->agp && !nouveau_noagp) {
nouveau_mem_reset_agp(dev);
ret = nouveau_mem_init_agp(dev);
if (ret)
NV_ERROR(dev, "Error initialising AGP: %d\n", ret);

View file

@ -55,7 +55,7 @@ nouveau_notifier_init_channel(struct nouveau_channel *chan)
if (ret)
goto out_err;
ret = nouveau_mem_init_heap(&chan->notifier_heap, 0, ntfy->bo.mem.size);
ret = drm_mm_init(&chan->notifier_heap, 0, ntfy->bo.mem.size);
if (ret)
goto out_err;
@ -80,7 +80,7 @@ nouveau_notifier_takedown_channel(struct nouveau_channel *chan)
nouveau_bo_unpin(chan->notifier_bo);
mutex_unlock(&dev->struct_mutex);
drm_gem_object_unreference_unlocked(chan->notifier_bo->gem);
nouveau_mem_takedown(&chan->notifier_heap);
drm_mm_takedown(&chan->notifier_heap);
}
static void
@ -90,7 +90,7 @@ nouveau_notifier_gpuobj_dtor(struct drm_device *dev,
NV_DEBUG(dev, "\n");
if (gpuobj->priv)
nouveau_mem_free_block(gpuobj->priv);
drm_mm_put_block(gpuobj->priv);
}
int
@ -100,18 +100,13 @@ nouveau_notifier_alloc(struct nouveau_channel *chan, uint32_t handle,
struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_gpuobj *nobj = NULL;
struct mem_block *mem;
struct drm_mm_node *mem;
uint32_t offset;
int target, ret;
if (!chan->notifier_heap) {
NV_ERROR(dev, "Channel %d doesn't have a notifier heap!\n",
chan->id);
return -EINVAL;
}
mem = nouveau_mem_alloc_block(chan->notifier_heap, size, 0,
(struct drm_file *)-2, 0);
mem = drm_mm_search_free(&chan->notifier_heap, size, 0, 0);
if (mem)
mem = drm_mm_get_block(mem, size, 0);
if (!mem) {
NV_ERROR(dev, "Channel %d notifier block full\n", chan->id);
return -ENOMEM;
@ -144,17 +139,17 @@ nouveau_notifier_alloc(struct nouveau_channel *chan, uint32_t handle,
mem->size, NV_DMA_ACCESS_RW, target,
&nobj);
if (ret) {
nouveau_mem_free_block(mem);
drm_mm_put_block(mem);
NV_ERROR(dev, "Error creating notifier ctxdma: %d\n", ret);
return ret;
}
nobj->dtor = nouveau_notifier_gpuobj_dtor;
nobj->priv = mem;
nobj->dtor = nouveau_notifier_gpuobj_dtor;
nobj->priv = mem;
ret = nouveau_gpuobj_ref_add(dev, chan, handle, nobj, NULL);
if (ret) {
nouveau_gpuobj_del(dev, &nobj);
nouveau_mem_free_block(mem);
drm_mm_put_block(mem);
NV_ERROR(dev, "Error referencing notifier ctxdma: %d\n", ret);
return ret;
}
@ -170,7 +165,7 @@ nouveau_notifier_offset(struct nouveau_gpuobj *nobj, uint32_t *poffset)
return -EINVAL;
if (poffset) {
struct mem_block *mem = nobj->priv;
struct drm_mm_node *mem = nobj->priv;
if (*poffset >= mem->size)
return false;
@ -189,7 +184,6 @@ nouveau_ioctl_notifier_alloc(struct drm_device *dev, void *data,
struct nouveau_channel *chan;
int ret;
NOUVEAU_CHECK_INITIALISED_WITH_RETURN;
NOUVEAU_GET_USER_CHANNEL_WITH_RETURN(na->channel, file_priv, chan);
ret = nouveau_notifier_alloc(chan, na->handle, na->size, &na->offset);

View file

@ -132,7 +132,6 @@ nouveau_ramht_insert(struct drm_device *dev, struct nouveau_gpuobj_ref *ref)
}
}
instmem->prepare_access(dev, true);
co = ho = nouveau_ramht_hash_handle(dev, chan->id, ref->handle);
do {
if (!nouveau_ramht_entry_valid(dev, ramht, co)) {
@ -143,7 +142,7 @@ nouveau_ramht_insert(struct drm_device *dev, struct nouveau_gpuobj_ref *ref)
nv_wo32(dev, ramht, (co + 4)/4, ctx);
list_add_tail(&ref->list, &chan->ramht_refs);
instmem->finish_access(dev);
instmem->flush(dev);
return 0;
}
NV_DEBUG(dev, "collision ch%d 0x%08x: h=0x%08x\n",
@ -153,7 +152,6 @@ nouveau_ramht_insert(struct drm_device *dev, struct nouveau_gpuobj_ref *ref)
if (co >= dev_priv->ramht_size)
co = 0;
} while (co != ho);
instmem->finish_access(dev);
NV_ERROR(dev, "RAMHT space exhausted. ch=%d\n", chan->id);
return -ENOMEM;
@ -173,7 +171,6 @@ nouveau_ramht_remove(struct drm_device *dev, struct nouveau_gpuobj_ref *ref)
return;
}
instmem->prepare_access(dev, true);
co = ho = nouveau_ramht_hash_handle(dev, chan->id, ref->handle);
do {
if (nouveau_ramht_entry_valid(dev, ramht, co) &&
@ -186,7 +183,7 @@ nouveau_ramht_remove(struct drm_device *dev, struct nouveau_gpuobj_ref *ref)
nv_wo32(dev, ramht, (co + 4)/4, 0x00000000);
list_del(&ref->list);
instmem->finish_access(dev);
instmem->flush(dev);
return;
}
@ -195,7 +192,6 @@ nouveau_ramht_remove(struct drm_device *dev, struct nouveau_gpuobj_ref *ref)
co = 0;
} while (co != ho);
list_del(&ref->list);
instmem->finish_access(dev);
NV_ERROR(dev, "RAMHT entry not found. ch=%d, handle=0x%08x\n",
chan->id, ref->handle);
@ -209,7 +205,7 @@ nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan,
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_engine *engine = &dev_priv->engine;
struct nouveau_gpuobj *gpuobj;
struct mem_block *pramin = NULL;
struct drm_mm *pramin = NULL;
int ret;
NV_DEBUG(dev, "ch%d size=%u align=%d flags=0x%08x\n",
@ -233,25 +229,12 @@ nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan,
* available.
*/
if (chan) {
if (chan->ramin_heap) {
NV_DEBUG(dev, "private heap\n");
pramin = chan->ramin_heap;
} else
if (dev_priv->card_type < NV_50) {
NV_DEBUG(dev, "global heap fallback\n");
pramin = dev_priv->ramin_heap;
}
NV_DEBUG(dev, "channel heap\n");
pramin = &chan->ramin_heap;
} else {
NV_DEBUG(dev, "global heap\n");
pramin = dev_priv->ramin_heap;
}
pramin = &dev_priv->ramin_heap;
if (!pramin) {
NV_ERROR(dev, "No PRAMIN heap!\n");
return -EINVAL;
}
if (!chan) {
ret = engine->instmem.populate(dev, gpuobj, &size);
if (ret) {
nouveau_gpuobj_del(dev, &gpuobj);
@ -260,9 +243,10 @@ nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan,
}
/* Allocate a chunk of the PRAMIN aperture */
gpuobj->im_pramin = nouveau_mem_alloc_block(pramin, size,
drm_order(align),
(struct drm_file *)-2, 0);
gpuobj->im_pramin = drm_mm_search_free(pramin, size, align, 0);
if (gpuobj->im_pramin)
gpuobj->im_pramin = drm_mm_get_block(gpuobj->im_pramin, size, align);
if (!gpuobj->im_pramin) {
nouveau_gpuobj_del(dev, &gpuobj);
return -ENOMEM;
@ -279,10 +263,9 @@ nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan,
if (gpuobj->flags & NVOBJ_FLAG_ZERO_ALLOC) {
int i;
engine->instmem.prepare_access(dev, true);
for (i = 0; i < gpuobj->im_pramin->size; i += 4)
nv_wo32(dev, gpuobj, i/4, 0);
engine->instmem.finish_access(dev);
engine->instmem.flush(dev);
}
*gpuobj_ret = gpuobj;
@ -370,10 +353,9 @@ nouveau_gpuobj_del(struct drm_device *dev, struct nouveau_gpuobj **pgpuobj)
}
if (gpuobj->im_pramin && (gpuobj->flags & NVOBJ_FLAG_ZERO_FREE)) {
engine->instmem.prepare_access(dev, true);
for (i = 0; i < gpuobj->im_pramin->size; i += 4)
nv_wo32(dev, gpuobj, i/4, 0);
engine->instmem.finish_access(dev);
engine->instmem.flush(dev);
}
if (gpuobj->dtor)
@ -386,7 +368,7 @@ nouveau_gpuobj_del(struct drm_device *dev, struct nouveau_gpuobj **pgpuobj)
if (gpuobj->flags & NVOBJ_FLAG_FAKE)
kfree(gpuobj->im_pramin);
else
nouveau_mem_free_block(gpuobj->im_pramin);
drm_mm_put_block(gpuobj->im_pramin);
}
list_del(&gpuobj->list);
@ -589,7 +571,7 @@ nouveau_gpuobj_new_fake(struct drm_device *dev, uint32_t p_offset,
list_add_tail(&gpuobj->list, &dev_priv->gpuobj_list);
if (p_offset != ~0) {
gpuobj->im_pramin = kzalloc(sizeof(struct mem_block),
gpuobj->im_pramin = kzalloc(sizeof(struct drm_mm_node),
GFP_KERNEL);
if (!gpuobj->im_pramin) {
nouveau_gpuobj_del(dev, &gpuobj);
@ -605,10 +587,9 @@ nouveau_gpuobj_new_fake(struct drm_device *dev, uint32_t p_offset,
}
if (gpuobj->flags & NVOBJ_FLAG_ZERO_ALLOC) {
dev_priv->engine.instmem.prepare_access(dev, true);
for (i = 0; i < gpuobj->im_pramin->size; i += 4)
nv_wo32(dev, gpuobj, i/4, 0);
dev_priv->engine.instmem.finish_access(dev);
dev_priv->engine.instmem.flush(dev);
}
if (pref) {
@ -696,8 +677,6 @@ nouveau_gpuobj_dma_new(struct nouveau_channel *chan, int class,
return ret;
}
instmem->prepare_access(dev, true);
if (dev_priv->card_type < NV_50) {
uint32_t frame, adjust, pte_flags = 0;
@ -734,7 +713,7 @@ nouveau_gpuobj_dma_new(struct nouveau_channel *chan, int class,
nv_wo32(dev, *gpuobj, 5, flags5);
}
instmem->finish_access(dev);
instmem->flush(dev);
(*gpuobj)->engine = NVOBJ_ENGINE_SW;
(*gpuobj)->class = class;
@ -849,7 +828,6 @@ nouveau_gpuobj_gr_new(struct nouveau_channel *chan, int class,
return ret;
}
dev_priv->engine.instmem.prepare_access(dev, true);
if (dev_priv->card_type >= NV_50) {
nv_wo32(dev, *gpuobj, 0, class);
nv_wo32(dev, *gpuobj, 5, 0x00010000);
@ -874,7 +852,7 @@ nouveau_gpuobj_gr_new(struct nouveau_channel *chan, int class,
}
}
}
dev_priv->engine.instmem.finish_access(dev);
dev_priv->engine.instmem.flush(dev);
(*gpuobj)->engine = NVOBJ_ENGINE_GR;
(*gpuobj)->class = class;
@ -920,6 +898,7 @@ nouveau_gpuobj_channel_init_pramin(struct nouveau_channel *chan)
base = 0;
/* PGRAPH context */
size += dev_priv->engine.graph.grctx_size;
if (dev_priv->card_type == NV_50) {
/* Various fixed table thingos */
@ -930,12 +909,8 @@ nouveau_gpuobj_channel_init_pramin(struct nouveau_channel *chan)
size += 0x8000;
/* RAMFC */
size += 0x1000;
/* PGRAPH context */
size += 0x70000;
}
NV_DEBUG(dev, "ch%d PRAMIN size: 0x%08x bytes, base alloc=0x%08x\n",
chan->id, size, base);
ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0, size, 0x1000, 0,
&chan->ramin);
if (ret) {
@ -944,8 +919,7 @@ nouveau_gpuobj_channel_init_pramin(struct nouveau_channel *chan)
}
pramin = chan->ramin->gpuobj;
ret = nouveau_mem_init_heap(&chan->ramin_heap,
pramin->im_pramin->start + base, size);
ret = drm_mm_init(&chan->ramin_heap, pramin->im_pramin->start + base, size);
if (ret) {
NV_ERROR(dev, "Error creating PRAMIN heap: %d\n", ret);
nouveau_gpuobj_ref_del(dev, &chan->ramin);
@ -969,15 +943,11 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan,
NV_DEBUG(dev, "ch%d vram=0x%08x tt=0x%08x\n", chan->id, vram_h, tt_h);
/* Reserve a block of PRAMIN for the channel
*XXX: maybe on <NV50 too at some point
*/
if (0 || dev_priv->card_type == NV_50) {
ret = nouveau_gpuobj_channel_init_pramin(chan);
if (ret) {
NV_ERROR(dev, "init pramin\n");
return ret;
}
/* Allocate a chunk of memory for per-channel object storage */
ret = nouveau_gpuobj_channel_init_pramin(chan);
if (ret) {
NV_ERROR(dev, "init pramin\n");
return ret;
}
/* NV50 VM
@ -988,17 +958,13 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan,
if (dev_priv->card_type >= NV_50) {
uint32_t vm_offset, pde;
instmem->prepare_access(dev, true);
vm_offset = (dev_priv->chipset & 0xf0) == 0x50 ? 0x1400 : 0x200;
vm_offset += chan->ramin->gpuobj->im_pramin->start;
ret = nouveau_gpuobj_new_fake(dev, vm_offset, ~0, 0x4000,
0, &chan->vm_pd, NULL);
if (ret) {
instmem->finish_access(dev);
if (ret)
return ret;
}
for (i = 0; i < 0x4000; i += 8) {
nv_wo32(dev, chan->vm_pd, (i+0)/4, 0x00000000);
nv_wo32(dev, chan->vm_pd, (i+4)/4, 0xdeadcafe);
@ -1008,10 +974,8 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan,
ret = nouveau_gpuobj_ref_add(dev, NULL, 0,
dev_priv->gart_info.sg_ctxdma,
&chan->vm_gart_pt);
if (ret) {
instmem->finish_access(dev);
if (ret)
return ret;
}
nv_wo32(dev, chan->vm_pd, pde++,
chan->vm_gart_pt->instance | 0x03);
nv_wo32(dev, chan->vm_pd, pde++, 0x00000000);
@ -1021,17 +985,15 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan,
ret = nouveau_gpuobj_ref_add(dev, NULL, 0,
dev_priv->vm_vram_pt[i],
&chan->vm_vram_pt[i]);
if (ret) {
instmem->finish_access(dev);
if (ret)
return ret;
}
nv_wo32(dev, chan->vm_pd, pde++,
chan->vm_vram_pt[i]->instance | 0x61);
nv_wo32(dev, chan->vm_pd, pde++, 0x00000000);
}
instmem->finish_access(dev);
instmem->flush(dev);
}
/* RAMHT */
@ -1130,8 +1092,8 @@ nouveau_gpuobj_channel_takedown(struct nouveau_channel *chan)
for (i = 0; i < dev_priv->vm_vram_pt_nr; i++)
nouveau_gpuobj_ref_del(dev, &chan->vm_vram_pt[i]);
if (chan->ramin_heap)
nouveau_mem_takedown(&chan->ramin_heap);
if (chan->ramin_heap.free_stack.next)
drm_mm_takedown(&chan->ramin_heap);
if (chan->ramin)
nouveau_gpuobj_ref_del(dev, &chan->ramin);
@ -1164,10 +1126,8 @@ nouveau_gpuobj_suspend(struct drm_device *dev)
return -ENOMEM;
}
dev_priv->engine.instmem.prepare_access(dev, false);
for (i = 0; i < gpuobj->im_pramin->size / 4; i++)
gpuobj->im_backing_suspend[i] = nv_ro32(dev, gpuobj, i);
dev_priv->engine.instmem.finish_access(dev);
}
return 0;
@ -1212,10 +1172,9 @@ nouveau_gpuobj_resume(struct drm_device *dev)
if (!gpuobj->im_backing_suspend)
continue;
dev_priv->engine.instmem.prepare_access(dev, true);
for (i = 0; i < gpuobj->im_pramin->size / 4; i++)
nv_wo32(dev, gpuobj, i, gpuobj->im_backing_suspend[i]);
dev_priv->engine.instmem.finish_access(dev);
dev_priv->engine.instmem.flush(dev);
}
nouveau_gpuobj_suspend_cleanup(dev);
@ -1232,7 +1191,6 @@ int nouveau_ioctl_grobj_alloc(struct drm_device *dev, void *data,
struct nouveau_channel *chan;
int ret;
NOUVEAU_CHECK_INITIALISED_WITH_RETURN;
NOUVEAU_GET_USER_CHANNEL_WITH_RETURN(init->channel, file_priv, chan);
if (init->handle == ~0)
@ -1283,7 +1241,6 @@ int nouveau_ioctl_gpuobj_free(struct drm_device *dev, void *data,
struct nouveau_channel *chan;
int ret;
NOUVEAU_CHECK_INITIALISED_WITH_RETURN;
NOUVEAU_GET_USER_CHANNEL_WITH_RETURN(objfree->channel, file_priv, chan);
ret = nouveau_gpuobj_ref_find(chan, objfree->handle, &ref);

View file

@ -1,19 +1,64 @@
#define NV04_PFB_BOOT_0 0x00100000
# define NV04_PFB_BOOT_0_RAM_AMOUNT 0x00000003
# define NV04_PFB_BOOT_0_RAM_AMOUNT_32MB 0x00000000
# define NV04_PFB_BOOT_0_RAM_AMOUNT_4MB 0x00000001
# define NV04_PFB_BOOT_0_RAM_AMOUNT_8MB 0x00000002
# define NV04_PFB_BOOT_0_RAM_AMOUNT_16MB 0x00000003
# define NV04_PFB_BOOT_0_RAM_WIDTH_128 0x00000004
# define NV04_PFB_BOOT_0_RAM_TYPE 0x00000028
# define NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_8MBIT 0x00000000
# define NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_16MBIT 0x00000008
# define NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_16MBIT_4BANK 0x00000010
# define NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_16MBIT 0x00000018
# define NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_64MBIT 0x00000020
# define NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_64MBITX16 0x00000028
# define NV04_PFB_BOOT_0_UMA_ENABLE 0x00000100
# define NV04_PFB_BOOT_0_UMA_SIZE 0x0000f000
#define NV04_PFB_DEBUG_0 0x00100080
# define NV04_PFB_DEBUG_0_PAGE_MODE 0x00000001
# define NV04_PFB_DEBUG_0_REFRESH_OFF 0x00000010
# define NV04_PFB_DEBUG_0_REFRESH_COUNTX64 0x00003f00
# define NV04_PFB_DEBUG_0_REFRESH_SLOW_CLK 0x00004000
# define NV04_PFB_DEBUG_0_SAFE_MODE 0x00008000
# define NV04_PFB_DEBUG_0_ALOM_ENABLE 0x00010000
# define NV04_PFB_DEBUG_0_CASOE 0x00100000
# define NV04_PFB_DEBUG_0_CKE_INVERT 0x10000000
# define NV04_PFB_DEBUG_0_REFINC 0x20000000
# define NV04_PFB_DEBUG_0_SAVE_POWER_OFF 0x40000000
#define NV04_PFB_CFG0 0x00100200
# define NV04_PFB_CFG0_SCRAMBLE 0x20000000
#define NV04_PFB_CFG1 0x00100204
#define NV04_PFB_FIFO_DATA 0x0010020c
# define NV10_PFB_FIFO_DATA_RAM_AMOUNT_MB_MASK 0xfff00000
# define NV10_PFB_FIFO_DATA_RAM_AMOUNT_MB_SHIFT 20
#define NV10_PFB_REFCTRL 0x00100210
# define NV10_PFB_REFCTRL_VALID_1 (1 << 31)
#define NV04_PFB_PAD 0x0010021c
# define NV04_PFB_PAD_CKE_NORMAL (1 << 0)
#define NV10_PFB_TILE(i) (0x00100240 + (i*16))
#define NV10_PFB_TILE__SIZE 8
#define NV10_PFB_TLIMIT(i) (0x00100244 + (i*16))
#define NV10_PFB_TSIZE(i) (0x00100248 + (i*16))
#define NV10_PFB_TSTATUS(i) (0x0010024c + (i*16))
#define NV04_PFB_REF 0x001002d0
# define NV04_PFB_REF_CMD_REFRESH (1 << 0)
#define NV04_PFB_PRE 0x001002d4
# define NV04_PFB_PRE_CMD_PRECHARGE (1 << 0)
#define NV10_PFB_CLOSE_PAGE2 0x0010033c
#define NV04_PFB_SCRAMBLE(i) (0x00100400 + 4 * (i))
#define NV40_PFB_TILE(i) (0x00100600 + (i*16))
#define NV40_PFB_TILE__SIZE_0 12
#define NV40_PFB_TILE__SIZE_1 15
#define NV40_PFB_TLIMIT(i) (0x00100604 + (i*16))
#define NV40_PFB_TSIZE(i) (0x00100608 + (i*16))
#define NV40_PFB_TSTATUS(i) (0x0010060c + (i*16))
#define NV40_PFB_UNK_800 0x00100800
#define NV03_BOOT_0 0x00100000
# define NV03_BOOT_0_RAM_AMOUNT 0x00000003
# define NV03_BOOT_0_RAM_AMOUNT_8MB 0x00000000
# define NV03_BOOT_0_RAM_AMOUNT_2MB 0x00000001
# define NV03_BOOT_0_RAM_AMOUNT_4MB 0x00000002
# define NV03_BOOT_0_RAM_AMOUNT_8MB_SDRAM 0x00000003
# define NV04_BOOT_0_RAM_AMOUNT_32MB 0x00000000
# define NV04_BOOT_0_RAM_AMOUNT_4MB 0x00000001
# define NV04_BOOT_0_RAM_AMOUNT_8MB 0x00000002
# define NV04_BOOT_0_RAM_AMOUNT_16MB 0x00000003
#define NV04_FIFO_DATA 0x0010020c
# define NV10_FIFO_DATA_RAM_AMOUNT_MB_MASK 0xfff00000
# define NV10_FIFO_DATA_RAM_AMOUNT_MB_SHIFT 20
#define NV_PEXTDEV_BOOT_0 0x00101000
#define NV_PEXTDEV_BOOT_0_RAMCFG 0x0000003c
# define NV_PEXTDEV_BOOT_0_STRAP_FP_IFACE_12BIT (8 << 12)
#define NV_PEXTDEV_BOOT_3 0x0010100c
#define NV_RAMIN 0x00700000
@ -131,23 +176,6 @@
#define NV04_PTIMER_TIME_1 0x00009410
#define NV04_PTIMER_ALARM_0 0x00009420
#define NV04_PFB_CFG0 0x00100200
#define NV04_PFB_CFG1 0x00100204
#define NV40_PFB_020C 0x0010020C
#define NV10_PFB_TILE(i) (0x00100240 + (i*16))
#define NV10_PFB_TILE__SIZE 8
#define NV10_PFB_TLIMIT(i) (0x00100244 + (i*16))
#define NV10_PFB_TSIZE(i) (0x00100248 + (i*16))
#define NV10_PFB_TSTATUS(i) (0x0010024C + (i*16))
#define NV10_PFB_CLOSE_PAGE2 0x0010033C
#define NV40_PFB_TILE(i) (0x00100600 + (i*16))
#define NV40_PFB_TILE__SIZE_0 12
#define NV40_PFB_TILE__SIZE_1 15
#define NV40_PFB_TLIMIT(i) (0x00100604 + (i*16))
#define NV40_PFB_TSIZE(i) (0x00100608 + (i*16))
#define NV40_PFB_TSTATUS(i) (0x0010060C + (i*16))
#define NV40_PFB_UNK_800 0x00100800
#define NV04_PGRAPH_DEBUG_0 0x00400080
#define NV04_PGRAPH_DEBUG_1 0x00400084
#define NV04_PGRAPH_DEBUG_2 0x00400088
@ -814,6 +842,7 @@
#define NV50_PDISPLAY_SOR_BACKLIGHT_ENABLE 0x80000000
#define NV50_PDISPLAY_SOR_BACKLIGHT_LEVEL 0x00000fff
#define NV50_SOR_DP_CTRL(i,l) (0x0061c10c + (i) * 0x800 + (l) * 0x80)
#define NV50_SOR_DP_CTRL_ENABLED 0x00000001
#define NV50_SOR_DP_CTRL_ENHANCED_FRAME_ENABLED 0x00004000
#define NV50_SOR_DP_CTRL_LANE_MASK 0x001f0000
#define NV50_SOR_DP_CTRL_LANE_0_ENABLED 0x00010000

View file

@ -97,7 +97,6 @@ nouveau_sgdma_bind(struct ttm_backend *be, struct ttm_mem_reg *mem)
NV_DEBUG(dev, "pg=0x%lx\n", mem->mm_node->start);
dev_priv->engine.instmem.prepare_access(nvbe->dev, true);
pte = nouveau_sgdma_pte(nvbe->dev, mem->mm_node->start << PAGE_SHIFT);
nvbe->pte_start = pte;
for (i = 0; i < nvbe->nr_pages; i++) {
@ -116,24 +115,11 @@ nouveau_sgdma_bind(struct ttm_backend *be, struct ttm_mem_reg *mem)
dma_offset += NV_CTXDMA_PAGE_SIZE;
}
}
dev_priv->engine.instmem.finish_access(nvbe->dev);
dev_priv->engine.instmem.flush(nvbe->dev);
if (dev_priv->card_type == NV_50) {
nv_wr32(dev, 0x100c80, 0x00050001);
if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) {
NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n");
NV_ERROR(dev, "0x100c80 = 0x%08x\n",
nv_rd32(dev, 0x100c80));
return -EBUSY;
}
nv_wr32(dev, 0x100c80, 0x00000001);
if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) {
NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n");
NV_ERROR(dev, "0x100c80 = 0x%08x\n",
nv_rd32(dev, 0x100c80));
return -EBUSY;
}
nv50_vm_flush(dev, 5); /* PGRAPH */
nv50_vm_flush(dev, 0); /* PFIFO */
}
nvbe->bound = true;
@ -154,7 +140,6 @@ nouveau_sgdma_unbind(struct ttm_backend *be)
if (!nvbe->bound)
return 0;
dev_priv->engine.instmem.prepare_access(nvbe->dev, true);
pte = nvbe->pte_start;
for (i = 0; i < nvbe->nr_pages; i++) {
dma_addr_t dma_offset = dev_priv->gart_info.sg_dummy_bus;
@ -170,24 +155,11 @@ nouveau_sgdma_unbind(struct ttm_backend *be)
dma_offset += NV_CTXDMA_PAGE_SIZE;
}
}
dev_priv->engine.instmem.finish_access(nvbe->dev);
dev_priv->engine.instmem.flush(nvbe->dev);
if (dev_priv->card_type == NV_50) {
nv_wr32(dev, 0x100c80, 0x00050001);
if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) {
NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n");
NV_ERROR(dev, "0x100c80 = 0x%08x\n",
nv_rd32(dev, 0x100c80));
return -EBUSY;
}
nv_wr32(dev, 0x100c80, 0x00000001);
if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) {
NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n");
NV_ERROR(dev, "0x100c80 = 0x%08x\n",
nv_rd32(dev, 0x100c80));
return -EBUSY;
}
nv50_vm_flush(dev, 5);
nv50_vm_flush(dev, 0);
}
nvbe->bound = false;
@ -272,7 +244,6 @@ nouveau_sgdma_init(struct drm_device *dev)
pci_map_page(dev->pdev, dev_priv->gart_info.sg_dummy_page, 0,
PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
dev_priv->engine.instmem.prepare_access(dev, true);
if (dev_priv->card_type < NV_50) {
/* Maybe use NV_DMA_TARGET_AGP for PCIE? NVIDIA do this, and
* confirmed to work on c51. Perhaps means NV_DMA_TARGET_PCIE
@ -294,7 +265,7 @@ nouveau_sgdma_init(struct drm_device *dev)
nv_wo32(dev, gpuobj, (i+4)/4, 0);
}
}
dev_priv->engine.instmem.finish_access(dev);
dev_priv->engine.instmem.flush(dev);
dev_priv->gart_info.type = NOUVEAU_GART_SGDMA;
dev_priv->gart_info.aper_base = 0;
@ -325,14 +296,11 @@ nouveau_sgdma_get_page(struct drm_device *dev, uint32_t offset, uint32_t *page)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_gpuobj *gpuobj = dev_priv->gart_info.sg_ctxdma;
struct nouveau_instmem_engine *instmem = &dev_priv->engine.instmem;
int pte;
pte = (offset >> NV_CTXDMA_PAGE_SHIFT);
if (dev_priv->card_type < NV_50) {
instmem->prepare_access(dev, false);
*page = nv_ro32(dev, gpuobj, (pte + 2)) & ~NV_CTXDMA_PAGE_MASK;
instmem->finish_access(dev);
return 0;
}

View file

@ -38,6 +38,7 @@
#include "nv50_display.h"
static void nouveau_stub_takedown(struct drm_device *dev) {}
static int nouveau_stub_init(struct drm_device *dev) { return 0; }
static int nouveau_init_engine_ptrs(struct drm_device *dev)
{
@ -54,8 +55,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->instmem.clear = nv04_instmem_clear;
engine->instmem.bind = nv04_instmem_bind;
engine->instmem.unbind = nv04_instmem_unbind;
engine->instmem.prepare_access = nv04_instmem_prepare_access;
engine->instmem.finish_access = nv04_instmem_finish_access;
engine->instmem.flush = nv04_instmem_flush;
engine->mc.init = nv04_mc_init;
engine->mc.takedown = nv04_mc_takedown;
engine->timer.init = nv04_timer_init;
@ -85,6 +85,16 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->fifo.destroy_context = nv04_fifo_destroy_context;
engine->fifo.load_context = nv04_fifo_load_context;
engine->fifo.unload_context = nv04_fifo_unload_context;
engine->display.early_init = nv04_display_early_init;
engine->display.late_takedown = nv04_display_late_takedown;
engine->display.create = nv04_display_create;
engine->display.init = nv04_display_init;
engine->display.destroy = nv04_display_destroy;
engine->gpio.init = nouveau_stub_init;
engine->gpio.takedown = nouveau_stub_takedown;
engine->gpio.get = NULL;
engine->gpio.set = NULL;
engine->gpio.irq_enable = NULL;
break;
case 0x10:
engine->instmem.init = nv04_instmem_init;
@ -95,8 +105,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->instmem.clear = nv04_instmem_clear;
engine->instmem.bind = nv04_instmem_bind;
engine->instmem.unbind = nv04_instmem_unbind;
engine->instmem.prepare_access = nv04_instmem_prepare_access;
engine->instmem.finish_access = nv04_instmem_finish_access;
engine->instmem.flush = nv04_instmem_flush;
engine->mc.init = nv04_mc_init;
engine->mc.takedown = nv04_mc_takedown;
engine->timer.init = nv04_timer_init;
@ -128,6 +137,16 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->fifo.destroy_context = nv10_fifo_destroy_context;
engine->fifo.load_context = nv10_fifo_load_context;
engine->fifo.unload_context = nv10_fifo_unload_context;
engine->display.early_init = nv04_display_early_init;
engine->display.late_takedown = nv04_display_late_takedown;
engine->display.create = nv04_display_create;
engine->display.init = nv04_display_init;
engine->display.destroy = nv04_display_destroy;
engine->gpio.init = nouveau_stub_init;
engine->gpio.takedown = nouveau_stub_takedown;
engine->gpio.get = nv10_gpio_get;
engine->gpio.set = nv10_gpio_set;
engine->gpio.irq_enable = NULL;
break;
case 0x20:
engine->instmem.init = nv04_instmem_init;
@ -138,8 +157,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->instmem.clear = nv04_instmem_clear;
engine->instmem.bind = nv04_instmem_bind;
engine->instmem.unbind = nv04_instmem_unbind;
engine->instmem.prepare_access = nv04_instmem_prepare_access;
engine->instmem.finish_access = nv04_instmem_finish_access;
engine->instmem.flush = nv04_instmem_flush;
engine->mc.init = nv04_mc_init;
engine->mc.takedown = nv04_mc_takedown;
engine->timer.init = nv04_timer_init;
@ -171,6 +189,16 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->fifo.destroy_context = nv10_fifo_destroy_context;
engine->fifo.load_context = nv10_fifo_load_context;
engine->fifo.unload_context = nv10_fifo_unload_context;
engine->display.early_init = nv04_display_early_init;
engine->display.late_takedown = nv04_display_late_takedown;
engine->display.create = nv04_display_create;
engine->display.init = nv04_display_init;
engine->display.destroy = nv04_display_destroy;
engine->gpio.init = nouveau_stub_init;
engine->gpio.takedown = nouveau_stub_takedown;
engine->gpio.get = nv10_gpio_get;
engine->gpio.set = nv10_gpio_set;
engine->gpio.irq_enable = NULL;
break;
case 0x30:
engine->instmem.init = nv04_instmem_init;
@ -181,15 +209,14 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->instmem.clear = nv04_instmem_clear;
engine->instmem.bind = nv04_instmem_bind;
engine->instmem.unbind = nv04_instmem_unbind;
engine->instmem.prepare_access = nv04_instmem_prepare_access;
engine->instmem.finish_access = nv04_instmem_finish_access;
engine->instmem.flush = nv04_instmem_flush;
engine->mc.init = nv04_mc_init;
engine->mc.takedown = nv04_mc_takedown;
engine->timer.init = nv04_timer_init;
engine->timer.read = nv04_timer_read;
engine->timer.takedown = nv04_timer_takedown;
engine->fb.init = nv10_fb_init;
engine->fb.takedown = nv10_fb_takedown;
engine->fb.init = nv30_fb_init;
engine->fb.takedown = nv30_fb_takedown;
engine->fb.set_region_tiling = nv10_fb_set_region_tiling;
engine->graph.grclass = nv30_graph_grclass;
engine->graph.init = nv30_graph_init;
@ -214,6 +241,16 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->fifo.destroy_context = nv10_fifo_destroy_context;
engine->fifo.load_context = nv10_fifo_load_context;
engine->fifo.unload_context = nv10_fifo_unload_context;
engine->display.early_init = nv04_display_early_init;
engine->display.late_takedown = nv04_display_late_takedown;
engine->display.create = nv04_display_create;
engine->display.init = nv04_display_init;
engine->display.destroy = nv04_display_destroy;
engine->gpio.init = nouveau_stub_init;
engine->gpio.takedown = nouveau_stub_takedown;
engine->gpio.get = nv10_gpio_get;
engine->gpio.set = nv10_gpio_set;
engine->gpio.irq_enable = NULL;
break;
case 0x40:
case 0x60:
@ -225,8 +262,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->instmem.clear = nv04_instmem_clear;
engine->instmem.bind = nv04_instmem_bind;
engine->instmem.unbind = nv04_instmem_unbind;
engine->instmem.prepare_access = nv04_instmem_prepare_access;
engine->instmem.finish_access = nv04_instmem_finish_access;
engine->instmem.flush = nv04_instmem_flush;
engine->mc.init = nv40_mc_init;
engine->mc.takedown = nv40_mc_takedown;
engine->timer.init = nv04_timer_init;
@ -258,6 +294,16 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->fifo.destroy_context = nv40_fifo_destroy_context;
engine->fifo.load_context = nv40_fifo_load_context;
engine->fifo.unload_context = nv40_fifo_unload_context;
engine->display.early_init = nv04_display_early_init;
engine->display.late_takedown = nv04_display_late_takedown;
engine->display.create = nv04_display_create;
engine->display.init = nv04_display_init;
engine->display.destroy = nv04_display_destroy;
engine->gpio.init = nouveau_stub_init;
engine->gpio.takedown = nouveau_stub_takedown;
engine->gpio.get = nv10_gpio_get;
engine->gpio.set = nv10_gpio_set;
engine->gpio.irq_enable = NULL;
break;
case 0x50:
case 0x80: /* gotta love NVIDIA's consistency.. */
@ -271,8 +317,10 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->instmem.clear = nv50_instmem_clear;
engine->instmem.bind = nv50_instmem_bind;
engine->instmem.unbind = nv50_instmem_unbind;
engine->instmem.prepare_access = nv50_instmem_prepare_access;
engine->instmem.finish_access = nv50_instmem_finish_access;
if (dev_priv->chipset == 0x50)
engine->instmem.flush = nv50_instmem_flush;
else
engine->instmem.flush = nv84_instmem_flush;
engine->mc.init = nv50_mc_init;
engine->mc.takedown = nv50_mc_takedown;
engine->timer.init = nv04_timer_init;
@ -300,6 +348,16 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->fifo.destroy_context = nv50_fifo_destroy_context;
engine->fifo.load_context = nv50_fifo_load_context;
engine->fifo.unload_context = nv50_fifo_unload_context;
engine->display.early_init = nv50_display_early_init;
engine->display.late_takedown = nv50_display_late_takedown;
engine->display.create = nv50_display_create;
engine->display.init = nv50_display_init;
engine->display.destroy = nv50_display_destroy;
engine->gpio.init = nv50_gpio_init;
engine->gpio.takedown = nouveau_stub_takedown;
engine->gpio.get = nv50_gpio_get;
engine->gpio.set = nv50_gpio_set;
engine->gpio.irq_enable = nv50_gpio_irq_enable;
break;
default:
NV_ERROR(dev, "NV%02x unsupported\n", dev_priv->chipset);
@ -407,11 +465,6 @@ nouveau_card_init(struct drm_device *dev)
struct nouveau_engine *engine;
int ret;
NV_DEBUG(dev, "prev state = %d\n", dev_priv->init_state);
if (dev_priv->init_state == NOUVEAU_CARD_INIT_DONE)
return 0;
vga_client_register(dev->pdev, dev, NULL, nouveau_vga_set_decode);
vga_switcheroo_register_client(dev->pdev, nouveau_switcheroo_set_state,
nouveau_switcheroo_can_switch);
@ -421,15 +474,17 @@ nouveau_card_init(struct drm_device *dev)
if (ret)
goto out;
engine = &dev_priv->engine;
dev_priv->init_state = NOUVEAU_CARD_INIT_FAILED;
spin_lock_init(&dev_priv->context_switch_lock);
/* Make the CRTCs and I2C buses accessible */
ret = engine->display.early_init(dev);
if (ret)
goto out;
/* Parse BIOS tables / Run init tables if card not POSTed */
if (drm_core_check_feature(dev, DRIVER_MODESET)) {
ret = nouveau_bios_init(dev);
if (ret)
goto out;
}
ret = nouveau_bios_init(dev);
if (ret)
goto out_display_early;
ret = nouveau_mem_detect(dev);
if (ret)
@ -461,10 +516,15 @@ nouveau_card_init(struct drm_device *dev)
if (ret)
goto out_gpuobj;
/* PGPIO */
ret = engine->gpio.init(dev);
if (ret)
goto out_mc;
/* PTIMER */
ret = engine->timer.init(dev);
if (ret)
goto out_mc;
goto out_gpio;
/* PFB */
ret = engine->fb.init(dev);
@ -485,12 +545,16 @@ nouveau_card_init(struct drm_device *dev)
goto out_graph;
}
ret = engine->display.create(dev);
if (ret)
goto out_fifo;
/* this call irq_preinstall, register irq handler and
* call irq_postinstall
*/
ret = drm_irq_install(dev);
if (ret)
goto out_fifo;
goto out_display;
ret = drm_vblank_init(dev, 0);
if (ret)
@ -504,35 +568,18 @@ nouveau_card_init(struct drm_device *dev)
goto out_irq;
}
if (drm_core_check_feature(dev, DRIVER_MODESET)) {
if (dev_priv->card_type >= NV_50)
ret = nv50_display_create(dev);
else
ret = nv04_display_create(dev);
if (ret)
goto out_channel;
}
ret = nouveau_backlight_init(dev);
if (ret)
NV_ERROR(dev, "Error %d registering backlight\n", ret);
dev_priv->init_state = NOUVEAU_CARD_INIT_DONE;
if (drm_core_check_feature(dev, DRIVER_MODESET)) {
nouveau_fbcon_init(dev);
drm_kms_helper_poll_init(dev);
}
nouveau_fbcon_init(dev);
drm_kms_helper_poll_init(dev);
return 0;
out_channel:
if (dev_priv->channel) {
nouveau_channel_free(dev_priv->channel);
dev_priv->channel = NULL;
}
out_irq:
drm_irq_uninstall(dev);
out_display:
engine->display.destroy(dev);
out_fifo:
if (!nouveau_noaccel)
engine->fifo.takedown(dev);
@ -543,6 +590,8 @@ out_fb:
engine->fb.takedown(dev);
out_timer:
engine->timer.takedown(dev);
out_gpio:
engine->gpio.takedown(dev);
out_mc:
engine->mc.takedown(dev);
out_gpuobj:
@ -556,6 +605,8 @@ out_gpuobj_early:
nouveau_gpuobj_late_takedown(dev);
out_bios:
nouveau_bios_takedown(dev);
out_display_early:
engine->display.late_takedown(dev);
out:
vga_client_register(dev->pdev, NULL, NULL, NULL);
return ret;
@ -566,45 +617,39 @@ static void nouveau_card_takedown(struct drm_device *dev)
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_engine *engine = &dev_priv->engine;
NV_DEBUG(dev, "prev state = %d\n", dev_priv->init_state);
nouveau_backlight_exit(dev);
if (dev_priv->init_state != NOUVEAU_CARD_INIT_DOWN) {
nouveau_backlight_exit(dev);
if (dev_priv->channel) {
nouveau_channel_free(dev_priv->channel);
dev_priv->channel = NULL;
}
if (!nouveau_noaccel) {
engine->fifo.takedown(dev);
engine->graph.takedown(dev);
}
engine->fb.takedown(dev);
engine->timer.takedown(dev);
engine->mc.takedown(dev);
mutex_lock(&dev->struct_mutex);
ttm_bo_clean_mm(&dev_priv->ttm.bdev, TTM_PL_VRAM);
ttm_bo_clean_mm(&dev_priv->ttm.bdev, TTM_PL_TT);
mutex_unlock(&dev->struct_mutex);
nouveau_sgdma_takedown(dev);
nouveau_gpuobj_takedown(dev);
nouveau_mem_close(dev);
engine->instmem.takedown(dev);
if (drm_core_check_feature(dev, DRIVER_MODESET))
drm_irq_uninstall(dev);
nouveau_gpuobj_late_takedown(dev);
nouveau_bios_takedown(dev);
vga_client_register(dev->pdev, NULL, NULL, NULL);
dev_priv->init_state = NOUVEAU_CARD_INIT_DOWN;
if (dev_priv->channel) {
nouveau_channel_free(dev_priv->channel);
dev_priv->channel = NULL;
}
if (!nouveau_noaccel) {
engine->fifo.takedown(dev);
engine->graph.takedown(dev);
}
engine->fb.takedown(dev);
engine->timer.takedown(dev);
engine->gpio.takedown(dev);
engine->mc.takedown(dev);
engine->display.late_takedown(dev);
mutex_lock(&dev->struct_mutex);
ttm_bo_clean_mm(&dev_priv->ttm.bdev, TTM_PL_VRAM);
ttm_bo_clean_mm(&dev_priv->ttm.bdev, TTM_PL_TT);
mutex_unlock(&dev->struct_mutex);
nouveau_sgdma_takedown(dev);
nouveau_gpuobj_takedown(dev);
nouveau_mem_close(dev);
engine->instmem.takedown(dev);
drm_irq_uninstall(dev);
nouveau_gpuobj_late_takedown(dev);
nouveau_bios_takedown(dev);
vga_client_register(dev->pdev, NULL, NULL, NULL);
}
/* here a client dies, release the stuff that was allocated for its
@ -691,6 +736,7 @@ int nouveau_load(struct drm_device *dev, unsigned long flags)
struct drm_nouveau_private *dev_priv;
uint32_t reg0;
resource_size_t mmio_start_offs;
int ret;
dev_priv = kzalloc(sizeof(*dev_priv), GFP_KERNEL);
if (!dev_priv)
@ -699,7 +745,6 @@ int nouveau_load(struct drm_device *dev, unsigned long flags)
dev_priv->dev = dev;
dev_priv->flags = flags & NOUVEAU_FLAGS;
dev_priv->init_state = NOUVEAU_CARD_INIT_DOWN;
NV_DEBUG(dev, "vendor: 0x%X device: 0x%X class: 0x%X\n",
dev->pci_vendor, dev->pci_device, dev->pdev->class);
@ -773,11 +818,9 @@ int nouveau_load(struct drm_device *dev, unsigned long flags)
NV_INFO(dev, "Detected an NV%2x generation card (0x%08x)\n",
dev_priv->card_type, reg0);
if (drm_core_check_feature(dev, DRIVER_MODESET)) {
int ret = nouveau_remove_conflicting_drivers(dev);
if (ret)
return ret;
}
ret = nouveau_remove_conflicting_drivers(dev);
if (ret)
return ret;
/* Map PRAMIN BAR, or on older cards, the aperture withing BAR0 */
if (dev_priv->card_type >= NV_40) {
@ -812,46 +855,26 @@ int nouveau_load(struct drm_device *dev, unsigned long flags)
dev_priv->flags |= NV_NFORCE2;
/* For kernel modesetting, init card now and bring up fbcon */
if (drm_core_check_feature(dev, DRIVER_MODESET)) {
int ret = nouveau_card_init(dev);
if (ret)
return ret;
}
ret = nouveau_card_init(dev);
if (ret)
return ret;
return 0;
}
static void nouveau_close(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
/* In the case of an error dev_priv may not be allocated yet */
if (dev_priv)
nouveau_card_takedown(dev);
}
/* KMS: we need mmio at load time, not when the first drm client opens. */
void nouveau_lastclose(struct drm_device *dev)
{
if (drm_core_check_feature(dev, DRIVER_MODESET))
return;
nouveau_close(dev);
}
int nouveau_unload(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_engine *engine = &dev_priv->engine;
if (drm_core_check_feature(dev, DRIVER_MODESET)) {
drm_kms_helper_poll_fini(dev);
nouveau_fbcon_fini(dev);
if (dev_priv->card_type >= NV_50)
nv50_display_destroy(dev);
else
nv04_display_destroy(dev);
nouveau_close(dev);
}
drm_kms_helper_poll_fini(dev);
nouveau_fbcon_fini(dev);
engine->display.destroy(dev);
nouveau_card_takedown(dev);
iounmap(dev_priv->mmio);
iounmap(dev_priv->ramin);
@ -867,8 +890,6 @@ int nouveau_ioctl_getparam(struct drm_device *dev, void *data,
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct drm_nouveau_getparam *getparam = data;
NOUVEAU_CHECK_INITIALISED_WITH_RETURN;
switch (getparam->param) {
case NOUVEAU_GETPARAM_CHIPSET_ID:
getparam->value = dev_priv->chipset;
@ -937,8 +958,6 @@ nouveau_ioctl_setparam(struct drm_device *dev, void *data,
{
struct drm_nouveau_setparam *setparam = data;
NOUVEAU_CHECK_INITIALISED_WITH_RETURN;
switch (setparam->param) {
default:
NV_ERROR(dev, "unknown parameter %lld\n", setparam->param);

View file

@ -157,6 +157,7 @@ nv_crtc_dpms(struct drm_crtc *crtc, int mode)
{
struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
struct drm_device *dev = crtc->dev;
struct drm_connector *connector;
unsigned char seq1 = 0, crtc17 = 0;
unsigned char crtc1A;
@ -211,6 +212,10 @@ nv_crtc_dpms(struct drm_crtc *crtc, int mode)
NVVgaSeqReset(dev, nv_crtc->index, false);
NVWriteVgaCrtc(dev, nv_crtc->index, NV_CIO_CRE_RPC1_INDEX, crtc1A);
/* Update connector polling modes */
list_for_each_entry(connector, &dev->mode_config.connector_list, head)
nouveau_connector_set_polling(connector);
}
static bool

View file

@ -220,6 +220,7 @@ uint32_t nv17_dac_sample_load(struct drm_encoder *encoder)
{
struct drm_device *dev = encoder->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_gpio_engine *gpio = &dev_priv->engine.gpio;
struct dcb_entry *dcb = nouveau_encoder(encoder)->dcb;
uint32_t sample, testval, regoffset = nv04_dac_output_offset(encoder);
uint32_t saved_powerctrl_2 = 0, saved_powerctrl_4 = 0, saved_routput,
@ -251,22 +252,21 @@ uint32_t nv17_dac_sample_load(struct drm_encoder *encoder)
nvWriteMC(dev, NV_PBUS_POWERCTRL_4, saved_powerctrl_4 & 0xffffffcf);
}
saved_gpio1 = nv17_gpio_get(dev, DCB_GPIO_TVDAC1);
saved_gpio0 = nv17_gpio_get(dev, DCB_GPIO_TVDAC0);
saved_gpio1 = gpio->get(dev, DCB_GPIO_TVDAC1);
saved_gpio0 = gpio->get(dev, DCB_GPIO_TVDAC0);
nv17_gpio_set(dev, DCB_GPIO_TVDAC1, dcb->type == OUTPUT_TV);
nv17_gpio_set(dev, DCB_GPIO_TVDAC0, dcb->type == OUTPUT_TV);
gpio->set(dev, DCB_GPIO_TVDAC1, dcb->type == OUTPUT_TV);
gpio->set(dev, DCB_GPIO_TVDAC0, dcb->type == OUTPUT_TV);
msleep(4);
saved_routput = NVReadRAMDAC(dev, 0, NV_PRAMDAC_DACCLK + regoffset);
head = (saved_routput & 0x100) >> 8;
#if 0
/* if there's a spare crtc, using it will minimise flicker for the case
* where the in-use crtc is in use by an off-chip tmds encoder */
if (xf86_config->crtc[head]->enabled && !xf86_config->crtc[head ^ 1]->enabled)
/* if there's a spare crtc, using it will minimise flicker */
if (!(NVReadVgaCrtc(dev, head, NV_CIO_CRE_RPC1_INDEX) & 0xC0))
head ^= 1;
#endif
/* nv driver and nv31 use 0xfffffeee, nv34 and 6600 use 0xfffffece */
routput = (saved_routput & 0xfffffece) | head << 8;
@ -304,8 +304,8 @@ uint32_t nv17_dac_sample_load(struct drm_encoder *encoder)
nvWriteMC(dev, NV_PBUS_POWERCTRL_4, saved_powerctrl_4);
nvWriteMC(dev, NV_PBUS_POWERCTRL_2, saved_powerctrl_2);
nv17_gpio_set(dev, DCB_GPIO_TVDAC1, saved_gpio1);
nv17_gpio_set(dev, DCB_GPIO_TVDAC0, saved_gpio0);
gpio->set(dev, DCB_GPIO_TVDAC1, saved_gpio1);
gpio->set(dev, DCB_GPIO_TVDAC0, saved_gpio0);
return sample;
}
@ -315,9 +315,12 @@ nv17_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector)
{
struct drm_device *dev = encoder->dev;
struct dcb_entry *dcb = nouveau_encoder(encoder)->dcb;
uint32_t sample = nv17_dac_sample_load(encoder);
if (sample & NV_PRAMDAC_TEST_CONTROL_SENSEB_ALLHI) {
if (nv04_dac_in_use(encoder))
return connector_status_disconnected;
if (nv17_dac_sample_load(encoder) &
NV_PRAMDAC_TEST_CONTROL_SENSEB_ALLHI) {
NV_INFO(dev, "Load detected on output %c\n",
'@' + ffs(dcb->or));
return connector_status_connected;
@ -330,6 +333,9 @@ static bool nv04_dac_mode_fixup(struct drm_encoder *encoder,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
if (nv04_dac_in_use(encoder))
return false;
return true;
}
@ -428,6 +434,17 @@ void nv04_dac_update_dacclk(struct drm_encoder *encoder, bool enable)
}
}
/* Check if the DAC corresponding to 'encoder' is being used by
* someone else. */
bool nv04_dac_in_use(struct drm_encoder *encoder)
{
struct drm_nouveau_private *dev_priv = encoder->dev->dev_private;
struct dcb_entry *dcb = nouveau_encoder(encoder)->dcb;
return nv_gf4_disp_arch(encoder->dev) &&
(dev_priv->dac_users[ffs(dcb->or) - 1] & ~(1 << dcb->index));
}
static void nv04_dac_dpms(struct drm_encoder *encoder, int mode)
{
struct drm_device *dev = encoder->dev;
@ -501,11 +518,13 @@ static const struct drm_encoder_funcs nv04_dac_funcs = {
.destroy = nv04_dac_destroy,
};
int nv04_dac_create(struct drm_device *dev, struct dcb_entry *entry)
int
nv04_dac_create(struct drm_connector *connector, struct dcb_entry *entry)
{
const struct drm_encoder_helper_funcs *helper;
struct drm_encoder *encoder;
struct nouveau_encoder *nv_encoder = NULL;
struct drm_device *dev = connector->dev;
struct drm_encoder *encoder;
nv_encoder = kzalloc(sizeof(*nv_encoder), GFP_KERNEL);
if (!nv_encoder)
@ -527,5 +546,6 @@ int nv04_dac_create(struct drm_device *dev, struct dcb_entry *entry)
encoder->possible_crtcs = entry->heads;
encoder->possible_clones = 0;
drm_mode_connector_attach_encoder(connector, encoder);
return 0;
}

View file

@ -413,10 +413,6 @@ static void nv04_dfp_commit(struct drm_encoder *encoder)
struct dcb_entry *dcbe = nv_encoder->dcb;
int head = nouveau_crtc(encoder->crtc)->index;
NV_INFO(dev, "Output %s is running on CRTC %d using output %c\n",
drm_get_connector_name(&nouveau_encoder_connector_get(nv_encoder)->base),
nv_crtc->index, '@' + ffs(nv_encoder->dcb->or));
if (dcbe->type == OUTPUT_TMDS)
run_tmds_table(dev, dcbe, head, nv_encoder->mode.clock);
else if (dcbe->type == OUTPUT_LVDS)
@ -584,11 +580,12 @@ static const struct drm_encoder_funcs nv04_dfp_funcs = {
.destroy = nv04_dfp_destroy,
};
int nv04_dfp_create(struct drm_device *dev, struct dcb_entry *entry)
int
nv04_dfp_create(struct drm_connector *connector, struct dcb_entry *entry)
{
const struct drm_encoder_helper_funcs *helper;
struct drm_encoder *encoder;
struct nouveau_encoder *nv_encoder = NULL;
struct drm_encoder *encoder;
int type;
switch (entry->type) {
@ -613,11 +610,12 @@ int nv04_dfp_create(struct drm_device *dev, struct dcb_entry *entry)
nv_encoder->dcb = entry;
nv_encoder->or = ffs(entry->or) - 1;
drm_encoder_init(dev, encoder, &nv04_dfp_funcs, type);
drm_encoder_init(connector->dev, encoder, &nv04_dfp_funcs, type);
drm_encoder_helper_add(encoder, helper);
encoder->possible_crtcs = entry->heads;
encoder->possible_clones = 0;
drm_mode_connector_attach_encoder(connector, encoder);
return 0;
}

View file

@ -32,8 +32,6 @@
#include "nouveau_encoder.h"
#include "nouveau_connector.h"
#define MULTIPLE_ENCODERS(e) (e & (e - 1))
static void
nv04_display_store_initial_head_owner(struct drm_device *dev)
{
@ -41,7 +39,7 @@ nv04_display_store_initial_head_owner(struct drm_device *dev)
if (dev_priv->chipset != 0x11) {
dev_priv->crtc_owner = NVReadVgaCrtc(dev, 0, NV_CIO_CRE_44);
goto ownerknown;
return;
}
/* reading CR44 is broken on nv11, so we attempt to infer it */
@ -52,8 +50,6 @@ nv04_display_store_initial_head_owner(struct drm_device *dev)
bool tvA = false;
bool tvB = false;
NVLockVgaCrtcs(dev, false);
slaved_on_B = NVReadVgaCrtc(dev, 1, NV_CIO_CRE_PIXEL_INDEX) &
0x80;
if (slaved_on_B)
@ -66,8 +62,6 @@ nv04_display_store_initial_head_owner(struct drm_device *dev)
tvA = !(NVReadVgaCrtc(dev, 0, NV_CIO_CRE_LCD__INDEX) &
MASK(NV_CIO_CRE_LCD_LCD_SELECT));
NVLockVgaCrtcs(dev, true);
if (slaved_on_A && !tvA)
dev_priv->crtc_owner = 0x0;
else if (slaved_on_B && !tvB)
@ -79,14 +73,40 @@ nv04_display_store_initial_head_owner(struct drm_device *dev)
else
dev_priv->crtc_owner = 0x0;
}
}
ownerknown:
NV_INFO(dev, "Initial CRTC_OWNER is %d\n", dev_priv->crtc_owner);
int
nv04_display_early_init(struct drm_device *dev)
{
/* Make the I2C buses accessible. */
if (!nv_gf4_disp_arch(dev)) {
uint32_t pmc_enable = nv_rd32(dev, NV03_PMC_ENABLE);
/* we need to ensure the heads are not tied henceforth, or reading any
* 8 bit reg on head B will fail
* setting a single arbitrary head solves that */
NVSetOwner(dev, 0);
if (!(pmc_enable & 1))
nv_wr32(dev, NV03_PMC_ENABLE, pmc_enable | 1);
}
/* Unlock the VGA CRTCs. */
NVLockVgaCrtcs(dev, false);
/* Make sure the CRTCs aren't in slaved mode. */
if (nv_two_heads(dev)) {
nv04_display_store_initial_head_owner(dev);
NVSetOwner(dev, 0);
}
return 0;
}
void
nv04_display_late_takedown(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
if (nv_two_heads(dev))
NVSetOwner(dev, dev_priv->crtc_owner);
NVLockVgaCrtcs(dev, true);
}
int
@ -94,14 +114,13 @@ nv04_display_create(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct dcb_table *dcb = &dev_priv->vbios.dcb;
struct drm_connector *connector, *ct;
struct drm_encoder *encoder;
struct drm_crtc *crtc;
int i, ret;
NV_DEBUG_KMS(dev, "\n");
if (nv_two_heads(dev))
nv04_display_store_initial_head_owner(dev);
nouveau_hw_save_vga_fonts(dev, 1);
drm_mode_config_init(dev);
@ -132,19 +151,23 @@ nv04_display_create(struct drm_device *dev)
for (i = 0; i < dcb->entries; i++) {
struct dcb_entry *dcbent = &dcb->entry[i];
connector = nouveau_connector_create(dev, dcbent->connector);
if (IS_ERR(connector))
continue;
switch (dcbent->type) {
case OUTPUT_ANALOG:
ret = nv04_dac_create(dev, dcbent);
ret = nv04_dac_create(connector, dcbent);
break;
case OUTPUT_LVDS:
case OUTPUT_TMDS:
ret = nv04_dfp_create(dev, dcbent);
ret = nv04_dfp_create(connector, dcbent);
break;
case OUTPUT_TV:
if (dcbent->location == DCB_LOC_ON_CHIP)
ret = nv17_tv_create(dev, dcbent);
ret = nv17_tv_create(connector, dcbent);
else
ret = nv04_tv_create(dev, dcbent);
ret = nv04_tv_create(connector, dcbent);
break;
default:
NV_WARN(dev, "DCB type %d not known\n", dcbent->type);
@ -155,12 +178,16 @@ nv04_display_create(struct drm_device *dev)
continue;
}
for (i = 0; i < dcb->connector.entries; i++)
nouveau_connector_create(dev, &dcb->connector.entry[i]);
list_for_each_entry_safe(connector, ct,
&dev->mode_config.connector_list, head) {
if (!connector->encoder_ids[0]) {
NV_WARN(dev, "%s has no encoders, removing\n",
drm_get_connector_name(connector));
connector->funcs->destroy(connector);
}
}
/* Save previous state */
NVLockVgaCrtcs(dev, false);
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
crtc->funcs->save(crtc);
@ -191,8 +218,6 @@ nv04_display_destroy(struct drm_device *dev)
}
/* Restore state */
NVLockVgaCrtcs(dev, false);
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
struct drm_encoder_helper_funcs *func = encoder->helper_private;
@ -207,15 +232,12 @@ nv04_display_destroy(struct drm_device *dev)
nouveau_hw_save_vga_fonts(dev, 0);
}
void
nv04_display_restore(struct drm_device *dev)
int
nv04_display_init(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct drm_encoder *encoder;
struct drm_crtc *crtc;
NVLockVgaCrtcs(dev, false);
/* meh.. modeset apparently doesn't setup all the regs and depends
* on pre-existing state, for now load the state of the card *before*
* nouveau was loaded, and then do a modeset.
@ -233,12 +255,6 @@ nv04_display_restore(struct drm_device *dev)
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
crtc->funcs->restore(crtc);
if (nv_two_heads(dev)) {
NV_INFO(dev, "Restoring CRTC_OWNER to %d.\n",
dev_priv->crtc_owner);
NVSetOwner(dev, dev_priv->crtc_owner);
}
NVLockVgaCrtcs(dev, true);
return 0;
}

View file

@ -112,6 +112,12 @@ nv04_fifo_channel_id(struct drm_device *dev)
NV03_PFIFO_CACHE1_PUSH1_CHID_MASK;
}
#ifdef __BIG_ENDIAN
#define DMA_FETCH_ENDIANNESS NV_PFIFO_CACHE1_BIG_ENDIAN
#else
#define DMA_FETCH_ENDIANNESS 0
#endif
int
nv04_fifo_create_context(struct nouveau_channel *chan)
{
@ -131,18 +137,13 @@ nv04_fifo_create_context(struct nouveau_channel *chan)
spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
/* Setup initial state */
dev_priv->engine.instmem.prepare_access(dev, true);
RAMFC_WR(DMA_PUT, chan->pushbuf_base);
RAMFC_WR(DMA_GET, chan->pushbuf_base);
RAMFC_WR(DMA_INSTANCE, chan->pushbuf->instance >> 4);
RAMFC_WR(DMA_FETCH, (NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES |
NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES |
NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8 |
#ifdef __BIG_ENDIAN
NV_PFIFO_CACHE1_BIG_ENDIAN |
#endif
0));
dev_priv->engine.instmem.finish_access(dev);
DMA_FETCH_ENDIANNESS));
/* enable the fifo dma operation */
nv_wr32(dev, NV04_PFIFO_MODE,
@ -169,8 +170,6 @@ nv04_fifo_do_load_context(struct drm_device *dev, int chid)
struct drm_nouveau_private *dev_priv = dev->dev_private;
uint32_t fc = NV04_RAMFC(chid), tmp;
dev_priv->engine.instmem.prepare_access(dev, false);
nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_PUT, nv_ri32(dev, fc + 0));
nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_GET, nv_ri32(dev, fc + 4));
tmp = nv_ri32(dev, fc + 8);
@ -181,8 +180,6 @@ nv04_fifo_do_load_context(struct drm_device *dev, int chid)
nv_wr32(dev, NV04_PFIFO_CACHE1_ENGINE, nv_ri32(dev, fc + 20));
nv_wr32(dev, NV04_PFIFO_CACHE1_PULL1, nv_ri32(dev, fc + 24));
dev_priv->engine.instmem.finish_access(dev);
nv_wr32(dev, NV03_PFIFO_CACHE1_GET, 0);
nv_wr32(dev, NV03_PFIFO_CACHE1_PUT, 0);
}
@ -223,7 +220,6 @@ nv04_fifo_unload_context(struct drm_device *dev)
return -EINVAL;
}
dev_priv->engine.instmem.prepare_access(dev, true);
RAMFC_WR(DMA_PUT, nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_PUT));
RAMFC_WR(DMA_GET, nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_GET));
tmp = nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_DCOUNT) << 16;
@ -233,7 +229,6 @@ nv04_fifo_unload_context(struct drm_device *dev)
RAMFC_WR(DMA_FETCH, nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_FETCH));
RAMFC_WR(ENGINE, nv_rd32(dev, NV04_PFIFO_CACHE1_ENGINE));
RAMFC_WR(PULL1_ENGINE, nv_rd32(dev, NV04_PFIFO_CACHE1_PULL1));
dev_priv->engine.instmem.finish_access(dev);
nv04_fifo_do_load_context(dev, pfifo->channels - 1);
nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH1, pfifo->channels - 1);
@ -297,6 +292,7 @@ nv04_fifo_init(struct drm_device *dev)
nv04_fifo_init_intr(dev);
pfifo->enable(dev);
pfifo->reassign(dev, true);
for (i = 0; i < dev_priv->engine.fifo.channels; i++) {
if (dev_priv->fifos[i]) {

View file

@ -342,7 +342,7 @@ static uint32_t nv04_graph_ctx_regs[] = {
};
struct graph_state {
int nv04[ARRAY_SIZE(nv04_graph_ctx_regs)];
uint32_t nv04[ARRAY_SIZE(nv04_graph_ctx_regs)];
};
struct nouveau_channel *
@ -527,8 +527,7 @@ static int
nv04_graph_mthd_set_ref(struct nouveau_channel *chan, int grclass,
int mthd, uint32_t data)
{
chan->fence.last_sequence_irq = data;
nouveau_fence_handler(chan->dev, chan->id);
atomic_set(&chan->fence.last_sequence_irq, data);
return 0;
}

View file

@ -49,10 +49,8 @@ nv04_instmem_determine_amount(struct drm_device *dev)
NV_DEBUG(dev, "RAMIN size: %dKiB\n", dev_priv->ramin_rsvd_vram >> 10);
/* Clear all of it, except the BIOS image that's in the first 64KiB */
dev_priv->engine.instmem.prepare_access(dev, true);
for (i = 64 * 1024; i < dev_priv->ramin_rsvd_vram; i += 4)
nv_wi32(dev, i, 0x00000000);
dev_priv->engine.instmem.finish_access(dev);
}
static void
@ -106,7 +104,7 @@ int nv04_instmem_init(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
uint32_t offset;
int ret = 0;
int ret;
nv04_instmem_determine_amount(dev);
nv04_instmem_configure_fixed_tables(dev);
@ -129,14 +127,14 @@ int nv04_instmem_init(struct drm_device *dev)
offset = 0x40000;
}
ret = nouveau_mem_init_heap(&dev_priv->ramin_heap,
offset, dev_priv->ramin_rsvd_vram - offset);
ret = drm_mm_init(&dev_priv->ramin_heap, offset,
dev_priv->ramin_rsvd_vram - offset);
if (ret) {
dev_priv->ramin_heap = NULL;
NV_ERROR(dev, "Failed to init RAMIN heap\n");
NV_ERROR(dev, "Failed to init RAMIN heap: %d\n", ret);
return ret;
}
return ret;
return 0;
}
void
@ -186,12 +184,7 @@ nv04_instmem_unbind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj)
}
void
nv04_instmem_prepare_access(struct drm_device *dev, bool write)
{
}
void
nv04_instmem_finish_access(struct drm_device *dev)
nv04_instmem_flush(struct drm_device *dev)
{
}

View file

@ -11,6 +11,10 @@ nv04_mc_init(struct drm_device *dev)
*/
nv_wr32(dev, NV03_PMC_ENABLE, 0xFFFFFFFF);
/* Disable PROM access. */
nv_wr32(dev, NV_PBUS_PCI_NV_20, NV_PBUS_PCI_NV_20_ROM_SHADOW_ENABLED);
return 0;
}

View file

@ -34,69 +34,26 @@
#include "i2c/ch7006.h"
static struct {
struct i2c_board_info board_info;
struct drm_encoder_funcs funcs;
struct drm_encoder_helper_funcs hfuncs;
void *params;
} nv04_tv_encoder_info[] = {
static struct i2c_board_info nv04_tv_encoder_info[] = {
{
.board_info = { I2C_BOARD_INFO("ch7006", 0x75) },
.params = &(struct ch7006_encoder_params) {
I2C_BOARD_INFO("ch7006", 0x75),
.platform_data = &(struct ch7006_encoder_params) {
CH7006_FORMAT_RGB24m12I, CH7006_CLOCK_MASTER,
0, 0, 0,
CH7006_SYNC_SLAVE, CH7006_SYNC_SEPARATED,
CH7006_POUT_3_3V, CH7006_ACTIVE_HSYNC
},
}
},
{ }
};
static bool probe_i2c_addr(struct i2c_adapter *adapter, int addr)
{
struct i2c_msg msg = {
.addr = addr,
.len = 0,
};
return i2c_transfer(adapter, &msg, 1) == 1;
}
int nv04_tv_identify(struct drm_device *dev, int i2c_index)
{
struct nouveau_i2c_chan *i2c;
bool was_locked;
int i, ret;
NV_TRACE(dev, "Probing TV encoders on I2C bus: %d\n", i2c_index);
i2c = nouveau_i2c_find(dev, i2c_index);
if (!i2c)
return -ENODEV;
was_locked = NVLockVgaCrtcs(dev, false);
for (i = 0; i < ARRAY_SIZE(nv04_tv_encoder_info); i++) {
if (probe_i2c_addr(&i2c->adapter,
nv04_tv_encoder_info[i].board_info.addr)) {
ret = i;
break;
}
}
if (i < ARRAY_SIZE(nv04_tv_encoder_info)) {
NV_TRACE(dev, "Detected TV encoder: %s\n",
nv04_tv_encoder_info[i].board_info.type);
} else {
NV_TRACE(dev, "No TV encoders found.\n");
i = -ENODEV;
}
NVLockVgaCrtcs(dev, was_locked);
return i;
return nouveau_i2c_identify(dev, "TV encoder",
nv04_tv_encoder_info, i2c_index);
}
#define PLLSEL_TV_CRTC1_MASK \
(NV_PRAMDAC_PLL_COEFF_SELECT_TV_VSCLK1 \
| NV_PRAMDAC_PLL_COEFF_SELECT_TV_PCLK1)
@ -214,30 +171,32 @@ static void nv04_tv_commit(struct drm_encoder *encoder)
static void nv04_tv_destroy(struct drm_encoder *encoder)
{
struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
to_encoder_slave(encoder)->slave_funcs->destroy(encoder);
drm_encoder_cleanup(encoder);
kfree(nv_encoder);
kfree(encoder->helper_private);
kfree(nouveau_encoder(encoder));
}
int nv04_tv_create(struct drm_device *dev, struct dcb_entry *entry)
static const struct drm_encoder_funcs nv04_tv_funcs = {
.destroy = nv04_tv_destroy,
};
int
nv04_tv_create(struct drm_connector *connector, struct dcb_entry *entry)
{
struct nouveau_encoder *nv_encoder;
struct drm_encoder *encoder;
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct i2c_adapter *adap;
struct drm_encoder_funcs *funcs = NULL;
struct drm_encoder_helper_funcs *hfuncs = NULL;
struct drm_encoder_slave_funcs *sfuncs = NULL;
int i2c_index = entry->i2c_index;
struct drm_device *dev = connector->dev;
struct drm_encoder_helper_funcs *hfuncs;
struct drm_encoder_slave_funcs *sfuncs;
struct nouveau_i2c_chan *i2c =
nouveau_i2c_find(dev, entry->i2c_index);
int type, ret;
bool was_locked;
/* Ensure that we can talk to this encoder */
type = nv04_tv_identify(dev, i2c_index);
type = nv04_tv_identify(dev, entry->i2c_index);
if (type < 0)
return type;
@ -246,41 +205,32 @@ int nv04_tv_create(struct drm_device *dev, struct dcb_entry *entry)
if (!nv_encoder)
return -ENOMEM;
hfuncs = kzalloc(sizeof(*hfuncs), GFP_KERNEL);
if (!hfuncs) {
ret = -ENOMEM;
goto fail_free;
}
/* Initialize the common members */
encoder = to_drm_encoder(nv_encoder);
funcs = &nv04_tv_encoder_info[type].funcs;
hfuncs = &nv04_tv_encoder_info[type].hfuncs;
drm_encoder_init(dev, encoder, funcs, DRM_MODE_ENCODER_TVDAC);
drm_encoder_init(dev, encoder, &nv04_tv_funcs, DRM_MODE_ENCODER_TVDAC);
drm_encoder_helper_add(encoder, hfuncs);
encoder->possible_crtcs = entry->heads;
encoder->possible_clones = 0;
nv_encoder->dcb = entry;
nv_encoder->or = ffs(entry->or) - 1;
/* Run the slave-specific initialization */
adap = &dev_priv->vbios.dcb.i2c[i2c_index].chan->adapter;
was_locked = NVLockVgaCrtcs(dev, false);
ret = drm_i2c_encoder_init(encoder->dev, to_encoder_slave(encoder), adap,
&nv04_tv_encoder_info[type].board_info);
NVLockVgaCrtcs(dev, was_locked);
ret = drm_i2c_encoder_init(dev, to_encoder_slave(encoder),
&i2c->adapter, &nv04_tv_encoder_info[type]);
if (ret < 0)
goto fail;
goto fail_cleanup;
/* Fill the function pointers */
sfuncs = to_encoder_slave(encoder)->slave_funcs;
*funcs = (struct drm_encoder_funcs) {
.destroy = nv04_tv_destroy,
};
*hfuncs = (struct drm_encoder_helper_funcs) {
.dpms = nv04_tv_dpms,
.save = sfuncs->save,
@ -292,14 +242,17 @@ int nv04_tv_create(struct drm_device *dev, struct dcb_entry *entry)
.detect = sfuncs->detect,
};
/* Set the slave encoder configuration */
sfuncs->set_config(encoder, nv04_tv_encoder_info[type].params);
/* Attach it to the specified connector. */
sfuncs->set_config(encoder, nv04_tv_encoder_info[type].platform_data);
sfuncs->create_resources(encoder, connector);
drm_mode_connector_attach_encoder(connector, encoder);
return 0;
fail:
fail_cleanup:
drm_encoder_cleanup(encoder);
kfree(hfuncs);
fail_free:
kfree(nv_encoder);
return ret;
}

View file

@ -55,7 +55,6 @@ nv10_fifo_create_context(struct nouveau_channel *chan)
/* Fill entries that are seen filled in dumps of nvidia driver just
* after channel's is put into DMA mode
*/
dev_priv->engine.instmem.prepare_access(dev, true);
nv_wi32(dev, fc + 0, chan->pushbuf_base);
nv_wi32(dev, fc + 4, chan->pushbuf_base);
nv_wi32(dev, fc + 12, chan->pushbuf->instance >> 4);
@ -66,7 +65,6 @@ nv10_fifo_create_context(struct nouveau_channel *chan)
NV_PFIFO_CACHE1_BIG_ENDIAN |
#endif
0);
dev_priv->engine.instmem.finish_access(dev);
/* enable the fifo dma operation */
nv_wr32(dev, NV04_PFIFO_MODE,
@ -91,8 +89,6 @@ nv10_fifo_do_load_context(struct drm_device *dev, int chid)
struct drm_nouveau_private *dev_priv = dev->dev_private;
uint32_t fc = NV10_RAMFC(chid), tmp;
dev_priv->engine.instmem.prepare_access(dev, false);
nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_PUT, nv_ri32(dev, fc + 0));
nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_GET, nv_ri32(dev, fc + 4));
nv_wr32(dev, NV10_PFIFO_CACHE1_REF_CNT, nv_ri32(dev, fc + 8));
@ -117,8 +113,6 @@ nv10_fifo_do_load_context(struct drm_device *dev, int chid)
nv_wr32(dev, NV10_PFIFO_CACHE1_DMA_SUBROUTINE, nv_ri32(dev, fc + 48));
out:
dev_priv->engine.instmem.finish_access(dev);
nv_wr32(dev, NV03_PFIFO_CACHE1_GET, 0);
nv_wr32(dev, NV03_PFIFO_CACHE1_PUT, 0);
}
@ -155,8 +149,6 @@ nv10_fifo_unload_context(struct drm_device *dev)
return 0;
fc = NV10_RAMFC(chid);
dev_priv->engine.instmem.prepare_access(dev, true);
nv_wi32(dev, fc + 0, nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_PUT));
nv_wi32(dev, fc + 4, nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_GET));
nv_wi32(dev, fc + 8, nv_rd32(dev, NV10_PFIFO_CACHE1_REF_CNT));
@ -179,8 +171,6 @@ nv10_fifo_unload_context(struct drm_device *dev)
nv_wi32(dev, fc + 48, nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_GET));
out:
dev_priv->engine.instmem.finish_access(dev);
nv10_fifo_do_load_context(dev, pfifo->channels - 1);
nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH1, pfifo->channels - 1);
return 0;

View file

@ -55,7 +55,7 @@ get_gpio_location(struct dcb_gpio_entry *ent, uint32_t *reg, uint32_t *shift,
}
int
nv17_gpio_get(struct drm_device *dev, enum dcb_gpio_tag tag)
nv10_gpio_get(struct drm_device *dev, enum dcb_gpio_tag tag)
{
struct dcb_gpio_entry *ent = nouveau_bios_gpio_entry(dev, tag);
uint32_t reg, shift, mask, value;
@ -72,7 +72,7 @@ nv17_gpio_get(struct drm_device *dev, enum dcb_gpio_tag tag)
}
int
nv17_gpio_set(struct drm_device *dev, enum dcb_gpio_tag tag, int state)
nv10_gpio_set(struct drm_device *dev, enum dcb_gpio_tag tag, int state)
{
struct dcb_gpio_entry *ent = nouveau_bios_gpio_entry(dev, tag);
uint32_t reg, shift, mask, value;

View file

@ -37,6 +37,7 @@ static uint32_t nv42_tv_sample_load(struct drm_encoder *encoder)
{
struct drm_device *dev = encoder->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_gpio_engine *gpio = &dev_priv->engine.gpio;
uint32_t testval, regoffset = nv04_dac_output_offset(encoder);
uint32_t gpio0, gpio1, fp_htotal, fp_hsync_start, fp_hsync_end,
fp_control, test_ctrl, dacclk, ctv_14, ctv_1c, ctv_6c;
@ -52,8 +53,8 @@ static uint32_t nv42_tv_sample_load(struct drm_encoder *encoder)
head = (dacclk & 0x100) >> 8;
/* Save the previous state. */
gpio1 = nv17_gpio_get(dev, DCB_GPIO_TVDAC1);
gpio0 = nv17_gpio_get(dev, DCB_GPIO_TVDAC0);
gpio1 = gpio->get(dev, DCB_GPIO_TVDAC1);
gpio0 = gpio->get(dev, DCB_GPIO_TVDAC0);
fp_htotal = NVReadRAMDAC(dev, head, NV_PRAMDAC_FP_HTOTAL);
fp_hsync_start = NVReadRAMDAC(dev, head, NV_PRAMDAC_FP_HSYNC_START);
fp_hsync_end = NVReadRAMDAC(dev, head, NV_PRAMDAC_FP_HSYNC_END);
@ -64,8 +65,8 @@ static uint32_t nv42_tv_sample_load(struct drm_encoder *encoder)
ctv_6c = NVReadRAMDAC(dev, head, 0x680c6c);
/* Prepare the DAC for load detection. */
nv17_gpio_set(dev, DCB_GPIO_TVDAC1, true);
nv17_gpio_set(dev, DCB_GPIO_TVDAC0, true);
gpio->set(dev, DCB_GPIO_TVDAC1, true);
gpio->set(dev, DCB_GPIO_TVDAC0, true);
NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_HTOTAL, 1343);
NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_HSYNC_START, 1047);
@ -110,12 +111,27 @@ static uint32_t nv42_tv_sample_load(struct drm_encoder *encoder)
NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_HSYNC_END, fp_hsync_end);
NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_HSYNC_START, fp_hsync_start);
NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_HTOTAL, fp_htotal);
nv17_gpio_set(dev, DCB_GPIO_TVDAC1, gpio1);
nv17_gpio_set(dev, DCB_GPIO_TVDAC0, gpio0);
gpio->set(dev, DCB_GPIO_TVDAC1, gpio1);
gpio->set(dev, DCB_GPIO_TVDAC0, gpio0);
return sample;
}
static bool
get_tv_detect_quirks(struct drm_device *dev, uint32_t *pin_mask)
{
/* Zotac FX5200 */
if (dev->pdev->device == 0x0322 &&
dev->pdev->subsystem_vendor == 0x19da &&
(dev->pdev->subsystem_device == 0x1035 ||
dev->pdev->subsystem_device == 0x2035)) {
*pin_mask = 0xc;
return false;
}
return true;
}
static enum drm_connector_status
nv17_tv_detect(struct drm_encoder *encoder, struct drm_connector *connector)
{
@ -124,12 +140,20 @@ nv17_tv_detect(struct drm_encoder *encoder, struct drm_connector *connector)
struct drm_mode_config *conf = &dev->mode_config;
struct nv17_tv_encoder *tv_enc = to_tv_enc(encoder);
struct dcb_entry *dcb = tv_enc->base.dcb;
bool reliable = get_tv_detect_quirks(dev, &tv_enc->pin_mask);
if (dev_priv->chipset == 0x42 ||
dev_priv->chipset == 0x43)
tv_enc->pin_mask = nv42_tv_sample_load(encoder) >> 28 & 0xe;
else
tv_enc->pin_mask = nv17_dac_sample_load(encoder) >> 28 & 0xe;
if (nv04_dac_in_use(encoder))
return connector_status_disconnected;
if (reliable) {
if (dev_priv->chipset == 0x42 ||
dev_priv->chipset == 0x43)
tv_enc->pin_mask =
nv42_tv_sample_load(encoder) >> 28 & 0xe;
else
tv_enc->pin_mask =
nv17_dac_sample_load(encoder) >> 28 & 0xe;
}
switch (tv_enc->pin_mask) {
case 0x2:
@ -154,7 +178,9 @@ nv17_tv_detect(struct drm_encoder *encoder, struct drm_connector *connector)
conf->tv_subconnector_property,
tv_enc->subconnector);
if (tv_enc->subconnector) {
if (!reliable) {
return connector_status_unknown;
} else if (tv_enc->subconnector) {
NV_INFO(dev, "Load detected on output %c\n",
'@' + ffs(dcb->or));
return connector_status_connected;
@ -296,6 +322,9 @@ static bool nv17_tv_mode_fixup(struct drm_encoder *encoder,
{
struct nv17_tv_norm_params *tv_norm = get_tv_norm(encoder);
if (nv04_dac_in_use(encoder))
return false;
if (tv_norm->kind == CTV_ENC_MODE)
adjusted_mode->clock = tv_norm->ctv_enc_mode.mode.clock;
else
@ -307,6 +336,8 @@ static bool nv17_tv_mode_fixup(struct drm_encoder *encoder,
static void nv17_tv_dpms(struct drm_encoder *encoder, int mode)
{
struct drm_device *dev = encoder->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_gpio_engine *gpio = &dev_priv->engine.gpio;
struct nv17_tv_state *regs = &to_tv_enc(encoder)->state;
struct nv17_tv_norm_params *tv_norm = get_tv_norm(encoder);
@ -331,8 +362,8 @@ static void nv17_tv_dpms(struct drm_encoder *encoder, int mode)
nv_load_ptv(dev, regs, 200);
nv17_gpio_set(dev, DCB_GPIO_TVDAC1, mode == DRM_MODE_DPMS_ON);
nv17_gpio_set(dev, DCB_GPIO_TVDAC0, mode == DRM_MODE_DPMS_ON);
gpio->set(dev, DCB_GPIO_TVDAC1, mode == DRM_MODE_DPMS_ON);
gpio->set(dev, DCB_GPIO_TVDAC0, mode == DRM_MODE_DPMS_ON);
nv04_dac_update_dacclk(encoder, mode == DRM_MODE_DPMS_ON);
}
@ -744,8 +775,10 @@ static struct drm_encoder_funcs nv17_tv_funcs = {
.destroy = nv17_tv_destroy,
};
int nv17_tv_create(struct drm_device *dev, struct dcb_entry *entry)
int
nv17_tv_create(struct drm_connector *connector, struct dcb_entry *entry)
{
struct drm_device *dev = connector->dev;
struct drm_encoder *encoder;
struct nv17_tv_encoder *tv_enc = NULL;
@ -774,5 +807,7 @@ int nv17_tv_create(struct drm_device *dev, struct dcb_entry *entry)
encoder->possible_crtcs = entry->heads;
encoder->possible_clones = 0;
nv17_tv_create_resources(encoder, connector);
drm_mode_connector_attach_encoder(connector, encoder);
return 0;
}

View file

@ -370,68 +370,54 @@ nv20_graph_create_context(struct nouveau_channel *chan)
{
struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
void (*ctx_init)(struct drm_device *, struct nouveau_gpuobj *);
unsigned int ctx_size;
unsigned int idoffs = 0x28/4;
int ret;
switch (dev_priv->chipset) {
case 0x20:
ctx_size = NV20_GRCTX_SIZE;
ctx_init = nv20_graph_context_init;
idoffs = 0;
break;
case 0x25:
case 0x28:
ctx_size = NV25_GRCTX_SIZE;
ctx_init = nv25_graph_context_init;
break;
case 0x2a:
ctx_size = NV2A_GRCTX_SIZE;
ctx_init = nv2a_graph_context_init;
idoffs = 0;
break;
case 0x30:
case 0x31:
ctx_size = NV30_31_GRCTX_SIZE;
ctx_init = nv30_31_graph_context_init;
break;
case 0x34:
ctx_size = NV34_GRCTX_SIZE;
ctx_init = nv34_graph_context_init;
break;
case 0x35:
case 0x36:
ctx_size = NV35_36_GRCTX_SIZE;
ctx_init = nv35_36_graph_context_init;
break;
default:
ctx_size = 0;
ctx_init = nv35_36_graph_context_init;
NV_ERROR(dev, "Please contact the devs if you want your NV%x"
" card to work\n", dev_priv->chipset);
return -ENOSYS;
break;
BUG_ON(1);
}
ret = nouveau_gpuobj_new_ref(dev, chan, NULL, 0, ctx_size, 16,
NVOBJ_FLAG_ZERO_ALLOC,
&chan->ramin_grctx);
ret = nouveau_gpuobj_new_ref(dev, chan, NULL, 0, pgraph->grctx_size,
16, NVOBJ_FLAG_ZERO_ALLOC,
&chan->ramin_grctx);
if (ret)
return ret;
/* Initialise default context values */
dev_priv->engine.instmem.prepare_access(dev, true);
ctx_init(dev, chan->ramin_grctx->gpuobj);
/* nv20: nv_wo32(dev, chan->ramin_grctx->gpuobj, 10, chan->id<<24); */
nv_wo32(dev, chan->ramin_grctx->gpuobj, idoffs,
(chan->id << 24) | 0x1); /* CTX_USER */
nv_wo32(dev, dev_priv->ctx_table->gpuobj, chan->id,
chan->ramin_grctx->instance >> 4);
dev_priv->engine.instmem.finish_access(dev);
nv_wo32(dev, pgraph->ctx_table->gpuobj, chan->id,
chan->ramin_grctx->instance >> 4);
return 0;
}
@ -440,13 +426,12 @@ nv20_graph_destroy_context(struct nouveau_channel *chan)
{
struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
if (chan->ramin_grctx)
nouveau_gpuobj_ref_del(dev, &chan->ramin_grctx);
dev_priv->engine.instmem.prepare_access(dev, true);
nv_wo32(dev, dev_priv->ctx_table->gpuobj, chan->id, 0);
dev_priv->engine.instmem.finish_access(dev);
nv_wo32(dev, pgraph->ctx_table->gpuobj, chan->id, 0);
}
int
@ -538,29 +523,44 @@ nv20_graph_set_region_tiling(struct drm_device *dev, int i, uint32_t addr,
int
nv20_graph_init(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv =
(struct drm_nouveau_private *)dev->dev_private;
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
uint32_t tmp, vramsz;
int ret, i;
switch (dev_priv->chipset) {
case 0x20:
pgraph->grctx_size = NV20_GRCTX_SIZE;
break;
case 0x25:
case 0x28:
pgraph->grctx_size = NV25_GRCTX_SIZE;
break;
case 0x2a:
pgraph->grctx_size = NV2A_GRCTX_SIZE;
break;
default:
NV_ERROR(dev, "unknown chipset, disabling acceleration\n");
pgraph->accel_blocked = true;
return 0;
}
nv_wr32(dev, NV03_PMC_ENABLE,
nv_rd32(dev, NV03_PMC_ENABLE) & ~NV_PMC_ENABLE_PGRAPH);
nv_wr32(dev, NV03_PMC_ENABLE,
nv_rd32(dev, NV03_PMC_ENABLE) | NV_PMC_ENABLE_PGRAPH);
if (!dev_priv->ctx_table) {
if (!pgraph->ctx_table) {
/* Create Context Pointer Table */
dev_priv->ctx_table_size = 32 * 4;
ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0,
dev_priv->ctx_table_size, 16,
ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0, 32 * 4, 16,
NVOBJ_FLAG_ZERO_ALLOC,
&dev_priv->ctx_table);
&pgraph->ctx_table);
if (ret)
return ret;
}
nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_TABLE,
dev_priv->ctx_table->instance >> 4);
pgraph->ctx_table->instance >> 4);
nv20_graph_rdi(dev);
@ -644,34 +644,52 @@ void
nv20_graph_takedown(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
nouveau_gpuobj_ref_del(dev, &dev_priv->ctx_table);
nouveau_gpuobj_ref_del(dev, &pgraph->ctx_table);
}
int
nv30_graph_init(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
int ret, i;
switch (dev_priv->chipset) {
case 0x30:
case 0x31:
pgraph->grctx_size = NV30_31_GRCTX_SIZE;
break;
case 0x34:
pgraph->grctx_size = NV34_GRCTX_SIZE;
break;
case 0x35:
case 0x36:
pgraph->grctx_size = NV35_36_GRCTX_SIZE;
break;
default:
NV_ERROR(dev, "unknown chipset, disabling acceleration\n");
pgraph->accel_blocked = true;
return 0;
}
nv_wr32(dev, NV03_PMC_ENABLE,
nv_rd32(dev, NV03_PMC_ENABLE) & ~NV_PMC_ENABLE_PGRAPH);
nv_wr32(dev, NV03_PMC_ENABLE,
nv_rd32(dev, NV03_PMC_ENABLE) | NV_PMC_ENABLE_PGRAPH);
if (!dev_priv->ctx_table) {
if (!pgraph->ctx_table) {
/* Create Context Pointer Table */
dev_priv->ctx_table_size = 32 * 4;
ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0,
dev_priv->ctx_table_size, 16,
ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0, 32 * 4, 16,
NVOBJ_FLAG_ZERO_ALLOC,
&dev_priv->ctx_table);
&pgraph->ctx_table);
if (ret)
return ret;
}
nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_TABLE,
dev_priv->ctx_table->instance >> 4);
pgraph->ctx_table->instance >> 4);
nv_wr32(dev, NV03_PGRAPH_INTR , 0xFFFFFFFF);
nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF);

View file

@ -0,0 +1,87 @@
/*
* Copyright (C) 2010 Francisco Jerez.
* All Rights Reserved.
*
* 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 (including the
* next paragraph) 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 OWNER(S) AND/OR ITS SUPPLIERS 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.
*
*/
#include "drmP.h"
#include "drm.h"
#include "nouveau_drv.h"
#include "nouveau_drm.h"
static int
calc_ref(int b, int l, int i)
{
int j, x = 0;
for (j = 0; j < 4; j++) {
int n = (b >> (8 * j) & 0xf);
int m = (l >> (8 * i) & 0xff) + 2 * (n & 0x8 ? n - 0x10 : n);
x |= (0x80 | (m & 0x1f)) << (8 * j);
}
return x;
}
int
nv30_fb_init(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_fb_engine *pfb = &dev_priv->engine.fb;
int i, j;
pfb->num_tiles = NV10_PFB_TILE__SIZE;
/* Turn all the tiling regions off. */
for (i = 0; i < pfb->num_tiles; i++)
pfb->set_region_tiling(dev, i, 0, 0, 0);
/* Init the memory timing regs at 0x10037c/0x1003ac */
if (dev_priv->chipset == 0x30 ||
dev_priv->chipset == 0x31 ||
dev_priv->chipset == 0x35) {
/* Related to ROP count */
int n = (dev_priv->chipset == 0x31 ? 2 : 4);
int b = (dev_priv->chipset > 0x30 ?
nv_rd32(dev, 0x122c) & 0xf : 0);
int l = nv_rd32(dev, 0x1003d0);
for (i = 0; i < n; i++) {
for (j = 0; j < 3; j++)
nv_wr32(dev, 0x10037c + 0xc * i + 0x4 * j,
calc_ref(b, l, j));
for (j = 0; j < 2; j++)
nv_wr32(dev, 0x1003ac + 0x8 * i + 0x4 * j,
calc_ref(b, l, j));
}
}
return 0;
}
void
nv30_fb_takedown(struct drm_device *dev)
{
}

View file

@ -48,7 +48,6 @@ nv40_fifo_create_context(struct nouveau_channel *chan)
spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
dev_priv->engine.instmem.prepare_access(dev, true);
nv_wi32(dev, fc + 0, chan->pushbuf_base);
nv_wi32(dev, fc + 4, chan->pushbuf_base);
nv_wi32(dev, fc + 12, chan->pushbuf->instance >> 4);
@ -61,7 +60,6 @@ nv40_fifo_create_context(struct nouveau_channel *chan)
0x30000000 /* no idea.. */);
nv_wi32(dev, fc + 56, chan->ramin_grctx->instance >> 4);
nv_wi32(dev, fc + 60, 0x0001FFFF);
dev_priv->engine.instmem.finish_access(dev);
/* enable the fifo dma operation */
nv_wr32(dev, NV04_PFIFO_MODE,
@ -89,8 +87,6 @@ nv40_fifo_do_load_context(struct drm_device *dev, int chid)
struct drm_nouveau_private *dev_priv = dev->dev_private;
uint32_t fc = NV40_RAMFC(chid), tmp, tmp2;
dev_priv->engine.instmem.prepare_access(dev, false);
nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_PUT, nv_ri32(dev, fc + 0));
nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_GET, nv_ri32(dev, fc + 4));
nv_wr32(dev, NV10_PFIFO_CACHE1_REF_CNT, nv_ri32(dev, fc + 8));
@ -127,8 +123,6 @@ nv40_fifo_do_load_context(struct drm_device *dev, int chid)
nv_wr32(dev, 0x2088, nv_ri32(dev, fc + 76));
nv_wr32(dev, 0x3300, nv_ri32(dev, fc + 80));
dev_priv->engine.instmem.finish_access(dev);
nv_wr32(dev, NV03_PFIFO_CACHE1_GET, 0);
nv_wr32(dev, NV03_PFIFO_CACHE1_PUT, 0);
}
@ -166,7 +160,6 @@ nv40_fifo_unload_context(struct drm_device *dev)
return 0;
fc = NV40_RAMFC(chid);
dev_priv->engine.instmem.prepare_access(dev, true);
nv_wi32(dev, fc + 0, nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_PUT));
nv_wi32(dev, fc + 4, nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_GET));
nv_wi32(dev, fc + 8, nv_rd32(dev, NV10_PFIFO_CACHE1_REF_CNT));
@ -200,7 +193,6 @@ nv40_fifo_unload_context(struct drm_device *dev)
tmp |= (nv_rd32(dev, NV04_PFIFO_CACHE1_PUT) << 16);
nv_wi32(dev, fc + 72, tmp);
#endif
dev_priv->engine.instmem.finish_access(dev);
nv40_fifo_do_load_context(dev, pfifo->channels - 1);
nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH1,

View file

@ -58,6 +58,7 @@ nv40_graph_create_context(struct nouveau_channel *chan)
struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
struct nouveau_grctx ctx = {};
int ret;
ret = nouveau_gpuobj_new_ref(dev, chan, NULL, 0, pgraph->grctx_size,
@ -67,20 +68,13 @@ nv40_graph_create_context(struct nouveau_channel *chan)
return ret;
/* Initialise default context values */
dev_priv->engine.instmem.prepare_access(dev, true);
if (!pgraph->ctxprog) {
struct nouveau_grctx ctx = {};
ctx.dev = chan->dev;
ctx.mode = NOUVEAU_GRCTX_VALS;
ctx.data = chan->ramin_grctx->gpuobj;
nv40_grctx_init(&ctx);
ctx.dev = chan->dev;
ctx.mode = NOUVEAU_GRCTX_VALS;
ctx.data = chan->ramin_grctx->gpuobj;
nv40_grctx_init(&ctx);
} else {
nouveau_grctx_vals_load(dev, chan->ramin_grctx->gpuobj);
}
nv_wo32(dev, chan->ramin_grctx->gpuobj, 0,
chan->ramin_grctx->gpuobj->im_pramin->start);
dev_priv->engine.instmem.finish_access(dev);
return 0;
}
@ -238,7 +232,8 @@ nv40_graph_init(struct drm_device *dev)
struct drm_nouveau_private *dev_priv =
(struct drm_nouveau_private *)dev->dev_private;
struct nouveau_fb_engine *pfb = &dev_priv->engine.fb;
uint32_t vramsz;
struct nouveau_grctx ctx = {};
uint32_t vramsz, *cp;
int i, j;
nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) &
@ -246,32 +241,22 @@ nv40_graph_init(struct drm_device *dev)
nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) |
NV_PMC_ENABLE_PGRAPH);
if (nouveau_ctxfw) {
nouveau_grctx_prog_load(dev);
dev_priv->engine.graph.grctx_size = 175 * 1024;
}
cp = kmalloc(sizeof(*cp) * 256, GFP_KERNEL);
if (!cp)
return -ENOMEM;
if (!dev_priv->engine.graph.ctxprog) {
struct nouveau_grctx ctx = {};
uint32_t *cp;
ctx.dev = dev;
ctx.mode = NOUVEAU_GRCTX_PROG;
ctx.data = cp;
ctx.ctxprog_max = 256;
nv40_grctx_init(&ctx);
dev_priv->engine.graph.grctx_size = ctx.ctxvals_pos * 4;
cp = kmalloc(sizeof(*cp) * 256, GFP_KERNEL);
if (!cp)
return -ENOMEM;
nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_INDEX, 0);
for (i = 0; i < ctx.ctxprog_len; i++)
nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_DATA, cp[i]);
ctx.dev = dev;
ctx.mode = NOUVEAU_GRCTX_PROG;
ctx.data = cp;
ctx.ctxprog_max = 256;
nv40_grctx_init(&ctx);
dev_priv->engine.graph.grctx_size = ctx.ctxvals_pos * 4;
nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_INDEX, 0);
for (i = 0; i < ctx.ctxprog_len; i++)
nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_DATA, cp[i]);
kfree(cp);
}
kfree(cp);
/* No context present currently */
nv_wr32(dev, NV40_PGRAPH_CTXCTL_CUR, 0x00000000);
@ -407,7 +392,6 @@ nv40_graph_init(struct drm_device *dev)
void nv40_graph_takedown(struct drm_device *dev)
{
nouveau_grctx_fini(dev);
}
struct nouveau_pgraph_object_class nv40_graph_grclass[] = {

View file

@ -19,7 +19,7 @@ nv40_mc_init(struct drm_device *dev)
case 0x46: /* G72 */
case 0x4e:
case 0x4c: /* C51_G7X */
tmp = nv_rd32(dev, NV40_PFB_020C);
tmp = nv_rd32(dev, NV04_PFB_FIFO_DATA);
nv_wr32(dev, NV40_PMC_1700, tmp);
nv_wr32(dev, NV40_PMC_1704, 0);
nv_wr32(dev, NV40_PMC_1708, 0);

View file

@ -440,47 +440,15 @@ nv50_crtc_prepare(struct drm_crtc *crtc)
{
struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
struct drm_device *dev = crtc->dev;
struct drm_encoder *encoder;
uint32_t dac = 0, sor = 0;
NV_DEBUG_KMS(dev, "index %d\n", nv_crtc->index);
/* Disconnect all unused encoders. */
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
if (!drm_helper_encoder_in_use(encoder))
continue;
if (nv_encoder->dcb->type == OUTPUT_ANALOG ||
nv_encoder->dcb->type == OUTPUT_TV)
dac |= (1 << nv_encoder->or);
else
sor |= (1 << nv_encoder->or);
}
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
if (nv_encoder->dcb->type == OUTPUT_ANALOG ||
nv_encoder->dcb->type == OUTPUT_TV) {
if (dac & (1 << nv_encoder->or))
continue;
} else {
if (sor & (1 << nv_encoder->or))
continue;
}
nv_encoder->disconnect(nv_encoder);
}
nv50_crtc_blank(nv_crtc, true);
}
static void
nv50_crtc_commit(struct drm_crtc *crtc)
{
struct drm_crtc *crtc2;
struct drm_device *dev = crtc->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_channel *evo = dev_priv->evo;
@ -491,20 +459,14 @@ nv50_crtc_commit(struct drm_crtc *crtc)
nv50_crtc_blank(nv_crtc, false);
/* Explicitly blank all unused crtc's. */
list_for_each_entry(crtc2, &dev->mode_config.crtc_list, head) {
if (!drm_helper_crtc_in_use(crtc2))
nv50_crtc_blank(nouveau_crtc(crtc2), true);
}
ret = RING_SPACE(evo, 2);
if (ret) {
NV_ERROR(dev, "no space while committing crtc\n");
return;
}
BEGIN_RING(evo, 0, NV50_EVO_UPDATE, 1);
OUT_RING(evo, 0);
FIRE_RING(evo);
OUT_RING (evo, 0);
FIRE_RING (evo);
}
static bool

View file

@ -37,22 +37,31 @@
#include "nv50_display.h"
static void
nv50_dac_disconnect(struct nouveau_encoder *nv_encoder)
nv50_dac_disconnect(struct drm_encoder *encoder)
{
struct drm_device *dev = to_drm_encoder(nv_encoder)->dev;
struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
struct drm_device *dev = encoder->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_channel *evo = dev_priv->evo;
int ret;
if (!nv_encoder->crtc)
return;
nv50_crtc_blank(nouveau_crtc(nv_encoder->crtc), true);
NV_DEBUG_KMS(dev, "Disconnecting DAC %d\n", nv_encoder->or);
ret = RING_SPACE(evo, 2);
ret = RING_SPACE(evo, 4);
if (ret) {
NV_ERROR(dev, "no space while disconnecting DAC\n");
return;
}
BEGIN_RING(evo, 0, NV50_EVO_DAC(nv_encoder->or, MODE_CTRL), 1);
OUT_RING(evo, 0);
OUT_RING (evo, 0);
BEGIN_RING(evo, 0, NV50_EVO_UPDATE, 1);
OUT_RING (evo, 0);
nv_encoder->crtc = NULL;
}
static enum drm_connector_status
@ -213,7 +222,8 @@ nv50_dac_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
uint32_t mode_ctl = 0, mode_ctl2 = 0;
int ret;
NV_DEBUG_KMS(dev, "or %d\n", nv_encoder->or);
NV_DEBUG_KMS(dev, "or %d type %d crtc %d\n",
nv_encoder->or, nv_encoder->dcb->type, crtc->index);
nv50_dac_dpms(encoder, DRM_MODE_DPMS_ON);
@ -243,6 +253,14 @@ nv50_dac_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
BEGIN_RING(evo, 0, NV50_EVO_DAC(nv_encoder->or, MODE_CTRL), 2);
OUT_RING(evo, mode_ctl);
OUT_RING(evo, mode_ctl2);
nv_encoder->crtc = encoder->crtc;
}
static struct drm_crtc *
nv50_dac_crtc_get(struct drm_encoder *encoder)
{
return nouveau_encoder(encoder)->crtc;
}
static const struct drm_encoder_helper_funcs nv50_dac_helper_funcs = {
@ -253,7 +271,9 @@ static const struct drm_encoder_helper_funcs nv50_dac_helper_funcs = {
.prepare = nv50_dac_prepare,
.commit = nv50_dac_commit,
.mode_set = nv50_dac_mode_set,
.detect = nv50_dac_detect
.get_crtc = nv50_dac_crtc_get,
.detect = nv50_dac_detect,
.disable = nv50_dac_disconnect
};
static void
@ -275,14 +295,11 @@ static const struct drm_encoder_funcs nv50_dac_encoder_funcs = {
};
int
nv50_dac_create(struct drm_device *dev, struct dcb_entry *entry)
nv50_dac_create(struct drm_connector *connector, struct dcb_entry *entry)
{
struct nouveau_encoder *nv_encoder;
struct drm_encoder *encoder;
NV_DEBUG_KMS(dev, "\n");
NV_INFO(dev, "Detected a DAC output\n");
nv_encoder = kzalloc(sizeof(*nv_encoder), GFP_KERNEL);
if (!nv_encoder)
return -ENOMEM;
@ -291,14 +308,14 @@ nv50_dac_create(struct drm_device *dev, struct dcb_entry *entry)
nv_encoder->dcb = entry;
nv_encoder->or = ffs(entry->or) - 1;
nv_encoder->disconnect = nv50_dac_disconnect;
drm_encoder_init(dev, encoder, &nv50_dac_encoder_funcs,
drm_encoder_init(connector->dev, encoder, &nv50_dac_encoder_funcs,
DRM_MODE_ENCODER_DAC);
drm_encoder_helper_add(encoder, &nv50_dac_helper_funcs);
encoder->possible_crtcs = entry->heads;
encoder->possible_clones = 0;
drm_mode_connector_attach_encoder(connector, encoder);
return 0;
}

View file

@ -71,14 +71,13 @@ nv50_evo_dmaobj_new(struct nouveau_channel *evo, uint32_t class, uint32_t name,
return ret;
}
dev_priv->engine.instmem.prepare_access(dev, true);
nv_wo32(dev, obj, 0, (tile_flags << 22) | (magic_flags << 16) | class);
nv_wo32(dev, obj, 1, limit);
nv_wo32(dev, obj, 2, offset);
nv_wo32(dev, obj, 3, 0x00000000);
nv_wo32(dev, obj, 4, 0x00000000);
nv_wo32(dev, obj, 5, 0x00010000);
dev_priv->engine.instmem.finish_access(dev);
dev_priv->engine.instmem.flush(dev);
return 0;
}
@ -110,8 +109,8 @@ nv50_evo_channel_new(struct drm_device *dev, struct nouveau_channel **pchan)
return ret;
}
ret = nouveau_mem_init_heap(&chan->ramin_heap, chan->ramin->gpuobj->
im_pramin->start, 32768);
ret = drm_mm_init(&chan->ramin_heap,
chan->ramin->gpuobj->im_pramin->start, 32768);
if (ret) {
NV_ERROR(dev, "Error initialising EVO PRAMIN heap: %d\n", ret);
nv50_evo_channel_del(pchan);
@ -178,14 +177,26 @@ nv50_evo_channel_new(struct drm_device *dev, struct nouveau_channel **pchan)
return 0;
}
int
nv50_display_early_init(struct drm_device *dev)
{
return 0;
}
void
nv50_display_late_takedown(struct drm_device *dev)
{
}
int
nv50_display_init(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_timer_engine *ptimer = &dev_priv->engine.timer;
struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio;
struct nouveau_channel *evo = dev_priv->evo;
struct drm_connector *connector;
uint32_t val, ram_amount, hpd_en[2];
uint32_t val, ram_amount;
uint64_t start;
int ret, i;
@ -366,26 +377,13 @@ nv50_display_init(struct drm_device *dev)
NV50_PDISPLAY_INTR_EN_CLK_UNK40));
/* enable hotplug interrupts */
hpd_en[0] = hpd_en[1] = 0;
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
struct nouveau_connector *conn = nouveau_connector(connector);
struct dcb_gpio_entry *gpio;
if (conn->dcb->gpio_tag == 0xff)
continue;
gpio = nouveau_bios_gpio_entry(dev, conn->dcb->gpio_tag);
if (!gpio)
continue;
hpd_en[gpio->line >> 4] |= (0x00010001 << (gpio->line & 0xf));
}
nv_wr32(dev, 0xe054, 0xffffffff);
nv_wr32(dev, 0xe050, hpd_en[0]);
if (dev_priv->chipset >= 0x90) {
nv_wr32(dev, 0xe074, 0xffffffff);
nv_wr32(dev, 0xe070, hpd_en[1]);
pgpio->irq_enable(dev, conn->dcb->gpio_tag, true);
}
return 0;
@ -465,6 +463,7 @@ int nv50_display_create(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct dcb_table *dcb = &dev_priv->vbios.dcb;
struct drm_connector *connector, *ct;
int ret, i;
NV_DEBUG_KMS(dev, "\n");
@ -507,14 +506,18 @@ int nv50_display_create(struct drm_device *dev)
continue;
}
connector = nouveau_connector_create(dev, entry->connector);
if (IS_ERR(connector))
continue;
switch (entry->type) {
case OUTPUT_TMDS:
case OUTPUT_LVDS:
case OUTPUT_DP:
nv50_sor_create(dev, entry);
nv50_sor_create(connector, entry);
break;
case OUTPUT_ANALOG:
nv50_dac_create(dev, entry);
nv50_dac_create(connector, entry);
break;
default:
NV_WARN(dev, "DCB encoder %d unknown\n", entry->type);
@ -522,11 +525,13 @@ int nv50_display_create(struct drm_device *dev)
}
}
for (i = 0 ; i < dcb->connector.entries; i++) {
if (i != 0 && dcb->connector.entry[i].index2 ==
dcb->connector.entry[i - 1].index2)
continue;
nouveau_connector_create(dev, &dcb->connector.entry[i]);
list_for_each_entry_safe(connector, ct,
&dev->mode_config.connector_list, head) {
if (!connector->encoder_ids[0]) {
NV_WARN(dev, "%s has no encoders, removing\n",
drm_get_connector_name(connector));
connector->funcs->destroy(connector);
}
}
ret = nv50_display_init(dev);
@ -538,7 +543,8 @@ int nv50_display_create(struct drm_device *dev)
return 0;
}
int nv50_display_destroy(struct drm_device *dev)
void
nv50_display_destroy(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
@ -548,135 +554,30 @@ int nv50_display_destroy(struct drm_device *dev)
nv50_display_disable(dev);
nv50_evo_channel_del(&dev_priv->evo);
return 0;
}
static inline uint32_t
nv50_display_mode_ctrl(struct drm_device *dev, bool sor, int or)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
uint32_t mc;
if (sor) {
if (dev_priv->chipset < 0x90 ||
dev_priv->chipset == 0x92 || dev_priv->chipset == 0xa0)
mc = nv_rd32(dev, NV50_PDISPLAY_SOR_MODE_CTRL_P(or));
else
mc = nv_rd32(dev, NV90_PDISPLAY_SOR_MODE_CTRL_P(or));
} else {
mc = nv_rd32(dev, NV50_PDISPLAY_DAC_MODE_CTRL_P(or));
}
return mc;
}
static int
nv50_display_irq_head(struct drm_device *dev, int *phead,
struct dcb_entry **pdcbent)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
uint32_t unk30 = nv_rd32(dev, NV50_PDISPLAY_UNK30_CTRL);
uint32_t dac = 0, sor = 0;
int head, i, or = 0, type = OUTPUT_ANY;
/* We're assuming that head 0 *or* head 1 will be active here,
* and not both. I'm not sure if the hw will even signal both
* ever, but it definitely shouldn't for us as we commit each
* CRTC separately, and submission will be blocked by the GPU
* until we handle each in turn.
*/
NV_DEBUG_KMS(dev, "0x610030: 0x%08x\n", unk30);
head = ffs((unk30 >> 9) & 3) - 1;
if (head < 0)
return -EINVAL;
/* This assumes CRTCs are never bound to multiple encoders, which
* should be the case.
*/
for (i = 0; i < 3 && type == OUTPUT_ANY; i++) {
uint32_t mc = nv50_display_mode_ctrl(dev, false, i);
if (!(mc & (1 << head)))
continue;
switch ((mc >> 8) & 0xf) {
case 0: type = OUTPUT_ANALOG; break;
case 1: type = OUTPUT_TV; break;
default:
NV_ERROR(dev, "unknown dac mode_ctrl: 0x%08x\n", dac);
return -1;
}
or = i;
}
for (i = 0; i < 4 && type == OUTPUT_ANY; i++) {
uint32_t mc = nv50_display_mode_ctrl(dev, true, i);
if (!(mc & (1 << head)))
continue;
switch ((mc >> 8) & 0xf) {
case 0: type = OUTPUT_LVDS; break;
case 1: type = OUTPUT_TMDS; break;
case 2: type = OUTPUT_TMDS; break;
case 5: type = OUTPUT_TMDS; break;
case 8: type = OUTPUT_DP; break;
case 9: type = OUTPUT_DP; break;
default:
NV_ERROR(dev, "unknown sor mode_ctrl: 0x%08x\n", sor);
return -1;
}
or = i;
}
NV_DEBUG_KMS(dev, "type %d, or %d\n", type, or);
if (type == OUTPUT_ANY) {
NV_ERROR(dev, "unknown encoder!!\n");
return -1;
}
for (i = 0; i < dev_priv->vbios.dcb.entries; i++) {
struct dcb_entry *dcbent = &dev_priv->vbios.dcb.entry[i];
if (dcbent->type != type)
continue;
if (!(dcbent->or & (1 << or)))
continue;
*phead = head;
*pdcbent = dcbent;
return 0;
}
NV_ERROR(dev, "no DCB entry for %d %d\n", dac != 0, or);
return 0;
}
static uint32_t
nv50_display_script_select(struct drm_device *dev, struct dcb_entry *dcbent,
int pxclk)
static u16
nv50_display_script_select(struct drm_device *dev, struct dcb_entry *dcb,
u32 mc, int pxclk)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_connector *nv_connector = NULL;
struct drm_encoder *encoder;
struct nvbios *bios = &dev_priv->vbios;
uint32_t mc, script = 0, or;
u32 script = 0, or;
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
if (nv_encoder->dcb != dcbent)
if (nv_encoder->dcb != dcb)
continue;
nv_connector = nouveau_encoder_connector_get(nv_encoder);
break;
}
or = ffs(dcbent->or) - 1;
mc = nv50_display_mode_ctrl(dev, dcbent->type != OUTPUT_ANALOG, or);
switch (dcbent->type) {
or = ffs(dcb->or) - 1;
switch (dcb->type) {
case OUTPUT_LVDS:
script = (mc >> 8) & 0xf;
if (bios->fp_no_ddc) {
@ -767,17 +668,88 @@ nv50_display_vblank_handler(struct drm_device *dev, uint32_t intr)
static void
nv50_display_unk10_handler(struct drm_device *dev)
{
struct dcb_entry *dcbent;
int head, ret;
struct drm_nouveau_private *dev_priv = dev->dev_private;
u32 unk30 = nv_rd32(dev, 0x610030), mc;
int i, crtc, or, type = OUTPUT_ANY;
ret = nv50_display_irq_head(dev, &head, &dcbent);
if (ret)
goto ack;
NV_DEBUG_KMS(dev, "0x610030: 0x%08x\n", unk30);
dev_priv->evo_irq.dcb = NULL;
nv_wr32(dev, 0x619494, nv_rd32(dev, 0x619494) & ~8);
nouveau_bios_run_display_table(dev, dcbent, 0, -1);
/* Determine which CRTC we're dealing with, only 1 ever will be
* signalled at the same time with the current nouveau code.
*/
crtc = ffs((unk30 & 0x00000060) >> 5) - 1;
if (crtc < 0)
goto ack;
/* Nothing needs to be done for the encoder */
crtc = ffs((unk30 & 0x00000180) >> 7) - 1;
if (crtc < 0)
goto ack;
/* Find which encoder was connected to the CRTC */
for (i = 0; type == OUTPUT_ANY && i < 3; i++) {
mc = nv_rd32(dev, NV50_PDISPLAY_DAC_MODE_CTRL_C(i));
NV_DEBUG_KMS(dev, "DAC-%d mc: 0x%08x\n", i, mc);
if (!(mc & (1 << crtc)))
continue;
switch ((mc & 0x00000f00) >> 8) {
case 0: type = OUTPUT_ANALOG; break;
case 1: type = OUTPUT_TV; break;
default:
NV_ERROR(dev, "invalid mc, DAC-%d: 0x%08x\n", i, mc);
goto ack;
}
or = i;
}
for (i = 0; type == OUTPUT_ANY && i < 4; i++) {
if (dev_priv->chipset < 0x90 ||
dev_priv->chipset == 0x92 ||
dev_priv->chipset == 0xa0)
mc = nv_rd32(dev, NV50_PDISPLAY_SOR_MODE_CTRL_C(i));
else
mc = nv_rd32(dev, NV90_PDISPLAY_SOR_MODE_CTRL_C(i));
NV_DEBUG_KMS(dev, "SOR-%d mc: 0x%08x\n", i, mc);
if (!(mc & (1 << crtc)))
continue;
switch ((mc & 0x00000f00) >> 8) {
case 0: type = OUTPUT_LVDS; break;
case 1: type = OUTPUT_TMDS; break;
case 2: type = OUTPUT_TMDS; break;
case 5: type = OUTPUT_TMDS; break;
case 8: type = OUTPUT_DP; break;
case 9: type = OUTPUT_DP; break;
default:
NV_ERROR(dev, "invalid mc, SOR-%d: 0x%08x\n", i, mc);
goto ack;
}
or = i;
}
/* There was no encoder to disable */
if (type == OUTPUT_ANY)
goto ack;
/* Disable the encoder */
for (i = 0; i < dev_priv->vbios.dcb.entries; i++) {
struct dcb_entry *dcb = &dev_priv->vbios.dcb.entry[i];
if (dcb->type == type && (dcb->or & (1 << or))) {
nouveau_bios_run_display_table(dev, dcb, 0, -1);
dev_priv->evo_irq.dcb = dcb;
goto ack;
}
}
NV_ERROR(dev, "no dcb for %d %d 0x%08x\n", or, type, mc);
ack:
nv_wr32(dev, NV50_PDISPLAY_INTR_1, NV50_PDISPLAY_INTR_1_CLK_UNK10);
nv_wr32(dev, 0x610030, 0x80000000);
@ -817,33 +789,103 @@ nv50_display_unk20_dp_hack(struct drm_device *dev, struct dcb_entry *dcb)
static void
nv50_display_unk20_handler(struct drm_device *dev)
{
struct dcb_entry *dcbent;
uint32_t tmp, pclk, script;
int head, or, ret;
struct drm_nouveau_private *dev_priv = dev->dev_private;
u32 unk30 = nv_rd32(dev, 0x610030), tmp, pclk, script, mc;
struct dcb_entry *dcb;
int i, crtc, or, type = OUTPUT_ANY;
ret = nv50_display_irq_head(dev, &head, &dcbent);
if (ret)
NV_DEBUG_KMS(dev, "0x610030: 0x%08x\n", unk30);
dcb = dev_priv->evo_irq.dcb;
if (dcb) {
nouveau_bios_run_display_table(dev, dcb, 0, -2);
dev_priv->evo_irq.dcb = NULL;
}
/* CRTC clock change requested? */
crtc = ffs((unk30 & 0x00000600) >> 9) - 1;
if (crtc >= 0) {
pclk = nv_rd32(dev, NV50_PDISPLAY_CRTC_P(crtc, CLOCK));
pclk &= 0x003fffff;
nv50_crtc_set_clock(dev, crtc, pclk);
tmp = nv_rd32(dev, NV50_PDISPLAY_CRTC_CLK_CTRL2(crtc));
tmp &= ~0x000000f;
nv_wr32(dev, NV50_PDISPLAY_CRTC_CLK_CTRL2(crtc), tmp);
}
/* Nothing needs to be done for the encoder */
crtc = ffs((unk30 & 0x00000180) >> 7) - 1;
if (crtc < 0)
goto ack;
or = ffs(dcbent->or) - 1;
pclk = nv_rd32(dev, NV50_PDISPLAY_CRTC_P(head, CLOCK)) & 0x3fffff;
script = nv50_display_script_select(dev, dcbent, pclk);
pclk = nv_rd32(dev, NV50_PDISPLAY_CRTC_P(crtc, CLOCK)) & 0x003fffff;
NV_DEBUG_KMS(dev, "head %d pxclk: %dKHz\n", head, pclk);
/* Find which encoder is connected to the CRTC */
for (i = 0; type == OUTPUT_ANY && i < 3; i++) {
mc = nv_rd32(dev, NV50_PDISPLAY_DAC_MODE_CTRL_P(i));
NV_DEBUG_KMS(dev, "DAC-%d mc: 0x%08x\n", i, mc);
if (!(mc & (1 << crtc)))
continue;
if (dcbent->type != OUTPUT_DP)
nouveau_bios_run_display_table(dev, dcbent, 0, -2);
switch ((mc & 0x00000f00) >> 8) {
case 0: type = OUTPUT_ANALOG; break;
case 1: type = OUTPUT_TV; break;
default:
NV_ERROR(dev, "invalid mc, DAC-%d: 0x%08x\n", i, mc);
goto ack;
}
nv50_crtc_set_clock(dev, head, pclk);
or = i;
}
nouveau_bios_run_display_table(dev, dcbent, script, pclk);
for (i = 0; type == OUTPUT_ANY && i < 4; i++) {
if (dev_priv->chipset < 0x90 ||
dev_priv->chipset == 0x92 ||
dev_priv->chipset == 0xa0)
mc = nv_rd32(dev, NV50_PDISPLAY_SOR_MODE_CTRL_P(i));
else
mc = nv_rd32(dev, NV90_PDISPLAY_SOR_MODE_CTRL_P(i));
nv50_display_unk20_dp_hack(dev, dcbent);
NV_DEBUG_KMS(dev, "SOR-%d mc: 0x%08x\n", i, mc);
if (!(mc & (1 << crtc)))
continue;
tmp = nv_rd32(dev, NV50_PDISPLAY_CRTC_CLK_CTRL2(head));
tmp &= ~0x000000f;
nv_wr32(dev, NV50_PDISPLAY_CRTC_CLK_CTRL2(head), tmp);
switch ((mc & 0x00000f00) >> 8) {
case 0: type = OUTPUT_LVDS; break;
case 1: type = OUTPUT_TMDS; break;
case 2: type = OUTPUT_TMDS; break;
case 5: type = OUTPUT_TMDS; break;
case 8: type = OUTPUT_DP; break;
case 9: type = OUTPUT_DP; break;
default:
NV_ERROR(dev, "invalid mc, SOR-%d: 0x%08x\n", i, mc);
goto ack;
}
if (dcbent->type != OUTPUT_ANALOG) {
or = i;
}
if (type == OUTPUT_ANY)
goto ack;
/* Enable the encoder */
for (i = 0; i < dev_priv->vbios.dcb.entries; i++) {
dcb = &dev_priv->vbios.dcb.entry[i];
if (dcb->type == type && (dcb->or & (1 << or)))
break;
}
if (i == dev_priv->vbios.dcb.entries) {
NV_ERROR(dev, "no dcb for %d %d 0x%08x\n", or, type, mc);
goto ack;
}
script = nv50_display_script_select(dev, dcb, mc, pclk);
nouveau_bios_run_display_table(dev, dcb, script, pclk);
nv50_display_unk20_dp_hack(dev, dcb);
if (dcb->type != OUTPUT_ANALOG) {
tmp = nv_rd32(dev, NV50_PDISPLAY_SOR_CLK_CTRL2(or));
tmp &= ~0x00000f0f;
if (script & 0x0100)
@ -853,24 +895,61 @@ nv50_display_unk20_handler(struct drm_device *dev)
nv_wr32(dev, NV50_PDISPLAY_DAC_CLK_CTRL2(or), 0);
}
dev_priv->evo_irq.dcb = dcb;
dev_priv->evo_irq.pclk = pclk;
dev_priv->evo_irq.script = script;
ack:
nv_wr32(dev, NV50_PDISPLAY_INTR_1, NV50_PDISPLAY_INTR_1_CLK_UNK20);
nv_wr32(dev, 0x610030, 0x80000000);
}
/* If programming a TMDS output on a SOR that can also be configured for
* DisplayPort, make sure NV50_SOR_DP_CTRL_ENABLE is forced off.
*
* It looks like the VBIOS TMDS scripts make an attempt at this, however,
* the VBIOS scripts on at least one board I have only switch it off on
* link 0, causing a blank display if the output has previously been
* programmed for DisplayPort.
*/
static void
nv50_display_unk40_dp_set_tmds(struct drm_device *dev, struct dcb_entry *dcb)
{
int or = ffs(dcb->or) - 1, link = !(dcb->dpconf.sor.link & 1);
struct drm_encoder *encoder;
u32 tmp;
if (dcb->type != OUTPUT_TMDS)
return;
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
if (nv_encoder->dcb->type == OUTPUT_DP &&
nv_encoder->dcb->or & (1 << or)) {
tmp = nv_rd32(dev, NV50_SOR_DP_CTRL(or, link));
tmp &= ~NV50_SOR_DP_CTRL_ENABLED;
nv_wr32(dev, NV50_SOR_DP_CTRL(or, link), tmp);
break;
}
}
}
static void
nv50_display_unk40_handler(struct drm_device *dev)
{
struct dcb_entry *dcbent;
int head, pclk, script, ret;
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct dcb_entry *dcb = dev_priv->evo_irq.dcb;
u16 script = dev_priv->evo_irq.script;
u32 unk30 = nv_rd32(dev, 0x610030), pclk = dev_priv->evo_irq.pclk;
ret = nv50_display_irq_head(dev, &head, &dcbent);
if (ret)
NV_DEBUG_KMS(dev, "0x610030: 0x%08x\n", unk30);
dev_priv->evo_irq.dcb = NULL;
if (!dcb)
goto ack;
pclk = nv_rd32(dev, NV50_PDISPLAY_CRTC_P(head, CLOCK)) & 0x3fffff;
script = nv50_display_script_select(dev, dcbent, pclk);
nouveau_bios_run_display_table(dev, dcbent, script, -pclk);
nouveau_bios_run_display_table(dev, dcb, script, -pclk);
nv50_display_unk40_dp_set_tmds(dev, dcb);
ack:
nv_wr32(dev, NV50_PDISPLAY_INTR_1, NV50_PDISPLAY_INTR_1_CLK_UNK40);

View file

@ -38,9 +38,11 @@
void nv50_display_irq_handler(struct drm_device *dev);
void nv50_display_irq_handler_bh(struct work_struct *work);
void nv50_display_irq_hotplug_bh(struct work_struct *work);
int nv50_display_init(struct drm_device *dev);
int nv50_display_early_init(struct drm_device *dev);
void nv50_display_late_takedown(struct drm_device *dev);
int nv50_display_create(struct drm_device *dev);
int nv50_display_destroy(struct drm_device *dev);
int nv50_display_init(struct drm_device *dev);
void nv50_display_destroy(struct drm_device *dev);
int nv50_crtc_blank(struct nouveau_crtc *, bool blank);
int nv50_crtc_set_clock(struct drm_device *, int head, int pclk);

View file

@ -28,41 +28,33 @@
#include "drm.h"
#include "nouveau_drv.h"
struct nv50_fifo_priv {
struct nouveau_gpuobj_ref *thingo[2];
int cur_thingo;
};
#define IS_G80 ((dev_priv->chipset & 0xf0) == 0x50)
static void
nv50_fifo_init_thingo(struct drm_device *dev)
nv50_fifo_playlist_update(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nv50_fifo_priv *priv = dev_priv->engine.fifo.priv;
struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
struct nouveau_gpuobj_ref *cur;
int i, nr;
NV_DEBUG(dev, "\n");
cur = priv->thingo[priv->cur_thingo];
priv->cur_thingo = !priv->cur_thingo;
cur = pfifo->playlist[pfifo->cur_playlist];
pfifo->cur_playlist = !pfifo->cur_playlist;
/* We never schedule channel 0 or 127 */
dev_priv->engine.instmem.prepare_access(dev, true);
for (i = 1, nr = 0; i < 127; i++) {
if (dev_priv->fifos[i] && dev_priv->fifos[i]->ramfc)
nv_wo32(dev, cur->gpuobj, nr++, i);
}
dev_priv->engine.instmem.finish_access(dev);
dev_priv->engine.instmem.flush(dev);
nv_wr32(dev, 0x32f4, cur->instance >> 12);
nv_wr32(dev, 0x32ec, nr);
nv_wr32(dev, 0x2500, 0x101);
}
static int
nv50_fifo_channel_enable(struct drm_device *dev, int channel, bool nt)
static void
nv50_fifo_channel_enable(struct drm_device *dev, int channel)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_channel *chan = dev_priv->fifos[channel];
@ -70,37 +62,28 @@ nv50_fifo_channel_enable(struct drm_device *dev, int channel, bool nt)
NV_DEBUG(dev, "ch%d\n", channel);
if (!chan->ramfc)
return -EINVAL;
if (IS_G80)
if (dev_priv->chipset == 0x50)
inst = chan->ramfc->instance >> 12;
else
inst = chan->ramfc->instance >> 8;
nv_wr32(dev, NV50_PFIFO_CTX_TABLE(channel),
inst | NV50_PFIFO_CTX_TABLE_CHANNEL_ENABLED);
if (!nt)
nv50_fifo_init_thingo(dev);
return 0;
nv_wr32(dev, NV50_PFIFO_CTX_TABLE(channel), inst |
NV50_PFIFO_CTX_TABLE_CHANNEL_ENABLED);
}
static void
nv50_fifo_channel_disable(struct drm_device *dev, int channel, bool nt)
nv50_fifo_channel_disable(struct drm_device *dev, int channel)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
uint32_t inst;
NV_DEBUG(dev, "ch%d, nt=%d\n", channel, nt);
NV_DEBUG(dev, "ch%d\n", channel);
if (IS_G80)
if (dev_priv->chipset == 0x50)
inst = NV50_PFIFO_CTX_TABLE_INSTANCE_MASK_G80;
else
inst = NV50_PFIFO_CTX_TABLE_INSTANCE_MASK_G84;
nv_wr32(dev, NV50_PFIFO_CTX_TABLE(channel), inst);
if (!nt)
nv50_fifo_init_thingo(dev);
}
static void
@ -133,12 +116,12 @@ nv50_fifo_init_context_table(struct drm_device *dev)
for (i = 0; i < NV50_PFIFO_CTX_TABLE__SIZE; i++) {
if (dev_priv->fifos[i])
nv50_fifo_channel_enable(dev, i, true);
nv50_fifo_channel_enable(dev, i);
else
nv50_fifo_channel_disable(dev, i, true);
nv50_fifo_channel_disable(dev, i);
}
nv50_fifo_init_thingo(dev);
nv50_fifo_playlist_update(dev);
}
static void
@ -162,41 +145,38 @@ nv50_fifo_init_regs(struct drm_device *dev)
nv_wr32(dev, 0x3270, 0);
/* Enable dummy channels setup by nv50_instmem.c */
nv50_fifo_channel_enable(dev, 0, true);
nv50_fifo_channel_enable(dev, 127, true);
nv50_fifo_channel_enable(dev, 0);
nv50_fifo_channel_enable(dev, 127);
}
int
nv50_fifo_init(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nv50_fifo_priv *priv;
struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
int ret;
NV_DEBUG(dev, "\n");
priv = dev_priv->engine.fifo.priv;
if (priv) {
priv->cur_thingo = !priv->cur_thingo;
if (pfifo->playlist[0]) {
pfifo->cur_playlist = !pfifo->cur_playlist;
goto just_reset;
}
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
dev_priv->engine.fifo.priv = priv;
ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0, 128*4, 0x1000,
NVOBJ_FLAG_ZERO_ALLOC, &priv->thingo[0]);
NVOBJ_FLAG_ZERO_ALLOC,
&pfifo->playlist[0]);
if (ret) {
NV_ERROR(dev, "error creating thingo0: %d\n", ret);
NV_ERROR(dev, "error creating playlist 0: %d\n", ret);
return ret;
}
ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0, 128*4, 0x1000,
NVOBJ_FLAG_ZERO_ALLOC, &priv->thingo[1]);
NVOBJ_FLAG_ZERO_ALLOC,
&pfifo->playlist[1]);
if (ret) {
NV_ERROR(dev, "error creating thingo1: %d\n", ret);
nouveau_gpuobj_ref_del(dev, &pfifo->playlist[0]);
NV_ERROR(dev, "error creating playlist 1: %d\n", ret);
return ret;
}
@ -216,18 +196,15 @@ void
nv50_fifo_takedown(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nv50_fifo_priv *priv = dev_priv->engine.fifo.priv;
struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
NV_DEBUG(dev, "\n");
if (!priv)
if (!pfifo->playlist[0])
return;
nouveau_gpuobj_ref_del(dev, &priv->thingo[0]);
nouveau_gpuobj_ref_del(dev, &priv->thingo[1]);
dev_priv->engine.fifo.priv = NULL;
kfree(priv);
nouveau_gpuobj_ref_del(dev, &pfifo->playlist[0]);
nouveau_gpuobj_ref_del(dev, &pfifo->playlist[1]);
}
int
@ -248,7 +225,7 @@ nv50_fifo_create_context(struct nouveau_channel *chan)
NV_DEBUG(dev, "ch%d\n", chan->id);
if (IS_G80) {
if (dev_priv->chipset == 0x50) {
uint32_t ramin_poffset = chan->ramin->gpuobj->im_pramin->start;
uint32_t ramin_voffset = chan->ramin->gpuobj->im_backing_start;
@ -281,10 +258,10 @@ nv50_fifo_create_context(struct nouveau_channel *chan)
spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
dev_priv->engine.instmem.prepare_access(dev, true);
nv_wo32(dev, ramfc, 0x48/4, chan->pushbuf->instance >> 4);
nv_wo32(dev, ramfc, 0x80/4, (0xc << 24) | (chan->ramht->instance >> 4));
nv_wo32(dev, ramfc, 0x80/4, (0 << 27) /* 4KiB */ |
(4 << 24) /* SEARCH_FULL */ |
(chan->ramht->instance >> 4));
nv_wo32(dev, ramfc, 0x44/4, 0x2101ffff);
nv_wo32(dev, ramfc, 0x60/4, 0x7fffffff);
nv_wo32(dev, ramfc, 0x40/4, 0x00000000);
@ -295,7 +272,7 @@ nv50_fifo_create_context(struct nouveau_channel *chan)
chan->dma.ib_base * 4);
nv_wo32(dev, ramfc, 0x54/4, drm_order(chan->dma.ib_max + 1) << 16);
if (!IS_G80) {
if (dev_priv->chipset != 0x50) {
nv_wo32(dev, chan->ramin->gpuobj, 0, chan->id);
nv_wo32(dev, chan->ramin->gpuobj, 1,
chan->ramfc->instance >> 8);
@ -304,16 +281,10 @@ nv50_fifo_create_context(struct nouveau_channel *chan)
nv_wo32(dev, ramfc, 0x98/4, chan->ramin->instance >> 12);
}
dev_priv->engine.instmem.finish_access(dev);
ret = nv50_fifo_channel_enable(dev, chan->id, false);
if (ret) {
NV_ERROR(dev, "error enabling ch%d: %d\n", chan->id, ret);
spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
nouveau_gpuobj_ref_del(dev, &chan->ramfc);
return ret;
}
dev_priv->engine.instmem.flush(dev);
nv50_fifo_channel_enable(dev, chan->id);
nv50_fifo_playlist_update(dev);
spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
return 0;
}
@ -328,11 +299,12 @@ nv50_fifo_destroy_context(struct nouveau_channel *chan)
/* This will ensure the channel is seen as disabled. */
chan->ramfc = NULL;
nv50_fifo_channel_disable(dev, chan->id, false);
nv50_fifo_channel_disable(dev, chan->id);
/* Dummy channel, also used on ch 127 */
if (chan->id == 0)
nv50_fifo_channel_disable(dev, 127, false);
nv50_fifo_channel_disable(dev, 127);
nv50_fifo_playlist_update(dev);
nouveau_gpuobj_ref_del(dev, &ramfc);
nouveau_gpuobj_ref_del(dev, &chan->cache);
@ -349,8 +321,6 @@ nv50_fifo_load_context(struct nouveau_channel *chan)
NV_DEBUG(dev, "ch%d\n", chan->id);
dev_priv->engine.instmem.prepare_access(dev, false);
nv_wr32(dev, 0x3330, nv_ro32(dev, ramfc, 0x00/4));
nv_wr32(dev, 0x3334, nv_ro32(dev, ramfc, 0x04/4));
nv_wr32(dev, 0x3240, nv_ro32(dev, ramfc, 0x08/4));
@ -396,7 +366,7 @@ nv50_fifo_load_context(struct nouveau_channel *chan)
nv_wr32(dev, NV03_PFIFO_CACHE1_GET, 0);
/* guessing that all the 0x34xx regs aren't on NV50 */
if (!IS_G80) {
if (dev_priv->chipset != 0x50) {
nv_wr32(dev, 0x340c, nv_ro32(dev, ramfc, 0x88/4));
nv_wr32(dev, 0x3400, nv_ro32(dev, ramfc, 0x8c/4));
nv_wr32(dev, 0x3404, nv_ro32(dev, ramfc, 0x90/4));
@ -404,8 +374,6 @@ nv50_fifo_load_context(struct nouveau_channel *chan)
nv_wr32(dev, 0x3410, nv_ro32(dev, ramfc, 0x98/4));
}
dev_priv->engine.instmem.finish_access(dev);
nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH1, chan->id | (1<<16));
return 0;
}
@ -434,8 +402,6 @@ nv50_fifo_unload_context(struct drm_device *dev)
ramfc = chan->ramfc->gpuobj;
cache = chan->cache->gpuobj;
dev_priv->engine.instmem.prepare_access(dev, true);
nv_wo32(dev, ramfc, 0x00/4, nv_rd32(dev, 0x3330));
nv_wo32(dev, ramfc, 0x04/4, nv_rd32(dev, 0x3334));
nv_wo32(dev, ramfc, 0x08/4, nv_rd32(dev, 0x3240));
@ -482,7 +448,7 @@ nv50_fifo_unload_context(struct drm_device *dev)
}
/* guessing that all the 0x34xx regs aren't on NV50 */
if (!IS_G80) {
if (dev_priv->chipset != 0x50) {
nv_wo32(dev, ramfc, 0x84/4, ptr >> 1);
nv_wo32(dev, ramfc, 0x88/4, nv_rd32(dev, 0x340c));
nv_wo32(dev, ramfc, 0x8c/4, nv_rd32(dev, 0x3400));
@ -491,7 +457,7 @@ nv50_fifo_unload_context(struct drm_device *dev)
nv_wo32(dev, ramfc, 0x98/4, nv_rd32(dev, 0x3410));
}
dev_priv->engine.instmem.finish_access(dev);
dev_priv->engine.instmem.flush(dev);
/*XXX: probably reload ch127 (NULL) state back too */
nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH1, 127);

View file

@ -74,3 +74,38 @@ nv50_gpio_set(struct drm_device *dev, enum dcb_gpio_tag tag, int state)
nv_wr32(dev, r, v);
return 0;
}
void
nv50_gpio_irq_enable(struct drm_device *dev, enum dcb_gpio_tag tag, bool on)
{
struct dcb_gpio_entry *gpio;
u32 reg, mask;
gpio = nouveau_bios_gpio_entry(dev, tag);
if (!gpio) {
NV_ERROR(dev, "gpio tag 0x%02x not found\n", tag);
return;
}
reg = gpio->line < 16 ? 0xe050 : 0xe070;
mask = 0x00010001 << (gpio->line & 0xf);
nv_wr32(dev, reg + 4, mask);
nv_mask(dev, reg + 0, mask, on ? mask : 0);
}
int
nv50_gpio_init(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
/* disable, and ack any pending gpio interrupts */
nv_wr32(dev, 0xe050, 0x00000000);
nv_wr32(dev, 0xe054, 0xffffffff);
if (dev_priv->chipset >= 0x90) {
nv_wr32(dev, 0xe070, 0x00000000);
nv_wr32(dev, 0xe074, 0xffffffff);
}
return 0;
}

View file

@ -30,8 +30,6 @@
#include "nouveau_grctx.h"
#define IS_G80 ((dev_priv->chipset & 0xf0) == 0x50)
static void
nv50_graph_init_reset(struct drm_device *dev)
{
@ -103,37 +101,33 @@ static int
nv50_graph_init_ctxctl(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_grctx ctx = {};
uint32_t *cp;
int i;
NV_DEBUG(dev, "\n");
if (nouveau_ctxfw) {
nouveau_grctx_prog_load(dev);
dev_priv->engine.graph.grctx_size = 0x70000;
cp = kmalloc(512 * 4, GFP_KERNEL);
if (!cp) {
NV_ERROR(dev, "failed to allocate ctxprog\n");
dev_priv->engine.graph.accel_blocked = true;
return 0;
}
if (!dev_priv->engine.graph.ctxprog) {
struct nouveau_grctx ctx = {};
uint32_t *cp = kmalloc(512 * 4, GFP_KERNEL);
int i;
if (!cp) {
NV_ERROR(dev, "Couldn't alloc ctxprog! Disabling acceleration.\n");
dev_priv->engine.graph.accel_blocked = true;
return 0;
}
ctx.dev = dev;
ctx.mode = NOUVEAU_GRCTX_PROG;
ctx.data = cp;
ctx.ctxprog_max = 512;
if (!nv50_grctx_init(&ctx)) {
dev_priv->engine.graph.grctx_size = ctx.ctxvals_pos * 4;
nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_INDEX, 0);
for (i = 0; i < ctx.ctxprog_len; i++)
nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_DATA, cp[i]);
} else {
dev_priv->engine.graph.accel_blocked = true;
}
kfree(cp);
ctx.dev = dev;
ctx.mode = NOUVEAU_GRCTX_PROG;
ctx.data = cp;
ctx.ctxprog_max = 512;
if (!nv50_grctx_init(&ctx)) {
dev_priv->engine.graph.grctx_size = ctx.ctxvals_pos * 4;
nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_INDEX, 0);
for (i = 0; i < ctx.ctxprog_len; i++)
nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_DATA, cp[i]);
} else {
dev_priv->engine.graph.accel_blocked = true;
}
kfree(cp);
nv_wr32(dev, 0x400320, 4);
nv_wr32(dev, NV40_PGRAPH_CTXCTL_CUR, 0);
@ -164,7 +158,6 @@ void
nv50_graph_takedown(struct drm_device *dev)
{
NV_DEBUG(dev, "\n");
nouveau_grctx_fini(dev);
}
void
@ -212,8 +205,9 @@ nv50_graph_create_context(struct nouveau_channel *chan)
struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_gpuobj *ramin = chan->ramin->gpuobj;
struct nouveau_gpuobj *ctx;
struct nouveau_gpuobj *obj;
struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
struct nouveau_grctx ctx = {};
int hdr, ret;
NV_DEBUG(dev, "ch%d\n", chan->id);
@ -223,10 +217,9 @@ nv50_graph_create_context(struct nouveau_channel *chan)
NVOBJ_FLAG_ZERO_FREE, &chan->ramin_grctx);
if (ret)
return ret;
ctx = chan->ramin_grctx->gpuobj;
obj = chan->ramin_grctx->gpuobj;
hdr = IS_G80 ? 0x200 : 0x20;
dev_priv->engine.instmem.prepare_access(dev, true);
hdr = (dev_priv->chipset == 0x50) ? 0x200 : 0x20;
nv_wo32(dev, ramin, (hdr + 0x00)/4, 0x00190002);
nv_wo32(dev, ramin, (hdr + 0x04)/4, chan->ramin_grctx->instance +
pgraph->grctx_size - 1);
@ -234,21 +227,15 @@ nv50_graph_create_context(struct nouveau_channel *chan)
nv_wo32(dev, ramin, (hdr + 0x0c)/4, 0);
nv_wo32(dev, ramin, (hdr + 0x10)/4, 0);
nv_wo32(dev, ramin, (hdr + 0x14)/4, 0x00010000);
dev_priv->engine.instmem.finish_access(dev);
dev_priv->engine.instmem.prepare_access(dev, true);
if (!pgraph->ctxprog) {
struct nouveau_grctx ctx = {};
ctx.dev = chan->dev;
ctx.mode = NOUVEAU_GRCTX_VALS;
ctx.data = chan->ramin_grctx->gpuobj;
nv50_grctx_init(&ctx);
} else {
nouveau_grctx_vals_load(dev, ctx);
}
nv_wo32(dev, ctx, 0x00000/4, chan->ramin->instance >> 12);
dev_priv->engine.instmem.finish_access(dev);
ctx.dev = chan->dev;
ctx.mode = NOUVEAU_GRCTX_VALS;
ctx.data = obj;
nv50_grctx_init(&ctx);
nv_wo32(dev, obj, 0x00000/4, chan->ramin->instance >> 12);
dev_priv->engine.instmem.flush(dev);
return 0;
}
@ -257,17 +244,16 @@ nv50_graph_destroy_context(struct nouveau_channel *chan)
{
struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
int i, hdr = IS_G80 ? 0x200 : 0x20;
int i, hdr = (dev_priv->chipset == 0x50) ? 0x200 : 0x20;
NV_DEBUG(dev, "ch%d\n", chan->id);
if (!chan->ramin || !chan->ramin->gpuobj)
return;
dev_priv->engine.instmem.prepare_access(dev, true);
for (i = hdr; i < hdr + 24; i += 4)
nv_wo32(dev, chan->ramin->gpuobj, i/4, 0);
dev_priv->engine.instmem.finish_access(dev);
dev_priv->engine.instmem.flush(dev);
nouveau_gpuobj_ref_del(dev, &chan->ramin_grctx);
}

View file

@ -35,8 +35,6 @@ struct nv50_instmem_priv {
struct nouveau_gpuobj_ref *pramin_pt;
struct nouveau_gpuobj_ref *pramin_bar;
struct nouveau_gpuobj_ref *fb_bar;
bool last_access_wr;
};
#define NV50_INSTMEM_PAGE_SHIFT 12
@ -147,7 +145,7 @@ nv50_instmem_init(struct drm_device *dev)
if (ret)
return ret;
if (nouveau_mem_init_heap(&chan->ramin_heap, c_base, c_size - c_base))
if (drm_mm_init(&chan->ramin_heap, c_base, c_size - c_base))
return -ENOMEM;
/* RAMFC + zero channel's PRAMIN up to start of VM pagedir */
@ -262,23 +260,18 @@ nv50_instmem_init(struct drm_device *dev)
/* Assume that praying isn't enough, check that we can re-read the
* entire fake channel back from the PRAMIN BAR */
dev_priv->engine.instmem.prepare_access(dev, false);
for (i = 0; i < c_size; i += 4) {
if (nv_rd32(dev, NV_RAMIN + i) != nv_ri32(dev, i)) {
NV_ERROR(dev, "Error reading back PRAMIN at 0x%08x\n",
i);
dev_priv->engine.instmem.finish_access(dev);
return -EINVAL;
}
}
dev_priv->engine.instmem.finish_access(dev);
nv_wr32(dev, NV50_PUNK_BAR0_PRAMIN, save_nv001700);
/* Global PRAMIN heap */
if (nouveau_mem_init_heap(&dev_priv->ramin_heap,
c_size, dev_priv->ramin_size - c_size)) {
dev_priv->ramin_heap = NULL;
if (drm_mm_init(&dev_priv->ramin_heap, c_size, dev_priv->ramin_size - c_size)) {
NV_ERROR(dev, "Failed to init RAMIN heap\n");
}
@ -321,7 +314,7 @@ nv50_instmem_takedown(struct drm_device *dev)
nouveau_gpuobj_del(dev, &chan->vm_pd);
nouveau_gpuobj_ref_del(dev, &chan->ramfc);
nouveau_gpuobj_ref_del(dev, &chan->ramin);
nouveau_mem_takedown(&chan->ramin_heap);
drm_mm_takedown(&chan->ramin_heap);
dev_priv->fifos[0] = dev_priv->fifos[127] = NULL;
kfree(chan);
@ -436,14 +429,14 @@ nv50_instmem_bind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj)
if (!gpuobj->im_backing || !gpuobj->im_pramin || gpuobj->im_bound)
return -EINVAL;
NV_DEBUG(dev, "st=0x%0llx sz=0x%0llx\n",
NV_DEBUG(dev, "st=0x%lx sz=0x%lx\n",
gpuobj->im_pramin->start, gpuobj->im_pramin->size);
pte = (gpuobj->im_pramin->start >> 12) << 1;
pte_end = ((gpuobj->im_pramin->size >> 12) << 1) + pte;
vram = gpuobj->im_backing_start;
NV_DEBUG(dev, "pramin=0x%llx, pte=%d, pte_end=%d\n",
NV_DEBUG(dev, "pramin=0x%lx, pte=%d, pte_end=%d\n",
gpuobj->im_pramin->start, pte, pte_end);
NV_DEBUG(dev, "first vram page: 0x%08x\n", gpuobj->im_backing_start);
@ -453,27 +446,15 @@ nv50_instmem_bind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj)
vram |= 0x30;
}
dev_priv->engine.instmem.prepare_access(dev, true);
while (pte < pte_end) {
nv_wo32(dev, pramin_pt, pte++, lower_32_bits(vram));
nv_wo32(dev, pramin_pt, pte++, upper_32_bits(vram));
vram += NV50_INSTMEM_PAGE_SIZE;
}
dev_priv->engine.instmem.finish_access(dev);
dev_priv->engine.instmem.flush(dev);
nv_wr32(dev, 0x100c80, 0x00040001);
if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) {
NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (1)\n");
NV_ERROR(dev, "0x100c80 = 0x%08x\n", nv_rd32(dev, 0x100c80));
return -EBUSY;
}
nv_wr32(dev, 0x100c80, 0x00060001);
if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) {
NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n");
NV_ERROR(dev, "0x100c80 = 0x%08x\n", nv_rd32(dev, 0x100c80));
return -EBUSY;
}
nv50_vm_flush(dev, 4);
nv50_vm_flush(dev, 6);
gpuobj->im_bound = 1;
return 0;
@ -492,36 +473,37 @@ nv50_instmem_unbind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj)
pte = (gpuobj->im_pramin->start >> 12) << 1;
pte_end = ((gpuobj->im_pramin->size >> 12) << 1) + pte;
dev_priv->engine.instmem.prepare_access(dev, true);
while (pte < pte_end) {
nv_wo32(dev, priv->pramin_pt->gpuobj, pte++, 0x00000000);
nv_wo32(dev, priv->pramin_pt->gpuobj, pte++, 0x00000000);
}
dev_priv->engine.instmem.finish_access(dev);
dev_priv->engine.instmem.flush(dev);
gpuobj->im_bound = 0;
return 0;
}
void
nv50_instmem_prepare_access(struct drm_device *dev, bool write)
nv50_instmem_flush(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nv50_instmem_priv *priv = dev_priv->engine.instmem.priv;
priv->last_access_wr = write;
nv_wr32(dev, 0x00330c, 0x00000001);
if (!nv_wait(0x00330c, 0x00000002, 0x00000000))
NV_ERROR(dev, "PRAMIN flush timeout\n");
}
void
nv50_instmem_finish_access(struct drm_device *dev)
nv84_instmem_flush(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nv50_instmem_priv *priv = dev_priv->engine.instmem.priv;
if (priv->last_access_wr) {
nv_wr32(dev, 0x070000, 0x00000001);
if (!nv_wait(0x070000, 0x00000001, 0x00000000))
NV_ERROR(dev, "PRAMIN flush timeout\n");
}
nv_wr32(dev, 0x070000, 0x00000001);
if (!nv_wait(0x070000, 0x00000002, 0x00000000))
NV_ERROR(dev, "PRAMIN flush timeout\n");
}
void
nv50_vm_flush(struct drm_device *dev, int engine)
{
nv_wr32(dev, 0x100c80, (engine << 16) | 1);
if (!nv_wait(0x100c80, 0x00000001, 0x00000000))
NV_ERROR(dev, "vm flush timeout: engine %d\n", engine);
}

View file

@ -37,52 +37,32 @@
#include "nv50_display.h"
static void
nv50_sor_disconnect(struct nouveau_encoder *nv_encoder)
nv50_sor_disconnect(struct drm_encoder *encoder)
{
struct drm_device *dev = to_drm_encoder(nv_encoder)->dev;
struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
struct drm_device *dev = encoder->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_channel *evo = dev_priv->evo;
int ret;
if (!nv_encoder->crtc)
return;
nv50_crtc_blank(nouveau_crtc(nv_encoder->crtc), true);
NV_DEBUG_KMS(dev, "Disconnecting SOR %d\n", nv_encoder->or);
ret = RING_SPACE(evo, 2);
ret = RING_SPACE(evo, 4);
if (ret) {
NV_ERROR(dev, "no space while disconnecting SOR\n");
return;
}
BEGIN_RING(evo, 0, NV50_EVO_SOR(nv_encoder->or, MODE_CTRL), 1);
OUT_RING(evo, 0);
}
OUT_RING (evo, 0);
BEGIN_RING(evo, 0, NV50_EVO_UPDATE, 1);
OUT_RING (evo, 0);
static void
nv50_sor_dp_link_train(struct drm_encoder *encoder)
{
struct drm_device *dev = encoder->dev;
struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
struct bit_displayport_encoder_table *dpe;
int dpe_headerlen;
dpe = nouveau_bios_dp_table(dev, nv_encoder->dcb, &dpe_headerlen);
if (!dpe) {
NV_ERROR(dev, "SOR-%d: no DP encoder table!\n", nv_encoder->or);
return;
}
if (dpe->script0) {
NV_DEBUG_KMS(dev, "SOR-%d: running DP script 0\n", nv_encoder->or);
nouveau_bios_run_init_table(dev, le16_to_cpu(dpe->script0),
nv_encoder->dcb);
}
if (!nouveau_dp_link_train(encoder))
NV_ERROR(dev, "SOR-%d: link training failed\n", nv_encoder->or);
if (dpe->script1) {
NV_DEBUG_KMS(dev, "SOR-%d: running DP script 1\n", nv_encoder->or);
nouveau_bios_run_init_table(dev, le16_to_cpu(dpe->script1),
nv_encoder->dcb);
}
nv_encoder->crtc = NULL;
nv_encoder->last_dpms = DRM_MODE_DPMS_OFF;
}
static void
@ -94,14 +74,16 @@ nv50_sor_dpms(struct drm_encoder *encoder, int mode)
uint32_t val;
int or = nv_encoder->or;
NV_DEBUG_KMS(dev, "or %d mode %d\n", or, mode);
NV_DEBUG_KMS(dev, "or %d type %d mode %d\n", or, nv_encoder->dcb->type, mode);
nv_encoder->last_dpms = mode;
list_for_each_entry(enc, &dev->mode_config.encoder_list, head) {
struct nouveau_encoder *nvenc = nouveau_encoder(enc);
if (nvenc == nv_encoder ||
nvenc->disconnect != nv50_sor_disconnect ||
(nvenc->dcb->type != OUTPUT_TMDS &&
nvenc->dcb->type != OUTPUT_LVDS &&
nvenc->dcb->type != OUTPUT_DP) ||
nvenc->dcb->or != nv_encoder->dcb->or)
continue;
@ -133,8 +115,22 @@ nv50_sor_dpms(struct drm_encoder *encoder, int mode)
nv_rd32(dev, NV50_PDISPLAY_SOR_DPMS_STATE(or)));
}
if (nv_encoder->dcb->type == OUTPUT_DP && mode == DRM_MODE_DPMS_ON)
nv50_sor_dp_link_train(encoder);
if (nv_encoder->dcb->type == OUTPUT_DP) {
struct nouveau_i2c_chan *auxch;
auxch = nouveau_i2c_find(dev, nv_encoder->dcb->i2c_index);
if (!auxch)
return;
if (mode == DRM_MODE_DPMS_ON) {
u8 status = DP_SET_POWER_D0;
nouveau_dp_auxch(auxch, 8, DP_SET_POWER, &status, 1);
nouveau_dp_link_train(encoder);
} else {
u8 status = DP_SET_POWER_D3;
nouveau_dp_auxch(auxch, 8, DP_SET_POWER, &status, 1);
}
}
}
static void
@ -196,7 +192,8 @@ nv50_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
uint32_t mode_ctl = 0;
int ret;
NV_DEBUG_KMS(dev, "or %d\n", nv_encoder->or);
NV_DEBUG_KMS(dev, "or %d type %d -> crtc %d\n",
nv_encoder->or, nv_encoder->dcb->type, crtc->index);
nv50_sor_dpms(encoder, DRM_MODE_DPMS_ON);
@ -239,6 +236,14 @@ nv50_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
}
BEGIN_RING(evo, 0, NV50_EVO_SOR(nv_encoder->or, MODE_CTRL), 1);
OUT_RING(evo, mode_ctl);
nv_encoder->crtc = encoder->crtc;
}
static struct drm_crtc *
nv50_sor_crtc_get(struct drm_encoder *encoder)
{
return nouveau_encoder(encoder)->crtc;
}
static const struct drm_encoder_helper_funcs nv50_sor_helper_funcs = {
@ -249,7 +254,9 @@ static const struct drm_encoder_helper_funcs nv50_sor_helper_funcs = {
.prepare = nv50_sor_prepare,
.commit = nv50_sor_commit,
.mode_set = nv50_sor_mode_set,
.detect = NULL
.get_crtc = nv50_sor_crtc_get,
.detect = NULL,
.disable = nv50_sor_disconnect
};
static void
@ -272,32 +279,22 @@ static const struct drm_encoder_funcs nv50_sor_encoder_funcs = {
};
int
nv50_sor_create(struct drm_device *dev, struct dcb_entry *entry)
nv50_sor_create(struct drm_connector *connector, struct dcb_entry *entry)
{
struct nouveau_encoder *nv_encoder = NULL;
struct drm_device *dev = connector->dev;
struct drm_encoder *encoder;
bool dum;
int type;
NV_DEBUG_KMS(dev, "\n");
switch (entry->type) {
case OUTPUT_TMDS:
NV_INFO(dev, "Detected a TMDS output\n");
case OUTPUT_DP:
type = DRM_MODE_ENCODER_TMDS;
break;
case OUTPUT_LVDS:
NV_INFO(dev, "Detected a LVDS output\n");
type = DRM_MODE_ENCODER_LVDS;
if (nouveau_bios_parse_lvds_table(dev, 0, &dum, &dum)) {
NV_ERROR(dev, "Failed parsing LVDS table\n");
return -EINVAL;
}
break;
case OUTPUT_DP:
NV_INFO(dev, "Detected a DP output\n");
type = DRM_MODE_ENCODER_TMDS;
break;
default:
return -EINVAL;
@ -310,8 +307,7 @@ nv50_sor_create(struct drm_device *dev, struct dcb_entry *entry)
nv_encoder->dcb = entry;
nv_encoder->or = ffs(entry->or) - 1;
nv_encoder->disconnect = nv50_sor_disconnect;
nv_encoder->last_dpms = DRM_MODE_DPMS_OFF;
drm_encoder_init(dev, encoder, &nv50_sor_encoder_funcs, type);
drm_encoder_helper_add(encoder, &nv50_sor_helper_funcs);
@ -342,5 +338,6 @@ nv50_sor_create(struct drm_device *dev, struct dcb_entry *entry)
nv_encoder->dp.mc_unknown = 5;
}
drm_mode_connector_attach_encoder(connector, encoder);
return 0;
}

View file

@ -147,28 +147,6 @@
# define NV_VIO_GX_DONT_CARE_INDEX 0x07
# define NV_VIO_GX_BIT_MASK_INDEX 0x08
#define NV_PFB_BOOT_0 0x00100000
#define NV_PFB_CFG0 0x00100200
#define NV_PFB_CFG1 0x00100204
#define NV_PFB_CSTATUS 0x0010020C
#define NV_PFB_REFCTRL 0x00100210
# define NV_PFB_REFCTRL_VALID_1 (1 << 31)
#define NV_PFB_PAD 0x0010021C
# define NV_PFB_PAD_CKE_NORMAL (1 << 0)
#define NV_PFB_TILE_NV10 0x00100240
#define NV_PFB_TILE_SIZE_NV10 0x00100244
#define NV_PFB_REF 0x001002D0
# define NV_PFB_REF_CMD_REFRESH (1 << 0)
#define NV_PFB_PRE 0x001002D4
# define NV_PFB_PRE_CMD_PRECHARGE (1 << 0)
#define NV_PFB_CLOSE_PAGE2 0x0010033C
#define NV_PFB_TILE_NV40 0x00100600
#define NV_PFB_TILE_SIZE_NV40 0x00100604
#define NV_PEXTDEV_BOOT_0 0x00101000
# define NV_PEXTDEV_BOOT_0_STRAP_FP_IFACE_12BIT (8 << 12)
#define NV_PEXTDEV_BOOT_3 0x0010100c
#define NV_PCRTC_INTR_0 0x00600100
# define NV_PCRTC_INTR_0_VBLANK (1 << 0)
#define NV_PCRTC_INTR_EN_0 0x00600140