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

* 'nouveau/for-airlied' of /ssd/git/drm-nouveau-next: (27 commits)
  drm/nvc0: fix typo in PRAMIN flush
  drm/nouveau: Fix DCB TMDS config parsing.
  drm/nv30: Fix PFB init for nv31.
  drm/nv04: Fix up SGRAM density detection.
  drm/i2c/ch7006: Don't use POWER_LEVEL_FULL_POWER_OFF on early chip versions.
  drm/nouveau: Init dcb->or on cards that have no usable DCB table.
  drm/nouveau: reduce severity of some "error" messages
  drm/nvc0: backup bar3 channel on suspend
  drm/nouveau: implement init table opcodex 0x5e and 0x9a
  drm/nouveau: implement init table op 0x57, INIT_LTIME
  drm/nvc0: implement crtc pll setting
  drm/nvc0: fix evo dma object so we display something
  drm/nvc0: rudimentary instmem support
  drm/nvc0: implement memory detection
  drm/nvc0: allow INIT_GPIO
  drm/nvc0: starting point for GF100 support, everything stubbed
  drm/nv30: Workaround dual TMDS brain damage.
  drm/nouveau: No need to set slave TV encoder configs explicitly.
  drm/nv17-nv4x: Attempt to init some external TMDS transmitters.
  drm/nv10: Fix up switching of NV10TCL_DMA_VTXBUF.
  ...
This commit is contained in:
Dave Airlie 2010-08-10 08:17:50 +10:00
commit c3b6ef8633
30 changed files with 1116 additions and 199 deletions

View File

@ -470,6 +470,7 @@ static int ch7006_encoder_init(struct i2c_client *client,
priv->hmargin = 50; priv->hmargin = 50;
priv->vmargin = 50; priv->vmargin = 50;
priv->last_dpms = -1; priv->last_dpms = -1;
priv->chip_version = ch7006_read(client, CH7006_VERSION_ID);
if (ch7006_tv_norm) { if (ch7006_tv_norm) {
for (i = 0; i < NUM_TV_NORMS; i++) { for (i = 0; i < NUM_TV_NORMS; i++) {

View File

@ -316,7 +316,10 @@ void ch7006_setup_power_state(struct drm_encoder *encoder)
} }
} else { } else {
if (priv->chip_version >= 0x20)
*power |= bitfs(CH7006_POWER_LEVEL, FULL_POWER_OFF); *power |= bitfs(CH7006_POWER_LEVEL, FULL_POWER_OFF);
else
*power |= bitfs(CH7006_POWER_LEVEL, POWER_OFF);
} }
} }

View File

@ -95,6 +95,7 @@ struct ch7006_priv {
int flicker; int flicker;
int scale; int scale;
int chip_version;
int last_dpms; int last_dpms;
}; };

View File

@ -12,12 +12,12 @@ nouveau-y := nouveau_drv.o nouveau_state.o nouveau_channel.o nouveau_mem.o \
nouveau_dp.o \ nouveau_dp.o \
nv04_timer.o \ nv04_timer.o \
nv04_mc.o nv40_mc.o nv50_mc.o \ nv04_mc.o nv40_mc.o nv50_mc.o \
nv04_fb.o nv10_fb.o nv30_fb.o nv40_fb.o nv50_fb.o \ nv04_fb.o nv10_fb.o nv30_fb.o nv40_fb.o nv50_fb.o nvc0_fb.o \
nv04_fifo.o nv10_fifo.o nv40_fifo.o nv50_fifo.o \ nv04_fifo.o nv10_fifo.o nv40_fifo.o nv50_fifo.o nvc0_fifo.o \
nv04_graph.o nv10_graph.o nv20_graph.o \ nv04_graph.o nv10_graph.o nv20_graph.o \
nv40_graph.o nv50_graph.o \ nv40_graph.o nv50_graph.o nvc0_graph.o \
nv40_grctx.o nv50_grctx.o \ nv40_grctx.o nv50_grctx.o \
nv04_instmem.o nv50_instmem.o \ nv04_instmem.o nv50_instmem.o nvc0_instmem.o \
nv50_crtc.o nv50_dac.o nv50_sor.o \ nv50_crtc.o nv50_dac.o nv50_sor.o \
nv50_cursor.o nv50_display.o nv50_fbcon.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_dac.o nv04_dfp.o nv04_tv.o nv17_tv.o nv17_tv_modes.o \

View File

@ -1927,6 +1927,31 @@ init_condition_time(struct nvbios *bios, uint16_t offset,
return 3; return 3;
} }
static int
init_ltime(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
{
/*
* INIT_LTIME opcode: 0x57 ('V')
*
* offset (8 bit): opcode
* offset + 1 (16 bit): time
*
* Sleep for "time" miliseconds.
*/
unsigned time = ROM16(bios->data[offset + 1]);
if (!iexec->execute)
return 3;
BIOSLOG(bios, "0x%04X: Sleeping for 0x%04X miliseconds\n",
offset, time);
msleep(time);
return 3;
}
static int static int
init_zm_reg_sequence(struct nvbios *bios, uint16_t offset, init_zm_reg_sequence(struct nvbios *bios, uint16_t offset,
struct init_exec *iexec) struct init_exec *iexec)
@ -1994,6 +2019,64 @@ init_sub_direct(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
return 3; return 3;
} }
static int
init_i2c_if(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
{
/*
* INIT_I2C_IF opcode: 0x5E ('^')
*
* offset (8 bit): opcode
* offset + 1 (8 bit): DCB I2C table entry index
* offset + 2 (8 bit): I2C slave address
* offset + 3 (8 bit): I2C register
* offset + 4 (8 bit): mask
* offset + 5 (8 bit): data
*
* Read the register given by "I2C register" on the device addressed
* by "I2C slave address" on the I2C bus given by "DCB I2C table
* entry index". Compare the result AND "mask" to "data".
* If they're not equal, skip subsequent opcodes until condition is
* inverted (INIT_NOT), or we hit INIT_RESUME
*/
uint8_t i2c_index = bios->data[offset + 1];
uint8_t i2c_address = bios->data[offset + 2] >> 1;
uint8_t reg = bios->data[offset + 3];
uint8_t mask = bios->data[offset + 4];
uint8_t data = bios->data[offset + 5];
struct nouveau_i2c_chan *chan;
union i2c_smbus_data val;
int ret;
/* no execute check by design */
BIOSLOG(bios, "0x%04X: DCBI2CIndex: 0x%02X, I2CAddress: 0x%02X\n",
offset, i2c_index, i2c_address);
chan = init_i2c_device_find(bios->dev, i2c_index);
if (!chan)
return -ENODEV;
ret = i2c_smbus_xfer(&chan->adapter, i2c_address, 0,
I2C_SMBUS_READ, reg,
I2C_SMBUS_BYTE_DATA, &val);
if (ret < 0) {
BIOSLOG(bios, "0x%04X: I2CReg: 0x%02X, Value: [no device], "
"Mask: 0x%02X, Data: 0x%02X\n",
offset, reg, mask, data);
iexec->execute = 0;
return 6;
}
BIOSLOG(bios, "0x%04X: I2CReg: 0x%02X, Value: 0x%02X, "
"Mask: 0x%02X, Data: 0x%02X\n",
offset, reg, val.byte, mask, data);
iexec->execute = ((val.byte & mask) == data);
return 6;
}
static int static int
init_copy_nv_reg(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) init_copy_nv_reg(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
{ {
@ -2083,9 +2166,10 @@ peek_fb(struct drm_device *dev, struct io_mapping *fb,
uint32_t val = 0; uint32_t val = 0;
if (off < pci_resource_len(dev->pdev, 1)) { if (off < pci_resource_len(dev->pdev, 1)) {
uint32_t __iomem *p = io_mapping_map_atomic_wc(fb, off, KM_USER0); uint32_t __iomem *p =
io_mapping_map_atomic_wc(fb, off & PAGE_MASK, KM_USER0);
val = ioread32(p); val = ioread32(p + (off & ~PAGE_MASK));
io_mapping_unmap_atomic(p, KM_USER0); io_mapping_unmap_atomic(p, KM_USER0);
} }
@ -2098,9 +2182,10 @@ poke_fb(struct drm_device *dev, struct io_mapping *fb,
uint32_t off, uint32_t val) uint32_t off, uint32_t val)
{ {
if (off < pci_resource_len(dev->pdev, 1)) { if (off < pci_resource_len(dev->pdev, 1)) {
uint32_t __iomem *p = io_mapping_map_atomic_wc(fb, off, KM_USER0); uint32_t __iomem *p =
io_mapping_map_atomic_wc(fb, off & PAGE_MASK, KM_USER0);
iowrite32(val, p); iowrite32(val, p + (off & ~PAGE_MASK));
wmb(); wmb();
io_mapping_unmap_atomic(p, KM_USER0); io_mapping_unmap_atomic(p, KM_USER0);
@ -2165,7 +2250,7 @@ nv04_init_compute_mem(struct nvbios *bios)
NV04_PFB_BOOT_0_RAM_AMOUNT, NV04_PFB_BOOT_0_RAM_AMOUNT,
NV04_PFB_BOOT_0_RAM_AMOUNT_4MB); NV04_PFB_BOOT_0_RAM_AMOUNT_4MB);
} else if (peek_fb(dev, fb, 0) == patt) { } else if (peek_fb(dev, fb, 0) != patt) {
if (read_back_fb(dev, fb, 0x800000, patt)) if (read_back_fb(dev, fb, 0x800000, patt))
bios_md32(bios, NV04_PFB_BOOT_0, bios_md32(bios, NV04_PFB_BOOT_0,
NV04_PFB_BOOT_0_RAM_AMOUNT, NV04_PFB_BOOT_0_RAM_AMOUNT,
@ -2593,7 +2678,7 @@ init_configure_preinit(struct nvbios *bios, uint16_t offset,
/* no iexec->execute check by design */ /* no iexec->execute check by design */
uint32_t straps = bios_rd32(bios, NV_PEXTDEV_BOOT_0); uint32_t straps = bios_rd32(bios, NV_PEXTDEV_BOOT_0);
uint8_t cr3c = ((straps << 2) & 0xf0) | (straps & (1 << 6)); uint8_t cr3c = ((straps << 2) & 0xf0) | (straps & 0x40) >> 6;
if (bios->major_version > 2) if (bios->major_version > 2)
return 0; return 0;
@ -3140,7 +3225,7 @@ init_gpio(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
const uint32_t nv50_gpio_ctl[2] = { 0xe100, 0xe28c }; const uint32_t nv50_gpio_ctl[2] = { 0xe100, 0xe28c };
int i; int i;
if (dev_priv->card_type != NV_50) { if (dev_priv->card_type < NV_50) {
NV_ERROR(bios->dev, "INIT_GPIO on unsupported chipset\n"); NV_ERROR(bios->dev, "INIT_GPIO on unsupported chipset\n");
return 1; return 1;
} }
@ -3490,6 +3575,69 @@ init_zm_auxch(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
return len; return len;
} }
static int
init_i2c_long_if(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
{
/*
* INIT_I2C_LONG_IF opcode: 0x9A ('')
*
* offset (8 bit): opcode
* offset + 1 (8 bit): DCB I2C table entry index
* offset + 2 (8 bit): I2C slave address
* offset + 3 (16 bit): I2C register
* offset + 5 (8 bit): mask
* offset + 6 (8 bit): data
*
* Read the register given by "I2C register" on the device addressed
* by "I2C slave address" on the I2C bus given by "DCB I2C table
* entry index". Compare the result AND "mask" to "data".
* If they're not equal, skip subsequent opcodes until condition is
* inverted (INIT_NOT), or we hit INIT_RESUME
*/
uint8_t i2c_index = bios->data[offset + 1];
uint8_t i2c_address = bios->data[offset + 2] >> 1;
uint8_t reglo = bios->data[offset + 3];
uint8_t reghi = bios->data[offset + 4];
uint8_t mask = bios->data[offset + 5];
uint8_t data = bios->data[offset + 6];
struct nouveau_i2c_chan *chan;
uint8_t buf0[2] = { reghi, reglo };
uint8_t buf1[1];
struct i2c_msg msg[2] = {
{ i2c_address, 0, 1, buf0 },
{ i2c_address, I2C_M_RD, 1, buf1 },
};
int ret;
/* no execute check by design */
BIOSLOG(bios, "0x%04X: DCBI2CIndex: 0x%02X, I2CAddress: 0x%02X\n",
offset, i2c_index, i2c_address);
chan = init_i2c_device_find(bios->dev, i2c_index);
if (!chan)
return -ENODEV;
ret = i2c_transfer(&chan->adapter, msg, 2);
if (ret < 0) {
BIOSLOG(bios, "0x%04X: I2CReg: 0x%02X:0x%02X, Value: [no device], "
"Mask: 0x%02X, Data: 0x%02X\n",
offset, reghi, reglo, mask, data);
iexec->execute = 0;
return 7;
}
BIOSLOG(bios, "0x%04X: I2CReg: 0x%02X:0x%02X, Value: 0x%02X, "
"Mask: 0x%02X, Data: 0x%02X\n",
offset, reghi, reglo, buf1[0], mask, data);
iexec->execute = ((buf1[0] & mask) == data);
return 7;
}
static struct init_tbl_entry itbl_entry[] = { static struct init_tbl_entry itbl_entry[] = {
/* command name , id , length , offset , mult , command handler */ /* command name , id , length , offset , mult , command handler */
/* INIT_PROG (0x31, 15, 10, 4) removed due to no example of use */ /* INIT_PROG (0x31, 15, 10, 4) removed due to no example of use */
@ -3516,9 +3664,11 @@ static struct init_tbl_entry itbl_entry[] = {
{ "INIT_ZM_CR" , 0x53, init_zm_cr }, { "INIT_ZM_CR" , 0x53, init_zm_cr },
{ "INIT_ZM_CR_GROUP" , 0x54, init_zm_cr_group }, { "INIT_ZM_CR_GROUP" , 0x54, init_zm_cr_group },
{ "INIT_CONDITION_TIME" , 0x56, init_condition_time }, { "INIT_CONDITION_TIME" , 0x56, init_condition_time },
{ "INIT_LTIME" , 0x57, init_ltime },
{ "INIT_ZM_REG_SEQUENCE" , 0x58, init_zm_reg_sequence }, { "INIT_ZM_REG_SEQUENCE" , 0x58, init_zm_reg_sequence },
/* INIT_INDIRECT_REG (0x5A, 7, 0, 0) removed due to no example of use */ /* INIT_INDIRECT_REG (0x5A, 7, 0, 0) removed due to no example of use */
{ "INIT_SUB_DIRECT" , 0x5B, init_sub_direct }, { "INIT_SUB_DIRECT" , 0x5B, init_sub_direct },
{ "INIT_I2C_IF" , 0x5E, init_i2c_if },
{ "INIT_COPY_NV_REG" , 0x5F, init_copy_nv_reg }, { "INIT_COPY_NV_REG" , 0x5F, init_copy_nv_reg },
{ "INIT_ZM_INDEX_IO" , 0x62, init_zm_index_io }, { "INIT_ZM_INDEX_IO" , 0x62, init_zm_index_io },
{ "INIT_COMPUTE_MEM" , 0x63, init_compute_mem }, { "INIT_COMPUTE_MEM" , 0x63, init_compute_mem },
@ -3552,6 +3702,7 @@ static struct init_tbl_entry itbl_entry[] = {
{ "INIT_97" , 0x97, init_97 }, { "INIT_97" , 0x97, init_97 },
{ "INIT_AUXCH" , 0x98, init_auxch }, { "INIT_AUXCH" , 0x98, init_auxch },
{ "INIT_ZM_AUXCH" , 0x99, init_zm_auxch }, { "INIT_ZM_AUXCH" , 0x99, init_zm_auxch },
{ "INIT_I2C_LONG_IF" , 0x9A, init_i2c_long_if },
{ NULL , 0 , NULL } { NULL , 0 , NULL }
}; };
@ -4410,7 +4561,7 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent,
bios->display.script_table_ptr, bios->display.script_table_ptr,
table[2], table[3], table[0] >= 0x21); table[2], table[3], table[0] >= 0x21);
if (!otable) { if (!otable) {
NV_ERROR(dev, "Couldn't find matching output script table\n"); NV_DEBUG_KMS(dev, "failed to match any output table\n");
return 1; return 1;
} }
@ -4467,7 +4618,7 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent,
if (script) if (script)
script = clkcmptable(bios, script, pxclk); script = clkcmptable(bios, script, pxclk);
if (!script) { if (!script) {
NV_ERROR(dev, "clock script 0 not found\n"); NV_DEBUG_KMS(dev, "clock script 0 not found\n");
return 1; return 1;
} }
@ -4826,7 +4977,7 @@ int get_pll_limits(struct drm_device *dev, uint32_t limit_match, struct pll_lims
pll_lim->min_p = record[12]; pll_lim->min_p = record[12];
pll_lim->max_p = record[13]; pll_lim->max_p = record[13];
/* where did this go to?? */ /* where did this go to?? */
if (limit_match == 0x00614100 || limit_match == 0x00614900) if ((entry[0] & 0xf0) == 0x80)
pll_lim->refclk = 27000; pll_lim->refclk = 27000;
else else
pll_lim->refclk = 100000; pll_lim->refclk = 100000;
@ -5852,7 +6003,7 @@ static void fabricate_vga_output(struct dcb_table *dcb, int i2c, int heads)
entry->i2c_index = i2c; entry->i2c_index = i2c;
entry->heads = heads; entry->heads = heads;
entry->location = DCB_LOC_ON_CHIP; entry->location = DCB_LOC_ON_CHIP;
/* "or" mostly unused in early gen crt modesetting, 0 is fine */ entry->or = 1;
} }
static void fabricate_dvi_i_output(struct dcb_table *dcb, bool twoHeads) static void fabricate_dvi_i_output(struct dcb_table *dcb, bool twoHeads)
@ -5980,7 +6131,13 @@ parse_dcb20_entry(struct drm_device *dev, struct dcb_table *dcb,
} }
break; break;
case OUTPUT_TMDS: case OUTPUT_TMDS:
if (dcb->version >= 0x40)
entry->tmdsconf.sor.link = (conf & 0x00000030) >> 4; entry->tmdsconf.sor.link = (conf & 0x00000030) >> 4;
else if (dcb->version >= 0x30)
entry->tmdsconf.slave_addr = (conf & 0x00000700) >> 8;
else if (dcb->version >= 0x22)
entry->tmdsconf.slave_addr = (conf & 0x00000070) >> 4;
break; break;
case 0xe: case 0xe:
/* weird g80 mobile type that "nv" treats as a terminator */ /* weird g80 mobile type that "nv" treats as a terminator */
@ -6270,6 +6427,19 @@ parse_dcb_table(struct drm_device *dev, struct nvbios *bios, bool twoHeads)
dcb->i2c_table = &bios->data[i2ctabptr]; dcb->i2c_table = &bios->data[i2ctabptr];
if (dcb->version >= 0x30) if (dcb->version >= 0x30)
dcb->i2c_default_indices = dcb->i2c_table[4]; dcb->i2c_default_indices = dcb->i2c_table[4];
/*
* Parse the "management" I2C bus, used for hardware
* monitoring and some external TMDS transmitters.
*/
if (dcb->version >= 0x22) {
int idx = (dcb->version >= 0x40 ?
dcb->i2c_default_indices & 0xf :
2);
read_dcb_i2c_entry(dev, dcb->version, dcb->i2c_table,
idx, &dcb->i2c[idx]);
}
} }
if (entries > DCB_MAX_NUM_ENTRIES) if (entries > DCB_MAX_NUM_ENTRIES)

View File

@ -131,6 +131,7 @@ struct dcb_entry {
} dpconf; } dpconf;
struct { struct {
struct sor_conf sor; struct sor_conf sor;
int slave_addr;
} tmdsconf; } tmdsconf;
}; };
bool i2c_upper_default; bool i2c_upper_default;

View File

@ -51,9 +51,6 @@ nouveau_bo_del_ttm(struct ttm_buffer_object *bo)
if (nvbo->tile) if (nvbo->tile)
nv10_mem_expire_tiling(dev, nvbo->tile, NULL); nv10_mem_expire_tiling(dev, nvbo->tile, NULL);
spin_lock(&dev_priv->ttm.bo_list_lock);
list_del(&nvbo->head);
spin_unlock(&dev_priv->ttm.bo_list_lock);
kfree(nvbo); kfree(nvbo);
} }
@ -166,9 +163,6 @@ nouveau_bo_new(struct drm_device *dev, struct nouveau_channel *chan,
} }
nvbo->channel = NULL; nvbo->channel = NULL;
spin_lock(&dev_priv->ttm.bo_list_lock);
list_add_tail(&nvbo->head, &dev_priv->ttm.bo_list);
spin_unlock(&dev_priv->ttm.bo_list_lock);
*pnvbo = nvbo; *pnvbo = nvbo;
return 0; return 0;
} }

View File

@ -37,12 +37,6 @@
#include "nouveau_connector.h" #include "nouveau_connector.h"
#include "nouveau_hw.h" #include "nouveau_hw.h"
static inline struct drm_encoder_slave_funcs *
get_slave_funcs(struct nouveau_encoder *enc)
{
return to_encoder_slave(to_drm_encoder(enc))->slave_funcs;
}
static struct nouveau_encoder * static struct nouveau_encoder *
find_encoder_by_type(struct drm_connector *connector, int type) find_encoder_by_type(struct drm_connector *connector, int type)
{ {
@ -360,6 +354,7 @@ nouveau_connector_set_property(struct drm_connector *connector,
{ {
struct nouveau_connector *nv_connector = nouveau_connector(connector); struct nouveau_connector *nv_connector = nouveau_connector(connector);
struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder; struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder;
struct drm_encoder *encoder = to_drm_encoder(nv_encoder);
struct drm_device *dev = connector->dev; struct drm_device *dev = connector->dev;
int ret; int ret;
@ -432,8 +427,8 @@ nouveau_connector_set_property(struct drm_connector *connector,
} }
if (nv_encoder && nv_encoder->dcb->type == OUTPUT_TV) if (nv_encoder && nv_encoder->dcb->type == OUTPUT_TV)
return get_slave_funcs(nv_encoder)-> return get_slave_funcs(encoder)->set_property(
set_property(to_drm_encoder(nv_encoder), connector, property, value); encoder, connector, property, value);
return -EINVAL; return -EINVAL;
} }
@ -545,6 +540,7 @@ nouveau_connector_get_modes(struct drm_connector *connector)
struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_connector *nv_connector = nouveau_connector(connector); struct nouveau_connector *nv_connector = nouveau_connector(connector);
struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder; struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder;
struct drm_encoder *encoder = to_drm_encoder(nv_encoder);
int ret = 0; int ret = 0;
/* destroy the native mode, the attached monitor could have changed. /* destroy the native mode, the attached monitor could have changed.
@ -580,8 +576,7 @@ nouveau_connector_get_modes(struct drm_connector *connector)
} }
if (nv_encoder->dcb->type == OUTPUT_TV) if (nv_encoder->dcb->type == OUTPUT_TV)
ret = get_slave_funcs(nv_encoder)-> ret = get_slave_funcs(encoder)->get_modes(encoder, connector);
get_modes(to_drm_encoder(nv_encoder), connector);
if (nv_connector->dcb->type == DCB_CONNECTOR_LVDS || if (nv_connector->dcb->type == DCB_CONNECTOR_LVDS ||
nv_connector->dcb->type == DCB_CONNECTOR_eDP) nv_connector->dcb->type == DCB_CONNECTOR_eDP)
@ -597,6 +592,7 @@ nouveau_connector_mode_valid(struct drm_connector *connector,
struct drm_nouveau_private *dev_priv = connector->dev->dev_private; struct drm_nouveau_private *dev_priv = connector->dev->dev_private;
struct nouveau_connector *nv_connector = nouveau_connector(connector); struct nouveau_connector *nv_connector = nouveau_connector(connector);
struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder; struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder;
struct drm_encoder *encoder = to_drm_encoder(nv_encoder);
unsigned min_clock = 25000, max_clock = min_clock; unsigned min_clock = 25000, max_clock = min_clock;
unsigned clock = mode->clock; unsigned clock = mode->clock;
@ -623,8 +619,7 @@ nouveau_connector_mode_valid(struct drm_connector *connector,
max_clock = 350000; max_clock = 350000;
break; break;
case OUTPUT_TV: case OUTPUT_TV:
return get_slave_funcs(nv_encoder)-> return get_slave_funcs(encoder)->mode_valid(encoder, mode);
mode_valid(to_drm_encoder(nv_encoder), mode);
case OUTPUT_DP: case OUTPUT_DP:
if (nv_encoder->dp.link_bw == DP_LINK_BW_2_7) if (nv_encoder->dp.link_bw == DP_LINK_BW_2_7)
max_clock = nv_encoder->dp.link_nr * 270000; max_clock = nv_encoder->dp.link_nr * 270000;

View File

@ -572,47 +572,64 @@ out:
return ret ? ret : (stat & NV50_AUXCH_STAT_REPLY); return ret ? ret : (stat & NV50_AUXCH_STAT_REPLY);
} }
int static int
nouveau_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode, nouveau_dp_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
uint8_t write_byte, uint8_t *read_byte)
{ {
struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data; struct nouveau_i2c_chan *auxch = (struct nouveau_i2c_chan *)adap;
struct nouveau_i2c_chan *auxch = (struct nouveau_i2c_chan *)adapter;
struct drm_device *dev = auxch->dev; struct drm_device *dev = auxch->dev;
int ret = 0, cmd, addr = algo_data->address; struct i2c_msg *msg = msgs;
uint8_t *buf; int ret, mcnt = num;
if (mode == MODE_I2C_READ) { while (mcnt--) {
u8 remaining = msg->len;
u8 *ptr = msg->buf;
while (remaining) {
u8 cnt = (remaining > 16) ? 16 : remaining;
u8 cmd;
if (msg->flags & I2C_M_RD)
cmd = AUX_I2C_READ; cmd = AUX_I2C_READ;
buf = read_byte; else
} else { cmd = AUX_I2C_WRITE;
cmd = (mode & MODE_I2C_READ) ? AUX_I2C_READ : AUX_I2C_WRITE;
buf = &write_byte;
}
if (!(mode & MODE_I2C_STOP)) if (mcnt || remaining > 16)
cmd |= AUX_I2C_MOT; cmd |= AUX_I2C_MOT;
if (mode & MODE_I2C_START) ret = nouveau_dp_auxch(auxch, cmd, msg->addr, ptr, cnt);
return 1;
for (;;) {
ret = nouveau_dp_auxch(auxch, cmd, addr, buf, 1);
if (ret < 0) if (ret < 0)
return ret; return ret;
switch (ret & NV50_AUXCH_STAT_REPLY_I2C) { switch (ret & NV50_AUXCH_STAT_REPLY_I2C) {
case NV50_AUXCH_STAT_REPLY_I2C_ACK: case NV50_AUXCH_STAT_REPLY_I2C_ACK:
return 1; break;
case NV50_AUXCH_STAT_REPLY_I2C_NACK: case NV50_AUXCH_STAT_REPLY_I2C_NACK:
return -EREMOTEIO; return -EREMOTEIO;
case NV50_AUXCH_STAT_REPLY_I2C_DEFER: case NV50_AUXCH_STAT_REPLY_I2C_DEFER:
udelay(100); udelay(100);
break; continue;
default: default:
NV_ERROR(dev, "invalid auxch status: 0x%08x\n", ret); NV_ERROR(dev, "bad auxch reply: 0x%08x\n", ret);
return -EREMOTEIO; return -EREMOTEIO;
} }
}
ptr += cnt;
remaining -= cnt;
} }
msg++;
}
return num;
}
static u32
nouveau_dp_i2c_func(struct i2c_adapter *adap)
{
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
}
const struct i2c_algorithm nouveau_dp_i2c_algo = {
.master_xfer = nouveau_dp_i2c_xfer,
.functionality = nouveau_dp_i2c_func
};

View File

@ -410,7 +410,7 @@ enum nv04_fp_display_regs {
struct nv04_crtc_reg { struct nv04_crtc_reg {
unsigned char MiscOutReg; /* */ unsigned char MiscOutReg; /* */
uint8_t CRTC[0x9f]; uint8_t CRTC[0xa0];
uint8_t CR58[0x10]; uint8_t CR58[0x10];
uint8_t Sequencer[5]; uint8_t Sequencer[5];
uint8_t Graphics[9]; uint8_t Graphics[9];
@ -509,6 +509,7 @@ enum nouveau_card_type {
NV_30 = 0x30, NV_30 = 0x30,
NV_40 = 0x40, NV_40 = 0x40,
NV_50 = 0x50, NV_50 = 0x50,
NV_C0 = 0xc0,
}; };
struct drm_nouveau_private { struct drm_nouveau_private {
@ -536,8 +537,6 @@ struct drm_nouveau_private {
struct drm_global_reference mem_global_ref; struct drm_global_reference mem_global_ref;
struct ttm_bo_global_ref bo_global_ref; struct ttm_bo_global_ref bo_global_ref;
struct ttm_bo_device bdev; struct ttm_bo_device bdev;
spinlock_t bo_list_lock;
struct list_head bo_list;
atomic_t validate_sequence; atomic_t validate_sequence;
} ttm; } ttm;
@ -931,6 +930,10 @@ extern void nv40_fb_set_region_tiling(struct drm_device *, int, uint32_t,
extern int nv50_fb_init(struct drm_device *); extern int nv50_fb_init(struct drm_device *);
extern void nv50_fb_takedown(struct drm_device *); extern void nv50_fb_takedown(struct drm_device *);
/* nvc0_fb.c */
extern int nvc0_fb_init(struct drm_device *);
extern void nvc0_fb_takedown(struct drm_device *);
/* nv04_fifo.c */ /* nv04_fifo.c */
extern int nv04_fifo_init(struct drm_device *); extern int nv04_fifo_init(struct drm_device *);
extern void nv04_fifo_disable(struct drm_device *); extern void nv04_fifo_disable(struct drm_device *);
@ -968,6 +971,20 @@ extern void nv50_fifo_destroy_context(struct nouveau_channel *);
extern int nv50_fifo_load_context(struct nouveau_channel *); extern int nv50_fifo_load_context(struct nouveau_channel *);
extern int nv50_fifo_unload_context(struct drm_device *); extern int nv50_fifo_unload_context(struct drm_device *);
/* nvc0_fifo.c */
extern int nvc0_fifo_init(struct drm_device *);
extern void nvc0_fifo_takedown(struct drm_device *);
extern void nvc0_fifo_disable(struct drm_device *);
extern void nvc0_fifo_enable(struct drm_device *);
extern bool nvc0_fifo_reassign(struct drm_device *, bool);
extern bool nvc0_fifo_cache_flush(struct drm_device *);
extern bool nvc0_fifo_cache_pull(struct drm_device *, bool);
extern int nvc0_fifo_channel_id(struct drm_device *);
extern int nvc0_fifo_create_context(struct nouveau_channel *);
extern void nvc0_fifo_destroy_context(struct nouveau_channel *);
extern int nvc0_fifo_load_context(struct nouveau_channel *);
extern int nvc0_fifo_unload_context(struct drm_device *);
/* nv04_graph.c */ /* nv04_graph.c */
extern struct nouveau_pgraph_object_class nv04_graph_grclass[]; extern struct nouveau_pgraph_object_class nv04_graph_grclass[];
extern int nv04_graph_init(struct drm_device *); extern int nv04_graph_init(struct drm_device *);
@ -1032,6 +1049,16 @@ extern int nv50_graph_unload_context(struct drm_device *);
extern void nv50_graph_context_switch(struct drm_device *); extern void nv50_graph_context_switch(struct drm_device *);
extern int nv50_grctx_init(struct nouveau_grctx *); extern int nv50_grctx_init(struct nouveau_grctx *);
/* nvc0_graph.c */
extern int nvc0_graph_init(struct drm_device *);
extern void nvc0_graph_takedown(struct drm_device *);
extern void nvc0_graph_fifo_access(struct drm_device *, bool);
extern struct nouveau_channel *nvc0_graph_channel(struct drm_device *);
extern int nvc0_graph_create_context(struct nouveau_channel *);
extern void nvc0_graph_destroy_context(struct nouveau_channel *);
extern int nvc0_graph_load_context(struct nouveau_channel *);
extern int nvc0_graph_unload_context(struct drm_device *);
/* nv04_instmem.c */ /* nv04_instmem.c */
extern int nv04_instmem_init(struct drm_device *); extern int nv04_instmem_init(struct drm_device *);
extern void nv04_instmem_takedown(struct drm_device *); extern void nv04_instmem_takedown(struct drm_device *);
@ -1058,6 +1085,18 @@ extern void nv50_instmem_flush(struct drm_device *);
extern void nv84_instmem_flush(struct drm_device *); extern void nv84_instmem_flush(struct drm_device *);
extern void nv50_vm_flush(struct drm_device *, int engine); extern void nv50_vm_flush(struct drm_device *, int engine);
/* nvc0_instmem.c */
extern int nvc0_instmem_init(struct drm_device *);
extern void nvc0_instmem_takedown(struct drm_device *);
extern int nvc0_instmem_suspend(struct drm_device *);
extern void nvc0_instmem_resume(struct drm_device *);
extern int nvc0_instmem_populate(struct drm_device *, struct nouveau_gpuobj *,
uint32_t *size);
extern void nvc0_instmem_clear(struct drm_device *, struct nouveau_gpuobj *);
extern int nvc0_instmem_bind(struct drm_device *, struct nouveau_gpuobj *);
extern int nvc0_instmem_unbind(struct drm_device *, struct nouveau_gpuobj *);
extern void nvc0_instmem_flush(struct drm_device *);
/* nv04_mc.c */ /* nv04_mc.c */
extern int nv04_mc_init(struct drm_device *); extern int nv04_mc_init(struct drm_device *);
extern void nv04_mc_takedown(struct drm_device *); extern void nv04_mc_takedown(struct drm_device *);

View File

@ -71,6 +71,12 @@ static inline struct drm_encoder *to_drm_encoder(struct nouveau_encoder *enc)
return &enc->base.base; return &enc->base.base;
} }
static inline struct drm_encoder_slave_funcs *
get_slave_funcs(struct drm_encoder *enc)
{
return to_encoder_slave(enc)->slave_funcs;
}
struct nouveau_connector * struct nouveau_connector *
nouveau_encoder_connector_get(struct nouveau_encoder *encoder); nouveau_encoder_connector_get(struct nouveau_encoder *encoder);
int nv50_sor_create(struct drm_connector *, struct dcb_entry *); int nv50_sor_create(struct drm_connector *, struct dcb_entry *);

View File

@ -280,6 +280,8 @@ nouveau_fbcon_create(struct nouveau_fbdev *nfbdev,
if (dev_priv->channel && !nouveau_nofbaccel) { if (dev_priv->channel && !nouveau_nofbaccel) {
switch (dev_priv->card_type) { switch (dev_priv->card_type) {
case NV_C0:
break;
case NV_50: case NV_50:
nv50_fbcon_accel_init(info); nv50_fbcon_accel_init(info);
info->fbops = &nv50_fbcon_ops; info->fbops = &nv50_fbcon_ops;

View File

@ -865,8 +865,12 @@ nv_save_state_ext(struct drm_device *dev, int head,
rd_cio_state(dev, head, regp, NV_CIO_CRE_FF_INDEX); rd_cio_state(dev, head, regp, NV_CIO_CRE_FF_INDEX);
rd_cio_state(dev, head, regp, NV_CIO_CRE_FFLWM__INDEX); rd_cio_state(dev, head, regp, NV_CIO_CRE_FFLWM__INDEX);
rd_cio_state(dev, head, regp, NV_CIO_CRE_21); rd_cio_state(dev, head, regp, NV_CIO_CRE_21);
if (dev_priv->card_type >= NV_30)
if (dev_priv->card_type >= NV_30) {
rd_cio_state(dev, head, regp, NV_CIO_CRE_47); rd_cio_state(dev, head, regp, NV_CIO_CRE_47);
rd_cio_state(dev, head, regp, 0x9f);
}
rd_cio_state(dev, head, regp, NV_CIO_CRE_49); rd_cio_state(dev, head, regp, NV_CIO_CRE_49);
rd_cio_state(dev, head, regp, NV_CIO_CRE_HCUR_ADDR0_INDEX); rd_cio_state(dev, head, regp, NV_CIO_CRE_HCUR_ADDR0_INDEX);
rd_cio_state(dev, head, regp, NV_CIO_CRE_HCUR_ADDR1_INDEX); rd_cio_state(dev, head, regp, NV_CIO_CRE_HCUR_ADDR1_INDEX);
@ -971,8 +975,11 @@ nv_load_state_ext(struct drm_device *dev, int head,
wr_cio_state(dev, head, regp, NV_CIO_CRE_ENH_INDEX); wr_cio_state(dev, head, regp, NV_CIO_CRE_ENH_INDEX);
wr_cio_state(dev, head, regp, NV_CIO_CRE_FF_INDEX); wr_cio_state(dev, head, regp, NV_CIO_CRE_FF_INDEX);
wr_cio_state(dev, head, regp, NV_CIO_CRE_FFLWM__INDEX); wr_cio_state(dev, head, regp, NV_CIO_CRE_FFLWM__INDEX);
if (dev_priv->card_type >= NV_30)
if (dev_priv->card_type >= NV_30) {
wr_cio_state(dev, head, regp, NV_CIO_CRE_47); wr_cio_state(dev, head, regp, NV_CIO_CRE_47);
wr_cio_state(dev, head, regp, 0x9f);
}
wr_cio_state(dev, head, regp, NV_CIO_CRE_49); wr_cio_state(dev, head, regp, NV_CIO_CRE_49);
wr_cio_state(dev, head, regp, NV_CIO_CRE_HCUR_ADDR0_INDEX); wr_cio_state(dev, head, regp, NV_CIO_CRE_HCUR_ADDR0_INDEX);

View File

@ -163,7 +163,7 @@ nouveau_i2c_init(struct drm_device *dev, struct dcb_i2c_entry *entry, int index)
if (entry->chan) if (entry->chan)
return -EEXIST; return -EEXIST;
if (dev_priv->card_type == NV_50 && entry->read >= NV50_I2C_PORTS) { if (dev_priv->card_type == NV_C0 && entry->read >= NV50_I2C_PORTS) {
NV_ERROR(dev, "unknown i2c port %d\n", entry->read); NV_ERROR(dev, "unknown i2c port %d\n", entry->read);
return -EINVAL; return -EINVAL;
} }
@ -174,26 +174,26 @@ nouveau_i2c_init(struct drm_device *dev, struct dcb_i2c_entry *entry, int index)
switch (entry->port_type) { switch (entry->port_type) {
case 0: case 0:
i2c->algo.bit.setsda = nv04_i2c_setsda; i2c->bit.setsda = nv04_i2c_setsda;
i2c->algo.bit.setscl = nv04_i2c_setscl; i2c->bit.setscl = nv04_i2c_setscl;
i2c->algo.bit.getsda = nv04_i2c_getsda; i2c->bit.getsda = nv04_i2c_getsda;
i2c->algo.bit.getscl = nv04_i2c_getscl; i2c->bit.getscl = nv04_i2c_getscl;
i2c->rd = entry->read; i2c->rd = entry->read;
i2c->wr = entry->write; i2c->wr = entry->write;
break; break;
case 4: case 4:
i2c->algo.bit.setsda = nv4e_i2c_setsda; i2c->bit.setsda = nv4e_i2c_setsda;
i2c->algo.bit.setscl = nv4e_i2c_setscl; i2c->bit.setscl = nv4e_i2c_setscl;
i2c->algo.bit.getsda = nv4e_i2c_getsda; i2c->bit.getsda = nv4e_i2c_getsda;
i2c->algo.bit.getscl = nv4e_i2c_getscl; i2c->bit.getscl = nv4e_i2c_getscl;
i2c->rd = 0x600800 + entry->read; i2c->rd = 0x600800 + entry->read;
i2c->wr = 0x600800 + entry->write; i2c->wr = 0x600800 + entry->write;
break; break;
case 5: case 5:
i2c->algo.bit.setsda = nv50_i2c_setsda; i2c->bit.setsda = nv50_i2c_setsda;
i2c->algo.bit.setscl = nv50_i2c_setscl; i2c->bit.setscl = nv50_i2c_setscl;
i2c->algo.bit.getsda = nv50_i2c_getsda; i2c->bit.getsda = nv50_i2c_getsda;
i2c->algo.bit.getscl = nv50_i2c_getscl; i2c->bit.getscl = nv50_i2c_getscl;
i2c->rd = nv50_i2c_port[entry->read]; i2c->rd = nv50_i2c_port[entry->read];
i2c->wr = i2c->rd; i2c->wr = i2c->rd;
break; break;
@ -216,17 +216,14 @@ nouveau_i2c_init(struct drm_device *dev, struct dcb_i2c_entry *entry, int index)
i2c_set_adapdata(&i2c->adapter, i2c); i2c_set_adapdata(&i2c->adapter, i2c);
if (entry->port_type < 6) { if (entry->port_type < 6) {
i2c->adapter.algo_data = &i2c->algo.bit; i2c->adapter.algo_data = &i2c->bit;
i2c->algo.bit.udelay = 40; i2c->bit.udelay = 40;
i2c->algo.bit.timeout = usecs_to_jiffies(5000); i2c->bit.timeout = usecs_to_jiffies(5000);
i2c->algo.bit.data = i2c; i2c->bit.data = i2c;
ret = i2c_bit_add_bus(&i2c->adapter); ret = i2c_bit_add_bus(&i2c->adapter);
} else { } else {
i2c->adapter.algo_data = &i2c->algo.dp; i2c->adapter.algo = &nouveau_dp_i2c_algo;
i2c->algo.dp.running = false; ret = i2c_add_adapter(&i2c->adapter);
i2c->algo.dp.address = 0;
i2c->algo.dp.aux_ch = nouveau_dp_i2c_aux_ch;
ret = i2c_dp_aux_add_bus(&i2c->adapter);
} }
if (ret) { if (ret) {

View File

@ -33,10 +33,7 @@ struct dcb_i2c_entry;
struct nouveau_i2c_chan { struct nouveau_i2c_chan {
struct i2c_adapter adapter; struct i2c_adapter adapter;
struct drm_device *dev; struct drm_device *dev;
union {
struct i2c_algo_bit_data bit; struct i2c_algo_bit_data bit;
struct i2c_algo_dp_aux_data dp;
} algo;
unsigned rd; unsigned rd;
unsigned wr; unsigned wr;
unsigned data; unsigned data;
@ -49,7 +46,6 @@ bool nouveau_probe_i2c_addr(struct nouveau_i2c_chan *i2c, int addr);
int nouveau_i2c_identify(struct drm_device *dev, const char *what, int nouveau_i2c_identify(struct drm_device *dev, const char *what,
struct i2c_board_info *info, int index); struct i2c_board_info *info, int index);
int nouveau_dp_i2c_aux_ch(struct i2c_adapter *, int mode, uint8_t write_byte, extern const struct i2c_algorithm nouveau_dp_i2c_algo;
uint8_t *read_byte);
#endif /* __NOUVEAU_I2C_H__ */ #endif /* __NOUVEAU_I2C_H__ */

View File

@ -49,7 +49,7 @@ nouveau_irq_preinstall(struct drm_device *dev)
/* Master disable */ /* Master disable */
nv_wr32(dev, NV03_PMC_INTR_EN_0, 0); nv_wr32(dev, NV03_PMC_INTR_EN_0, 0);
if (dev_priv->card_type == NV_50) { if (dev_priv->card_type >= NV_50) {
INIT_WORK(&dev_priv->irq_work, nv50_display_irq_handler_bh); INIT_WORK(&dev_priv->irq_work, nv50_display_irq_handler_bh);
INIT_WORK(&dev_priv->hpd_work, nv50_display_irq_hotplug_bh); INIT_WORK(&dev_priv->hpd_work, nv50_display_irq_hotplug_bh);
INIT_LIST_HEAD(&dev_priv->vbl_waiting); INIT_LIST_HEAD(&dev_priv->vbl_waiting);
@ -586,11 +586,11 @@ nouveau_pgraph_irq_handler(struct drm_device *dev)
} }
if (status & NV_PGRAPH_INTR_CONTEXT_SWITCH) { if (status & NV_PGRAPH_INTR_CONTEXT_SWITCH) {
nouveau_pgraph_intr_context_switch(dev);
status &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH; status &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH;
nv_wr32(dev, NV03_PGRAPH_INTR, nv_wr32(dev, NV03_PGRAPH_INTR,
NV_PGRAPH_INTR_CONTEXT_SWITCH); NV_PGRAPH_INTR_CONTEXT_SWITCH);
nouveau_pgraph_intr_context_switch(dev);
} }
if (status) { if (status) {

View File

@ -320,7 +320,8 @@ nouveau_mem_detect(struct drm_device *dev)
if (dev_priv->card_type < NV_50) { if (dev_priv->card_type < NV_50) {
dev_priv->vram_size = nv_rd32(dev, NV04_PFB_FIFO_DATA); dev_priv->vram_size = nv_rd32(dev, NV04_PFB_FIFO_DATA);
dev_priv->vram_size &= NV10_PFB_FIFO_DATA_RAM_AMOUNT_MB_MASK; dev_priv->vram_size &= NV10_PFB_FIFO_DATA_RAM_AMOUNT_MB_MASK;
} else { } else
if (dev_priv->card_type < NV_C0) {
dev_priv->vram_size = nv_rd32(dev, NV04_PFB_FIFO_DATA); 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 |= (dev_priv->vram_size & 0xff) << 32;
dev_priv->vram_size &= 0xffffffff00ll; dev_priv->vram_size &= 0xffffffff00ll;
@ -328,6 +329,9 @@ nouveau_mem_detect(struct drm_device *dev)
dev_priv->vram_sys_base = nv_rd32(dev, 0x100e10); dev_priv->vram_sys_base = nv_rd32(dev, 0x100e10);
dev_priv->vram_sys_base <<= 12; dev_priv->vram_sys_base <<= 12;
} }
} else {
dev_priv->vram_size = nv_rd32(dev, 0x10f20c) << 20;
dev_priv->vram_size *= nv_rd32(dev, 0x121c74);
} }
NV_INFO(dev, "Detected %dMiB VRAM\n", (int)(dev_priv->vram_size >> 20)); NV_INFO(dev, "Detected %dMiB VRAM\n", (int)(dev_priv->vram_size >> 20));
@ -351,7 +355,7 @@ nouveau_mem_reset_agp(struct drm_device *dev)
/* First of all, disable fast writes, otherwise if it's /* First of all, disable fast writes, otherwise if it's
* already enabled in the AGP bridge and we disable the card's * already enabled in the AGP bridge and we disable the card's
* AGP controller we might be locking ourselves out of it. */ * AGP controller we might be locking ourselves out of it. */
if (dev->agp->acquired) { if (nv_rd32(dev, NV04_PBUS_PCI_NV_19) & PCI_AGP_COMMAND_FW) {
struct drm_agp_info info; struct drm_agp_info info;
struct drm_agp_mode mode; struct drm_agp_mode mode;
@ -359,7 +363,7 @@ nouveau_mem_reset_agp(struct drm_device *dev)
if (ret) if (ret)
return ret; return ret;
mode.mode = info.mode & ~0x10; mode.mode = info.mode & ~PCI_AGP_COMMAND_FW;
ret = drm_agp_enable(dev, mode); ret = drm_agp_enable(dev, mode);
if (ret) if (ret)
return ret; return ret;
@ -405,6 +409,8 @@ nouveau_mem_init_agp(struct drm_device *dev)
} }
} }
nouveau_mem_reset_agp(dev);
ret = drm_agp_info(dev, &info); ret = drm_agp_info(dev, &info);
if (ret) { if (ret) {
NV_ERROR(dev, "Unable to get AGP info: %d\n", ret); NV_ERROR(dev, "Unable to get AGP info: %d\n", ret);
@ -459,8 +465,6 @@ nouveau_mem_init(struct drm_device *dev)
return ret; return ret;
} }
INIT_LIST_HEAD(&dev_priv->ttm.bo_list);
spin_lock_init(&dev_priv->ttm.bo_list_lock);
spin_lock_init(&dev_priv->tile.lock); spin_lock_init(&dev_priv->tile.lock);
dev_priv->fb_available_size = dev_priv->vram_size; dev_priv->fb_available_size = dev_priv->vram_size;
@ -494,7 +498,6 @@ nouveau_mem_init(struct drm_device *dev)
/* GART */ /* GART */
#if !defined(__powerpc__) && !defined(__ia64__) #if !defined(__powerpc__) && !defined(__ia64__)
if (drm_device_is_agp(dev) && dev->agp && !nouveau_noagp) { if (drm_device_is_agp(dev) && dev->agp && !nouveau_noagp) {
nouveau_mem_reset_agp(dev);
ret = nouveau_mem_init_agp(dev); ret = nouveau_mem_init_agp(dev);
if (ret) if (ret)
NV_ERROR(dev, "Error initialising AGP: %d\n", ret); NV_ERROR(dev, "Error initialising AGP: %d\n", ret);

View File

@ -220,28 +220,21 @@
# define NV_PGRAPH_INTR_ERROR (1<<20) # define NV_PGRAPH_INTR_ERROR (1<<20)
#define NV10_PGRAPH_CTX_CONTROL 0x00400144 #define NV10_PGRAPH_CTX_CONTROL 0x00400144
#define NV10_PGRAPH_CTX_USER 0x00400148 #define NV10_PGRAPH_CTX_USER 0x00400148
#define NV10_PGRAPH_CTX_SWITCH1 0x0040014C #define NV10_PGRAPH_CTX_SWITCH(i) (0x0040014C + 0x4*(i))
#define NV10_PGRAPH_CTX_SWITCH2 0x00400150
#define NV10_PGRAPH_CTX_SWITCH3 0x00400154
#define NV10_PGRAPH_CTX_SWITCH4 0x00400158
#define NV10_PGRAPH_CTX_SWITCH5 0x0040015C
#define NV04_PGRAPH_CTX_SWITCH1 0x00400160 #define NV04_PGRAPH_CTX_SWITCH1 0x00400160
#define NV10_PGRAPH_CTX_CACHE1 0x00400160 #define NV10_PGRAPH_CTX_CACHE(i, j) (0x00400160 \
+ 0x4*(i) + 0x20*(j))
#define NV04_PGRAPH_CTX_SWITCH2 0x00400164 #define NV04_PGRAPH_CTX_SWITCH2 0x00400164
#define NV04_PGRAPH_CTX_SWITCH3 0x00400168 #define NV04_PGRAPH_CTX_SWITCH3 0x00400168
#define NV04_PGRAPH_CTX_SWITCH4 0x0040016C #define NV04_PGRAPH_CTX_SWITCH4 0x0040016C
#define NV04_PGRAPH_CTX_CONTROL 0x00400170 #define NV04_PGRAPH_CTX_CONTROL 0x00400170
#define NV04_PGRAPH_CTX_USER 0x00400174 #define NV04_PGRAPH_CTX_USER 0x00400174
#define NV04_PGRAPH_CTX_CACHE1 0x00400180 #define NV04_PGRAPH_CTX_CACHE1 0x00400180
#define NV10_PGRAPH_CTX_CACHE2 0x00400180
#define NV03_PGRAPH_CTX_CONTROL 0x00400190 #define NV03_PGRAPH_CTX_CONTROL 0x00400190
#define NV03_PGRAPH_CTX_USER 0x00400194 #define NV03_PGRAPH_CTX_USER 0x00400194
#define NV04_PGRAPH_CTX_CACHE2 0x004001A0 #define NV04_PGRAPH_CTX_CACHE2 0x004001A0
#define NV10_PGRAPH_CTX_CACHE3 0x004001A0
#define NV04_PGRAPH_CTX_CACHE3 0x004001C0 #define NV04_PGRAPH_CTX_CACHE3 0x004001C0
#define NV10_PGRAPH_CTX_CACHE4 0x004001C0
#define NV04_PGRAPH_CTX_CACHE4 0x004001E0 #define NV04_PGRAPH_CTX_CACHE4 0x004001E0
#define NV10_PGRAPH_CTX_CACHE5 0x004001E0
#define NV40_PGRAPH_CTXCTL_0304 0x00400304 #define NV40_PGRAPH_CTXCTL_0304 0x00400304
#define NV40_PGRAPH_CTXCTL_0304_XFER_CTX 0x00000001 #define NV40_PGRAPH_CTXCTL_0304_XFER_CTX 0x00000001
#define NV40_PGRAPH_CTXCTL_UCODE_STAT 0x00400308 #define NV40_PGRAPH_CTXCTL_UCODE_STAT 0x00400308
@ -356,9 +349,12 @@
#define NV04_PGRAPH_FFINTFC_ST2 0x00400754 #define NV04_PGRAPH_FFINTFC_ST2 0x00400754
#define NV10_PGRAPH_RDI_DATA 0x00400754 #define NV10_PGRAPH_RDI_DATA 0x00400754
#define NV04_PGRAPH_DMA_PITCH 0x00400760 #define NV04_PGRAPH_DMA_PITCH 0x00400760
#define NV10_PGRAPH_FFINTFC_ST2 0x00400764 #define NV10_PGRAPH_FFINTFC_FIFO_PTR 0x00400760
#define NV04_PGRAPH_DVD_COLORFMT 0x00400764 #define NV04_PGRAPH_DVD_COLORFMT 0x00400764
#define NV10_PGRAPH_FFINTFC_ST2 0x00400764
#define NV04_PGRAPH_SCALED_FORMAT 0x00400768 #define NV04_PGRAPH_SCALED_FORMAT 0x00400768
#define NV10_PGRAPH_FFINTFC_ST2_DL 0x00400768
#define NV10_PGRAPH_FFINTFC_ST2_DH 0x0040076c
#define NV10_PGRAPH_DMA_PITCH 0x00400770 #define NV10_PGRAPH_DMA_PITCH 0x00400770
#define NV10_PGRAPH_DVD_COLORFMT 0x00400774 #define NV10_PGRAPH_DVD_COLORFMT 0x00400774
#define NV10_PGRAPH_SCALED_FORMAT 0x00400778 #define NV10_PGRAPH_SCALED_FORMAT 0x00400778

View File

@ -359,6 +359,54 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->gpio.set = nv50_gpio_set; engine->gpio.set = nv50_gpio_set;
engine->gpio.irq_enable = nv50_gpio_irq_enable; engine->gpio.irq_enable = nv50_gpio_irq_enable;
break; break;
case 0xC0:
engine->instmem.init = nvc0_instmem_init;
engine->instmem.takedown = nvc0_instmem_takedown;
engine->instmem.suspend = nvc0_instmem_suspend;
engine->instmem.resume = nvc0_instmem_resume;
engine->instmem.populate = nvc0_instmem_populate;
engine->instmem.clear = nvc0_instmem_clear;
engine->instmem.bind = nvc0_instmem_bind;
engine->instmem.unbind = nvc0_instmem_unbind;
engine->instmem.flush = nvc0_instmem_flush;
engine->mc.init = nv50_mc_init;
engine->mc.takedown = nv50_mc_takedown;
engine->timer.init = nv04_timer_init;
engine->timer.read = nv04_timer_read;
engine->timer.takedown = nv04_timer_takedown;
engine->fb.init = nvc0_fb_init;
engine->fb.takedown = nvc0_fb_takedown;
engine->graph.grclass = NULL; //nvc0_graph_grclass;
engine->graph.init = nvc0_graph_init;
engine->graph.takedown = nvc0_graph_takedown;
engine->graph.fifo_access = nvc0_graph_fifo_access;
engine->graph.channel = nvc0_graph_channel;
engine->graph.create_context = nvc0_graph_create_context;
engine->graph.destroy_context = nvc0_graph_destroy_context;
engine->graph.load_context = nvc0_graph_load_context;
engine->graph.unload_context = nvc0_graph_unload_context;
engine->fifo.channels = 128;
engine->fifo.init = nvc0_fifo_init;
engine->fifo.takedown = nvc0_fifo_takedown;
engine->fifo.disable = nvc0_fifo_disable;
engine->fifo.enable = nvc0_fifo_enable;
engine->fifo.reassign = nvc0_fifo_reassign;
engine->fifo.channel_id = nvc0_fifo_channel_id;
engine->fifo.create_context = nvc0_fifo_create_context;
engine->fifo.destroy_context = nvc0_fifo_destroy_context;
engine->fifo.load_context = nvc0_fifo_load_context;
engine->fifo.unload_context = nvc0_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: default:
NV_ERROR(dev, "NV%02x unsupported\n", dev_priv->chipset); NV_ERROR(dev, "NV%02x unsupported\n", dev_priv->chipset);
return 1; return 1;
@ -739,8 +787,10 @@ int nouveau_load(struct drm_device *dev, unsigned long flags)
int ret; int ret;
dev_priv = kzalloc(sizeof(*dev_priv), GFP_KERNEL); dev_priv = kzalloc(sizeof(*dev_priv), GFP_KERNEL);
if (!dev_priv) if (!dev_priv) {
return -ENOMEM; ret = -ENOMEM;
goto err_out;
}
dev->dev_private = dev_priv; dev->dev_private = dev_priv;
dev_priv->dev = dev; dev_priv->dev = dev;
@ -750,8 +800,10 @@ int nouveau_load(struct drm_device *dev, unsigned long flags)
dev->pci_vendor, dev->pci_device, dev->pdev->class); dev->pci_vendor, dev->pci_device, dev->pdev->class);
dev_priv->wq = create_workqueue("nouveau"); dev_priv->wq = create_workqueue("nouveau");
if (!dev_priv->wq) if (!dev_priv->wq) {
return -EINVAL; ret = -EINVAL;
goto err_priv;
}
/* resource 0 is mmio regs */ /* resource 0 is mmio regs */
/* resource 1 is linear FB */ /* resource 1 is linear FB */
@ -764,7 +816,8 @@ int nouveau_load(struct drm_device *dev, unsigned long flags)
if (!dev_priv->mmio) { if (!dev_priv->mmio) {
NV_ERROR(dev, "Unable to initialize the mmio mapping. " NV_ERROR(dev, "Unable to initialize the mmio mapping. "
"Please report your setup to " DRIVER_EMAIL "\n"); "Please report your setup to " DRIVER_EMAIL "\n");
return -EINVAL; ret = -EINVAL;
goto err_wq;
} }
NV_DEBUG(dev, "regs mapped ok at 0x%llx\n", NV_DEBUG(dev, "regs mapped ok at 0x%llx\n",
(unsigned long long)mmio_start_offs); (unsigned long long)mmio_start_offs);
@ -810,9 +863,13 @@ int nouveau_load(struct drm_device *dev, unsigned long flags)
case 0xa0: case 0xa0:
dev_priv->card_type = NV_50; dev_priv->card_type = NV_50;
break; break;
case 0xc0:
dev_priv->card_type = NV_C0;
break;
default: default:
NV_INFO(dev, "Unsupported chipset 0x%08x\n", reg0); NV_INFO(dev, "Unsupported chipset 0x%08x\n", reg0);
return -EINVAL; ret = -EINVAL;
goto err_mmio;
} }
NV_INFO(dev, "Detected an NV%2x generation card (0x%08x)\n", NV_INFO(dev, "Detected an NV%2x generation card (0x%08x)\n",
@ -820,7 +877,7 @@ int nouveau_load(struct drm_device *dev, unsigned long flags)
ret = nouveau_remove_conflicting_drivers(dev); ret = nouveau_remove_conflicting_drivers(dev);
if (ret) if (ret)
return ret; goto err_mmio;
/* Map PRAMIN BAR, or on older cards, the aperture withing BAR0 */ /* Map PRAMIN BAR, or on older cards, the aperture withing BAR0 */
if (dev_priv->card_type >= NV_40) { if (dev_priv->card_type >= NV_40) {
@ -834,7 +891,8 @@ int nouveau_load(struct drm_device *dev, unsigned long flags)
dev_priv->ramin_size); dev_priv->ramin_size);
if (!dev_priv->ramin) { if (!dev_priv->ramin) {
NV_ERROR(dev, "Failed to PRAMIN BAR"); NV_ERROR(dev, "Failed to PRAMIN BAR");
return -ENOMEM; ret = -ENOMEM;
goto err_mmio;
} }
} else { } else {
dev_priv->ramin_size = 1 * 1024 * 1024; dev_priv->ramin_size = 1 * 1024 * 1024;
@ -842,7 +900,8 @@ int nouveau_load(struct drm_device *dev, unsigned long flags)
dev_priv->ramin_size); dev_priv->ramin_size);
if (!dev_priv->ramin) { if (!dev_priv->ramin) {
NV_ERROR(dev, "Failed to map BAR0 PRAMIN.\n"); NV_ERROR(dev, "Failed to map BAR0 PRAMIN.\n");
return -ENOMEM; ret = -ENOMEM;
goto err_mmio;
} }
} }
@ -857,9 +916,21 @@ int nouveau_load(struct drm_device *dev, unsigned long flags)
/* For kernel modesetting, init card now and bring up fbcon */ /* For kernel modesetting, init card now and bring up fbcon */
ret = nouveau_card_init(dev); ret = nouveau_card_init(dev);
if (ret) if (ret)
return ret; goto err_ramin;
return 0; return 0;
err_ramin:
iounmap(dev_priv->ramin);
err_mmio:
iounmap(dev_priv->mmio);
err_wq:
destroy_workqueue(dev_priv->wq);
err_priv:
kfree(dev_priv);
dev->dev_private = NULL;
err_out:
return ret;
} }
void nouveau_lastclose(struct drm_device *dev) void nouveau_lastclose(struct drm_device *dev)

View File

@ -542,6 +542,9 @@ nv_crtc_mode_set_regs(struct drm_crtc *crtc, struct drm_display_mode * mode)
* 1 << 30 on 0x60.830), for no apparent reason */ * 1 << 30 on 0x60.830), for no apparent reason */
regp->CRTC[NV_CIO_CRE_59] = off_chip_digital; regp->CRTC[NV_CIO_CRE_59] = off_chip_digital;
if (dev_priv->card_type >= NV_30)
regp->CRTC[0x9f] = off_chip_digital ? 0x11 : 0x1;
regp->crtc_830 = mode->crtc_vdisplay - 3; regp->crtc_830 = mode->crtc_vdisplay - 3;
regp->crtc_834 = mode->crtc_vdisplay - 1; regp->crtc_834 = mode->crtc_vdisplay - 1;

View File

@ -34,6 +34,8 @@
#include "nouveau_hw.h" #include "nouveau_hw.h"
#include "nvreg.h" #include "nvreg.h"
#include "i2c/sil164.h"
#define FP_TG_CONTROL_ON (NV_PRAMDAC_FP_TG_CONTROL_DISPEN_POS | \ #define FP_TG_CONTROL_ON (NV_PRAMDAC_FP_TG_CONTROL_DISPEN_POS | \
NV_PRAMDAC_FP_TG_CONTROL_HSYNC_POS | \ NV_PRAMDAC_FP_TG_CONTROL_HSYNC_POS | \
NV_PRAMDAC_FP_TG_CONTROL_VSYNC_POS) NV_PRAMDAC_FP_TG_CONTROL_VSYNC_POS)
@ -144,6 +146,36 @@ void nv04_dfp_update_fp_control(struct drm_encoder *encoder, int mode)
} }
} }
static struct drm_encoder *get_tmds_slave(struct drm_encoder *encoder)
{
struct drm_device *dev = encoder->dev;
struct dcb_entry *dcb = nouveau_encoder(encoder)->dcb;
struct drm_encoder *slave;
if (dcb->type != OUTPUT_TMDS || dcb->location == DCB_LOC_ON_CHIP)
return NULL;
/* Some BIOSes (e.g. the one in a Quadro FX1000) report several
* TMDS transmitters at the same I2C address, in the same I2C
* bus. This can still work because in that case one of them is
* always hard-wired to a reasonable configuration using straps,
* and the other one needs to be programmed.
*
* I don't think there's a way to know which is which, even the
* blob programs the one exposed via I2C for *both* heads, so
* let's do the same.
*/
list_for_each_entry(slave, &dev->mode_config.encoder_list, head) {
struct dcb_entry *slave_dcb = nouveau_encoder(slave)->dcb;
if (slave_dcb->type == OUTPUT_TMDS && get_slave_funcs(slave) &&
slave_dcb->tmdsconf.slave_addr == dcb->tmdsconf.slave_addr)
return slave;
}
return NULL;
}
static bool nv04_dfp_mode_fixup(struct drm_encoder *encoder, static bool nv04_dfp_mode_fixup(struct drm_encoder *encoder,
struct drm_display_mode *mode, struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode) struct drm_display_mode *adjusted_mode)
@ -429,6 +461,11 @@ static void nv04_dfp_commit(struct drm_encoder *encoder)
else else
NVWriteRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL + nv04_dac_output_offset(encoder), 0x00100000); NVWriteRAMDAC(dev, 0, NV_PRAMDAC_TEST_CONTROL + nv04_dac_output_offset(encoder), 0x00100000);
/* Init external transmitters */
if (get_tmds_slave(encoder))
get_slave_funcs(get_tmds_slave(encoder))->mode_set(
encoder, &nv_encoder->mode, &nv_encoder->mode);
helper->dpms(encoder, DRM_MODE_DPMS_ON); helper->dpms(encoder, DRM_MODE_DPMS_ON);
NV_INFO(dev, "Output %s is running on CRTC %d using output %c\n", NV_INFO(dev, "Output %s is running on CRTC %d using output %c\n",
@ -550,10 +587,42 @@ static void nv04_dfp_destroy(struct drm_encoder *encoder)
NV_DEBUG_KMS(encoder->dev, "\n"); NV_DEBUG_KMS(encoder->dev, "\n");
if (get_slave_funcs(encoder))
get_slave_funcs(encoder)->destroy(encoder);
drm_encoder_cleanup(encoder); drm_encoder_cleanup(encoder);
kfree(nv_encoder); kfree(nv_encoder);
} }
static void nv04_tmds_slave_init(struct drm_encoder *encoder)
{
struct drm_device *dev = encoder->dev;
struct dcb_entry *dcb = nouveau_encoder(encoder)->dcb;
struct nouveau_i2c_chan *i2c = nouveau_i2c_find(dev, 2);
struct i2c_board_info info[] = {
{
.type = "sil164",
.addr = (dcb->tmdsconf.slave_addr == 0x7 ? 0x3a : 0x38),
.platform_data = &(struct sil164_encoder_params) {
SIL164_INPUT_EDGE_RISING
}
},
{ }
};
int type;
if (!nv_gf4_disp_arch(dev) || !i2c ||
get_tmds_slave(encoder))
return;
type = nouveau_i2c_identify(dev, "TMDS transmitter", info, 2);
if (type < 0)
return;
drm_i2c_encoder_init(dev, to_encoder_slave(encoder),
&i2c->adapter, &info[type]);
}
static const struct drm_encoder_helper_funcs nv04_lvds_helper_funcs = { static const struct drm_encoder_helper_funcs nv04_lvds_helper_funcs = {
.dpms = nv04_lvds_dpms, .dpms = nv04_lvds_dpms,
.save = nv04_dfp_save, .save = nv04_dfp_save,
@ -616,6 +685,10 @@ nv04_dfp_create(struct drm_connector *connector, struct dcb_entry *entry)
encoder->possible_crtcs = entry->heads; encoder->possible_crtcs = entry->heads;
encoder->possible_clones = 0; encoder->possible_clones = 0;
if (entry->type == OUTPUT_TMDS &&
entry->location != DCB_LOC_ON_CHIP)
nv04_tmds_slave_init(encoder);
drm_mode_connector_attach_encoder(connector, encoder); drm_mode_connector_attach_encoder(connector, encoder);
return 0; return 0;
} }

View File

@ -89,7 +89,7 @@ static void nv04_tv_dpms(struct drm_encoder *encoder, int mode)
NVWriteRAMDAC(dev, 0, NV_PRAMDAC_PLL_COEFF_SELECT, state->pllsel); NVWriteRAMDAC(dev, 0, NV_PRAMDAC_PLL_COEFF_SELECT, state->pllsel);
to_encoder_slave(encoder)->slave_funcs->dpms(encoder, mode); get_slave_funcs(encoder)->dpms(encoder, mode);
} }
static void nv04_tv_bind(struct drm_device *dev, int head, bool bind) static void nv04_tv_bind(struct drm_device *dev, int head, bool bind)
@ -152,7 +152,7 @@ static void nv04_tv_mode_set(struct drm_encoder *encoder,
regp->tv_vskew = 1; regp->tv_vskew = 1;
regp->tv_vsync_delay = 1; regp->tv_vsync_delay = 1;
to_encoder_slave(encoder)->slave_funcs->mode_set(encoder, mode, adjusted_mode); get_slave_funcs(encoder)->mode_set(encoder, mode, adjusted_mode);
} }
static void nv04_tv_commit(struct drm_encoder *encoder) static void nv04_tv_commit(struct drm_encoder *encoder)
@ -171,8 +171,7 @@ static void nv04_tv_commit(struct drm_encoder *encoder)
static void nv04_tv_destroy(struct drm_encoder *encoder) static void nv04_tv_destroy(struct drm_encoder *encoder)
{ {
to_encoder_slave(encoder)->slave_funcs->destroy(encoder); get_slave_funcs(encoder)->destroy(encoder);
drm_encoder_cleanup(encoder); drm_encoder_cleanup(encoder);
kfree(encoder->helper_private); kfree(encoder->helper_private);
@ -229,7 +228,7 @@ nv04_tv_create(struct drm_connector *connector, struct dcb_entry *entry)
goto fail_cleanup; goto fail_cleanup;
/* Fill the function pointers */ /* Fill the function pointers */
sfuncs = to_encoder_slave(encoder)->slave_funcs; sfuncs = get_slave_funcs(encoder);
*hfuncs = (struct drm_encoder_helper_funcs) { *hfuncs = (struct drm_encoder_helper_funcs) {
.dpms = nv04_tv_dpms, .dpms = nv04_tv_dpms,
@ -243,7 +242,6 @@ nv04_tv_create(struct drm_connector *connector, struct dcb_entry *entry)
}; };
/* Attach it to the specified connector. */ /* Attach it to the specified connector. */
sfuncs->set_config(encoder, nv04_tv_encoder_info[type].platform_data);
sfuncs->create_resources(encoder, connector); sfuncs->create_resources(encoder, connector);
drm_mode_connector_attach_encoder(connector, encoder); drm_mode_connector_attach_encoder(connector, encoder);

View File

@ -43,51 +43,51 @@ struct pipe_state {
}; };
static int nv10_graph_ctx_regs[] = { static int nv10_graph_ctx_regs[] = {
NV10_PGRAPH_CTX_SWITCH1, NV10_PGRAPH_CTX_SWITCH(0),
NV10_PGRAPH_CTX_SWITCH2, NV10_PGRAPH_CTX_SWITCH(1),
NV10_PGRAPH_CTX_SWITCH3, NV10_PGRAPH_CTX_SWITCH(2),
NV10_PGRAPH_CTX_SWITCH4, NV10_PGRAPH_CTX_SWITCH(3),
NV10_PGRAPH_CTX_SWITCH5, NV10_PGRAPH_CTX_SWITCH(4),
NV10_PGRAPH_CTX_CACHE1, /* 8 values from 0x400160 to 0x40017c */ NV10_PGRAPH_CTX_CACHE(0, 0),
NV10_PGRAPH_CTX_CACHE2, /* 8 values from 0x400180 to 0x40019c */ NV10_PGRAPH_CTX_CACHE(0, 1),
NV10_PGRAPH_CTX_CACHE3, /* 8 values from 0x4001a0 to 0x4001bc */ NV10_PGRAPH_CTX_CACHE(0, 2),
NV10_PGRAPH_CTX_CACHE4, /* 8 values from 0x4001c0 to 0x4001dc */ NV10_PGRAPH_CTX_CACHE(0, 3),
NV10_PGRAPH_CTX_CACHE5, /* 8 values from 0x4001e0 to 0x4001fc */ NV10_PGRAPH_CTX_CACHE(0, 4),
0x00400164, NV10_PGRAPH_CTX_CACHE(1, 0),
0x00400184, NV10_PGRAPH_CTX_CACHE(1, 1),
0x004001a4, NV10_PGRAPH_CTX_CACHE(1, 2),
0x004001c4, NV10_PGRAPH_CTX_CACHE(1, 3),
0x004001e4, NV10_PGRAPH_CTX_CACHE(1, 4),
0x00400168, NV10_PGRAPH_CTX_CACHE(2, 0),
0x00400188, NV10_PGRAPH_CTX_CACHE(2, 1),
0x004001a8, NV10_PGRAPH_CTX_CACHE(2, 2),
0x004001c8, NV10_PGRAPH_CTX_CACHE(2, 3),
0x004001e8, NV10_PGRAPH_CTX_CACHE(2, 4),
0x0040016c, NV10_PGRAPH_CTX_CACHE(3, 0),
0x0040018c, NV10_PGRAPH_CTX_CACHE(3, 1),
0x004001ac, NV10_PGRAPH_CTX_CACHE(3, 2),
0x004001cc, NV10_PGRAPH_CTX_CACHE(3, 3),
0x004001ec, NV10_PGRAPH_CTX_CACHE(3, 4),
0x00400170, NV10_PGRAPH_CTX_CACHE(4, 0),
0x00400190, NV10_PGRAPH_CTX_CACHE(4, 1),
0x004001b0, NV10_PGRAPH_CTX_CACHE(4, 2),
0x004001d0, NV10_PGRAPH_CTX_CACHE(4, 3),
0x004001f0, NV10_PGRAPH_CTX_CACHE(4, 4),
0x00400174, NV10_PGRAPH_CTX_CACHE(5, 0),
0x00400194, NV10_PGRAPH_CTX_CACHE(5, 1),
0x004001b4, NV10_PGRAPH_CTX_CACHE(5, 2),
0x004001d4, NV10_PGRAPH_CTX_CACHE(5, 3),
0x004001f4, NV10_PGRAPH_CTX_CACHE(5, 4),
0x00400178, NV10_PGRAPH_CTX_CACHE(6, 0),
0x00400198, NV10_PGRAPH_CTX_CACHE(6, 1),
0x004001b8, NV10_PGRAPH_CTX_CACHE(6, 2),
0x004001d8, NV10_PGRAPH_CTX_CACHE(6, 3),
0x004001f8, NV10_PGRAPH_CTX_CACHE(6, 4),
0x0040017c, NV10_PGRAPH_CTX_CACHE(7, 0),
0x0040019c, NV10_PGRAPH_CTX_CACHE(7, 1),
0x004001bc, NV10_PGRAPH_CTX_CACHE(7, 2),
0x004001dc, NV10_PGRAPH_CTX_CACHE(7, 3),
0x004001fc, NV10_PGRAPH_CTX_CACHE(7, 4),
NV10_PGRAPH_CTX_USER, NV10_PGRAPH_CTX_USER,
NV04_PGRAPH_DMA_START_0, NV04_PGRAPH_DMA_START_0,
NV04_PGRAPH_DMA_START_1, NV04_PGRAPH_DMA_START_1,
@ -653,6 +653,78 @@ static int nv17_graph_ctx_regs_find_offset(struct drm_device *dev, int reg)
return -1; return -1;
} }
static void nv10_graph_load_dma_vtxbuf(struct nouveau_channel *chan,
uint32_t inst)
{
struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
uint32_t st2, st2_dl, st2_dh, fifo_ptr, fifo[0x60/4];
uint32_t ctx_user, ctx_switch[5];
int i, subchan = -1;
/* NV10TCL_DMA_VTXBUF (method 0x18c) modifies hidden state
* that cannot be restored via MMIO. Do it through the FIFO
* instead.
*/
/* Look for a celsius object */
for (i = 0; i < 8; i++) {
int class = nv_rd32(dev, NV10_PGRAPH_CTX_CACHE(i, 0)) & 0xfff;
if (class == 0x56 || class == 0x96 || class == 0x99) {
subchan = i;
break;
}
}
if (subchan < 0 || !inst)
return;
/* Save the current ctx object */
ctx_user = nv_rd32(dev, NV10_PGRAPH_CTX_USER);
for (i = 0; i < 5; i++)
ctx_switch[i] = nv_rd32(dev, NV10_PGRAPH_CTX_SWITCH(i));
/* Save the FIFO state */
st2 = nv_rd32(dev, NV10_PGRAPH_FFINTFC_ST2);
st2_dl = nv_rd32(dev, NV10_PGRAPH_FFINTFC_ST2_DL);
st2_dh = nv_rd32(dev, NV10_PGRAPH_FFINTFC_ST2_DH);
fifo_ptr = nv_rd32(dev, NV10_PGRAPH_FFINTFC_FIFO_PTR);
for (i = 0; i < ARRAY_SIZE(fifo); i++)
fifo[i] = nv_rd32(dev, 0x4007a0 + 4 * i);
/* Switch to the celsius subchannel */
for (i = 0; i < 5; i++)
nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH(i),
nv_rd32(dev, NV10_PGRAPH_CTX_CACHE(subchan, i)));
nv_mask(dev, NV10_PGRAPH_CTX_USER, 0xe000, subchan << 13);
/* Inject NV10TCL_DMA_VTXBUF */
nv_wr32(dev, NV10_PGRAPH_FFINTFC_FIFO_PTR, 0);
nv_wr32(dev, NV10_PGRAPH_FFINTFC_ST2,
0x2c000000 | chan->id << 20 | subchan << 16 | 0x18c);
nv_wr32(dev, NV10_PGRAPH_FFINTFC_ST2_DL, inst);
nv_mask(dev, NV10_PGRAPH_CTX_CONTROL, 0, 0x10000);
pgraph->fifo_access(dev, true);
pgraph->fifo_access(dev, false);
/* Restore the FIFO state */
for (i = 0; i < ARRAY_SIZE(fifo); i++)
nv_wr32(dev, 0x4007a0 + 4 * i, fifo[i]);
nv_wr32(dev, NV10_PGRAPH_FFINTFC_FIFO_PTR, fifo_ptr);
nv_wr32(dev, NV10_PGRAPH_FFINTFC_ST2, st2);
nv_wr32(dev, NV10_PGRAPH_FFINTFC_ST2_DL, st2_dl);
nv_wr32(dev, NV10_PGRAPH_FFINTFC_ST2_DH, st2_dh);
/* Restore the current ctx object */
for (i = 0; i < 5; i++)
nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH(i), ctx_switch[i]);
nv_wr32(dev, NV10_PGRAPH_CTX_USER, ctx_user);
}
int nv10_graph_load_context(struct nouveau_channel *chan) int nv10_graph_load_context(struct nouveau_channel *chan)
{ {
struct drm_device *dev = chan->dev; struct drm_device *dev = chan->dev;
@ -670,6 +742,8 @@ int nv10_graph_load_context(struct nouveau_channel *chan)
} }
nv10_graph_load_pipe(chan); nv10_graph_load_pipe(chan);
nv10_graph_load_dma_vtxbuf(chan, (nv_rd32(dev, NV10_PGRAPH_GLOBALSTATE1)
& 0xffff));
nv_wr32(dev, NV10_PGRAPH_CTX_CONTROL, 0x10010100); nv_wr32(dev, NV10_PGRAPH_CTX_CONTROL, 0x10010100);
tmp = nv_rd32(dev, NV10_PGRAPH_CTX_USER); tmp = nv_rd32(dev, NV10_PGRAPH_CTX_USER);
@ -856,10 +930,11 @@ int nv10_graph_init(struct drm_device *dev)
for (i = 0; i < NV10_PFB_TILE__SIZE; i++) for (i = 0; i < NV10_PFB_TILE__SIZE; i++)
nv10_graph_set_region_tiling(dev, i, 0, 0, 0); nv10_graph_set_region_tiling(dev, i, 0, 0, 0);
nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH1, 0x00000000); nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH(0), 0x00000000);
nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH2, 0x00000000); nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH(1), 0x00000000);
nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH3, 0x00000000); nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH(2), 0x00000000);
nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH4, 0x00000000); nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH(3), 0x00000000);
nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH(4), 0x00000000);
nv_wr32(dev, NV10_PGRAPH_STATE, 0xFFFFFFFF); nv_wr32(dev, NV10_PGRAPH_STATE, 0xFFFFFFFF);
tmp = nv_rd32(dev, NV10_PGRAPH_CTX_USER) & 0x00ffffff; tmp = nv_rd32(dev, NV10_PGRAPH_CTX_USER) & 0x00ffffff;

View File

@ -30,15 +30,25 @@
#include "nouveau_drm.h" #include "nouveau_drm.h"
static int static int
calc_ref(int b, int l, int i) calc_bias(struct drm_device *dev, int k, int i, int j)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
int b = (dev_priv->chipset > 0x30 ?
nv_rd32(dev, 0x122c + 0x10 * k + 0x4 * j) >> (4 * (i ^ 1)) :
0) & 0xf;
return 2 * (b & 0x8 ? b - 0x10 : b);
}
static int
calc_ref(struct drm_device *dev, int l, int k, int i)
{ {
int j, x = 0; int j, x = 0;
for (j = 0; j < 4; j++) { for (j = 0; j < 4; j++) {
int n = (b >> (8 * j) & 0xf); int m = (l >> (8 * i) & 0xff) + calc_bias(dev, k, i, j);
int m = (l >> (8 * i) & 0xff) + 2 * (n & 0x8 ? n - 0x10 : n);
x |= (0x80 | (m & 0x1f)) << (8 * j); x |= (0x80 | clamp(m, 0, 0x1f)) << (8 * j);
} }
return x; return x;
@ -63,18 +73,16 @@ nv30_fb_init(struct drm_device *dev)
dev_priv->chipset == 0x35) { dev_priv->chipset == 0x35) {
/* Related to ROP count */ /* Related to ROP count */
int n = (dev_priv->chipset == 0x31 ? 2 : 4); 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); int l = nv_rd32(dev, 0x1003d0);
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
for (j = 0; j < 3; j++) for (j = 0; j < 3; j++)
nv_wr32(dev, 0x10037c + 0xc * i + 0x4 * j, nv_wr32(dev, 0x10037c + 0xc * i + 0x4 * j,
calc_ref(b, l, j)); calc_ref(dev, l, 0, j));
for (j = 0; j < 2; j++) for (j = 0; j < 2; j++)
nv_wr32(dev, 0x1003ac + 0x8 * i + 0x4 * j, nv_wr32(dev, 0x1003ac + 0x8 * i + 0x4 * j,
calc_ref(b, l, j)); calc_ref(dev, l, 1, j));
} }
} }

View File

@ -264,11 +264,16 @@ nv50_crtc_set_scale(struct nouveau_crtc *nv_crtc, int scaling_mode, bool update)
int int
nv50_crtc_set_clock(struct drm_device *dev, int head, int pclk) nv50_crtc_set_clock(struct drm_device *dev, int head, int pclk)
{ {
uint32_t reg = NV50_PDISPLAY_CRTC_CLK_CTRL1(head); struct drm_nouveau_private *dev_priv = dev->dev_private;
struct pll_lims pll; struct pll_lims pll;
uint32_t reg1, reg2; uint32_t reg, reg1, reg2;
int ret, N1, M1, N2, M2, P; int ret, N1, M1, N2, M2, P;
if (dev_priv->chipset < NV_C0)
reg = NV50_PDISPLAY_CRTC_CLK_CTRL1(head);
else
reg = 0x614140 + (head * 0x800);
ret = get_pll_limits(dev, reg, &pll); ret = get_pll_limits(dev, reg, &pll);
if (ret) if (ret)
return ret; return ret;
@ -286,7 +291,8 @@ nv50_crtc_set_clock(struct drm_device *dev, int head, int pclk)
nv_wr32(dev, reg, 0x10000611); nv_wr32(dev, reg, 0x10000611);
nv_wr32(dev, reg + 4, reg1 | (M1 << 16) | N1); nv_wr32(dev, reg + 4, reg1 | (M1 << 16) | N1);
nv_wr32(dev, reg + 8, reg2 | (P << 28) | (M2 << 16) | N2); nv_wr32(dev, reg + 8, reg2 | (P << 28) | (M2 << 16) | N2);
} else { } else
if (dev_priv->chipset < NV_C0) {
ret = nv50_calc_pll2(dev, &pll, pclk, &N1, &N2, &M1, &P); ret = nv50_calc_pll2(dev, &pll, pclk, &N1, &N2, &M1, &P);
if (ret <= 0) if (ret <= 0)
return 0; return 0;
@ -298,6 +304,17 @@ nv50_crtc_set_clock(struct drm_device *dev, int head, int pclk)
nv_wr32(dev, reg, 0x50000610); nv_wr32(dev, reg, 0x50000610);
nv_wr32(dev, reg + 4, reg1 | (P << 16) | (M1 << 8) | N1); nv_wr32(dev, reg + 4, reg1 | (P << 16) | (M1 << 8) | N1);
nv_wr32(dev, reg + 8, N2); nv_wr32(dev, reg + 8, N2);
} else {
ret = nv50_calc_pll2(dev, &pll, pclk, &N1, &N2, &M1, &P);
if (ret <= 0)
return 0;
NV_DEBUG(dev, "pclk %d out %d N %d fN 0x%04x M %d P %d\n",
pclk, ret, N1, N2, M1, P);
nv_mask(dev, reg + 0x0c, 0x00000000, 0x00000100);
nv_wr32(dev, reg + 0x04, (P << 16) | (N1 << 8) | M1);
nv_wr32(dev, reg + 0x10, N2 << 16);
} }
return 0; return 0;

View File

@ -76,7 +76,10 @@ nv50_evo_dmaobj_new(struct nouveau_channel *evo, uint32_t class, uint32_t name,
nv_wo32(dev, obj, 2, offset); nv_wo32(dev, obj, 2, offset);
nv_wo32(dev, obj, 3, 0x00000000); nv_wo32(dev, obj, 3, 0x00000000);
nv_wo32(dev, obj, 4, 0x00000000); nv_wo32(dev, obj, 4, 0x00000000);
if (dev_priv->card_type < NV_C0)
nv_wo32(dev, obj, 5, 0x00010000); nv_wo32(dev, obj, 5, 0x00010000);
else
nv_wo32(dev, obj, 5, 0x00020000);
dev_priv->engine.instmem.flush(dev); dev_priv->engine.instmem.flush(dev);
return 0; return 0;

View File

@ -0,0 +1,38 @@
/*
* Copyright 2010 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors: Ben Skeggs
*/
#include "drmP.h"
#include "nouveau_drv.h"
int
nvc0_fb_init(struct drm_device *dev)
{
return 0;
}
void
nvc0_fb_takedown(struct drm_device *dev)
{
}

View File

@ -0,0 +1,96 @@
/*
* Copyright 2010 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors: Ben Skeggs
*/
#include "drmP.h"
#include "nouveau_drv.h"
void
nvc0_fifo_disable(struct drm_device *dev)
{
}
void
nvc0_fifo_enable(struct drm_device *dev)
{
}
bool
nvc0_fifo_reassign(struct drm_device *dev, bool enable)
{
return false;
}
bool
nvc0_fifo_cache_flush(struct drm_device *dev)
{
return true;
}
bool
nvc0_fifo_cache_pull(struct drm_device *dev, bool enable)
{
return false;
}
int
nvc0_fifo_channel_id(struct drm_device *dev)
{
return 127;
}
int
nvc0_fifo_create_context(struct nouveau_channel *chan)
{
return 0;
}
void
nvc0_fifo_destroy_context(struct nouveau_channel *chan)
{
}
int
nvc0_fifo_load_context(struct nouveau_channel *chan)
{
return 0;
}
int
nvc0_fifo_unload_context(struct drm_device *dev)
{
return 0;
}
void
nvc0_fifo_takedown(struct drm_device *dev)
{
}
int
nvc0_fifo_init(struct drm_device *dev)
{
return 0;
}

View File

@ -0,0 +1,75 @@
/*
* Copyright 2010 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors: Ben Skeggs
*/
#include "drmP.h"
#include "nouveau_drv.h"
void
nvc0_graph_fifo_access(struct drm_device *dev, bool enabled)
{
}
struct nouveau_channel *
nvc0_graph_channel(struct drm_device *dev)
{
return NULL;
}
int
nvc0_graph_create_context(struct nouveau_channel *chan)
{
return 0;
}
void
nvc0_graph_destroy_context(struct nouveau_channel *chan)
{
}
int
nvc0_graph_load_context(struct nouveau_channel *chan)
{
return 0;
}
int
nvc0_graph_unload_context(struct drm_device *dev)
{
return 0;
}
void
nvc0_graph_takedown(struct drm_device *dev)
{
}
int
nvc0_graph_init(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
dev_priv->engine.graph.accel_blocked = true;
return 0;
}

View File

@ -0,0 +1,232 @@
/*
* Copyright 2010 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors: Ben Skeggs
*/
#include "drmP.h"
#include "nouveau_drv.h"
int
nvc0_instmem_populate(struct drm_device *dev, struct nouveau_gpuobj *gpuobj,
uint32_t *size)
{
int ret;
*size = ALIGN(*size, 4096);
if (*size == 0)
return -EINVAL;
ret = nouveau_bo_new(dev, NULL, *size, 0, TTM_PL_FLAG_VRAM, 0, 0x0000,
true, false, &gpuobj->im_backing);
if (ret) {
NV_ERROR(dev, "error getting PRAMIN backing pages: %d\n", ret);
return ret;
}
ret = nouveau_bo_pin(gpuobj->im_backing, TTM_PL_FLAG_VRAM);
if (ret) {
NV_ERROR(dev, "error pinning PRAMIN backing VRAM: %d\n", ret);
nouveau_bo_ref(NULL, &gpuobj->im_backing);
return ret;
}
gpuobj->im_backing_start = gpuobj->im_backing->bo.mem.mm_node->start;
gpuobj->im_backing_start <<= PAGE_SHIFT;
return 0;
}
void
nvc0_instmem_clear(struct drm_device *dev, struct nouveau_gpuobj *gpuobj)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
if (gpuobj && gpuobj->im_backing) {
if (gpuobj->im_bound)
dev_priv->engine.instmem.unbind(dev, gpuobj);
nouveau_bo_unpin(gpuobj->im_backing);
nouveau_bo_ref(NULL, &gpuobj->im_backing);
gpuobj->im_backing = NULL;
}
}
int
nvc0_instmem_bind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
uint32_t pte, pte_end;
uint64_t vram;
if (!gpuobj->im_backing || !gpuobj->im_pramin || gpuobj->im_bound)
return -EINVAL;
NV_DEBUG(dev, "st=0x%lx sz=0x%lx\n",
gpuobj->im_pramin->start, gpuobj->im_pramin->size);
pte = gpuobj->im_pramin->start >> 12;
pte_end = (gpuobj->im_pramin->size >> 12) + pte;
vram = gpuobj->im_backing_start;
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);
while (pte < pte_end) {
nv_wr32(dev, 0x702000 + (pte * 8), (vram >> 8) | 1);
nv_wr32(dev, 0x702004 + (pte * 8), 0);
vram += 4096;
pte++;
}
dev_priv->engine.instmem.flush(dev);
if (1) {
u32 chan = nv_rd32(dev, 0x1700) << 16;
nv_wr32(dev, 0x100cb8, (chan + 0x1000) >> 8);
nv_wr32(dev, 0x100cbc, 0x80000005);
}
gpuobj->im_bound = 1;
return 0;
}
int
nvc0_instmem_unbind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
uint32_t pte, pte_end;
if (gpuobj->im_bound == 0)
return -EINVAL;
pte = gpuobj->im_pramin->start >> 12;
pte_end = (gpuobj->im_pramin->size >> 12) + pte;
while (pte < pte_end) {
nv_wr32(dev, 0x702000 + (pte * 8), 0);
nv_wr32(dev, 0x702004 + (pte * 8), 0);
pte++;
}
dev_priv->engine.instmem.flush(dev);
gpuobj->im_bound = 0;
return 0;
}
void
nvc0_instmem_flush(struct drm_device *dev)
{
nv_wr32(dev, 0x070000, 1);
if (!nv_wait(0x070000, 0x00000002, 0x00000000))
NV_ERROR(dev, "PRAMIN flush timeout\n");
}
int
nvc0_instmem_suspend(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
int i;
dev_priv->susres.ramin_copy = vmalloc(65536);
if (!dev_priv->susres.ramin_copy)
return -ENOMEM;
for (i = 0x700000; i < 0x710000; i += 4)
dev_priv->susres.ramin_copy[i/4] = nv_rd32(dev, i);
return 0;
}
void
nvc0_instmem_resume(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
u64 chan;
int i;
chan = dev_priv->vram_size - dev_priv->ramin_rsvd_vram;
nv_wr32(dev, 0x001700, chan >> 16);
for (i = 0x700000; i < 0x710000; i += 4)
nv_wr32(dev, i, dev_priv->susres.ramin_copy[i/4]);
vfree(dev_priv->susres.ramin_copy);
dev_priv->susres.ramin_copy = NULL;
nv_wr32(dev, 0x001714, 0xc0000000 | (chan >> 12));
}
int
nvc0_instmem_init(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
u64 chan, pgt3, imem, lim3 = dev_priv->ramin_size - 1;
int ret, i;
dev_priv->ramin_rsvd_vram = 1 * 1024 * 1024;
chan = dev_priv->vram_size - dev_priv->ramin_rsvd_vram;
imem = 4096 + 4096 + 32768;
nv_wr32(dev, 0x001700, chan >> 16);
/* channel setup */
nv_wr32(dev, 0x700200, lower_32_bits(chan + 0x1000));
nv_wr32(dev, 0x700204, upper_32_bits(chan + 0x1000));
nv_wr32(dev, 0x700208, lower_32_bits(lim3));
nv_wr32(dev, 0x70020c, upper_32_bits(lim3));
/* point pgd -> pgt */
nv_wr32(dev, 0x701000, 0);
nv_wr32(dev, 0x701004, ((chan + 0x2000) >> 8) | 1);
/* point pgt -> physical vram for channel */
pgt3 = 0x2000;
for (i = 0; i < dev_priv->ramin_rsvd_vram; i += 4096, pgt3 += 8) {
nv_wr32(dev, 0x700000 + pgt3, ((chan + i) >> 8) | 1);
nv_wr32(dev, 0x700004 + pgt3, 0);
}
/* clear rest of pgt */
for (; i < dev_priv->ramin_size; i += 4096, pgt3 += 8) {
nv_wr32(dev, 0x700000 + pgt3, 0);
nv_wr32(dev, 0x700004 + pgt3, 0);
}
/* point bar3 at the channel */
nv_wr32(dev, 0x001714, 0xc0000000 | (chan >> 12));
/* Global PRAMIN heap */
ret = drm_mm_init(&dev_priv->ramin_heap, imem,
dev_priv->ramin_size - imem);
if (ret) {
NV_ERROR(dev, "Failed to init RAMIN heap\n");
return -ENOMEM;
}
/*XXX: incorrect, but needed to make hash func "work" */
dev_priv->ramht_offset = 0x10000;
dev_priv->ramht_bits = 9;
dev_priv->ramht_size = (1 << dev_priv->ramht_bits);
return 0;
}
void
nvc0_instmem_takedown(struct drm_device *dev)
{
}