Merge remote branch 'nouveau/for-airlied' of /ssd/git/drm-nouveau-next into drm-fixes
* 'nouveau/for-airlied' of /ssd/git/drm-nouveau-next: (25 commits) nouveau: Acknowledge HPD irq in handler, not bottom half drm/nouveau: Fix a few confusions between "chipset" and "card_type". drm/nouveau: don't expose backlight control when available through ACPI drm/nouveau/pm: improve memtiming mappings drm/nouveau: Make PCIE GART size depend on the available RAMIN space. drm/nouveau: Return error from nouveau_gpuobj_new if we're out of RAMIN. drm/nouveau: Fix compilation issues in nouveau_pm when CONFIG_HWMON is not set drm/nouveau: Don't use load detection for connector polling. drm/nv10-nv20: Fix instability after MPLL changes. drm/nv50: implement possible workaround for NV86 PGRAPH TLB flush hang drm/nouveau: Don't poll LVDS outputs. drm/nouveau: Use "force" to decide if analog load detection is ok or not. drm/nv04: Fix scanout over the 16MB mark. drm/nouveau: fix nv40 pcie gart size drm/nva3: fix overflow in fixed point math used for pll calculation drm/nv10: Balance RTs expected to be accessed simultaneously by the 3d engine. drm/nouveau: Expose some BO usage flags to userspace. drm/nouveau: Reduce severity of the unknown getparam error. drm/nouveau: Avoid lock dependency between ramht and ramin spinlocks. drm/nouveau: Some random cleanups. ...
This commit is contained in:
commit
9a03d3487a
|
@ -31,6 +31,7 @@
|
|||
*/
|
||||
|
||||
#include <linux/backlight.h>
|
||||
#include <linux/acpi.h>
|
||||
|
||||
#include "drmP.h"
|
||||
#include "nouveau_drv.h"
|
||||
|
@ -136,6 +137,14 @@ int nouveau_backlight_init(struct drm_device *dev)
|
|||
{
|
||||
struct drm_nouveau_private *dev_priv = dev->dev_private;
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
if (acpi_video_backlight_support()) {
|
||||
NV_INFO(dev, "ACPI backlight interface available, "
|
||||
"not registering our own\n");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
switch (dev_priv->card_type) {
|
||||
case NV_40:
|
||||
return nouveau_nv40_backlight_init(dev);
|
||||
|
|
|
@ -6829,7 +6829,7 @@ nouveau_bios_posted(struct drm_device *dev)
|
|||
struct drm_nouveau_private *dev_priv = dev->dev_private;
|
||||
unsigned htotal;
|
||||
|
||||
if (dev_priv->chipset >= NV_50) {
|
||||
if (dev_priv->card_type >= NV_50) {
|
||||
if (NVReadVgaCrtc(dev, 0, 0x00) == 0 &&
|
||||
NVReadVgaCrtc(dev, 0, 0x1a) == 0)
|
||||
return false;
|
||||
|
|
|
@ -143,8 +143,10 @@ nouveau_bo_new(struct drm_device *dev, struct nouveau_channel *chan,
|
|||
nvbo->no_vm = no_vm;
|
||||
nvbo->tile_mode = tile_mode;
|
||||
nvbo->tile_flags = tile_flags;
|
||||
nvbo->bo.bdev = &dev_priv->ttm.bdev;
|
||||
|
||||
nouveau_bo_fixup_align(dev, tile_mode, tile_flags, &align, &size);
|
||||
nouveau_bo_fixup_align(dev, tile_mode, nouveau_bo_tile_layout(nvbo),
|
||||
&align, &size);
|
||||
align >>= PAGE_SHIFT;
|
||||
|
||||
nouveau_bo_placement_set(nvbo, flags, 0);
|
||||
|
@ -176,6 +178,31 @@ set_placement_list(uint32_t *pl, unsigned *n, uint32_t type, uint32_t flags)
|
|||
pl[(*n)++] = TTM_PL_FLAG_SYSTEM | flags;
|
||||
}
|
||||
|
||||
static void
|
||||
set_placement_range(struct nouveau_bo *nvbo, uint32_t type)
|
||||
{
|
||||
struct drm_nouveau_private *dev_priv = nouveau_bdev(nvbo->bo.bdev);
|
||||
|
||||
if (dev_priv->card_type == NV_10 &&
|
||||
nvbo->tile_mode && (type & TTM_PL_FLAG_VRAM)) {
|
||||
/*
|
||||
* Make sure that the color and depth buffers are handled
|
||||
* by independent memory controller units. Up to a 9x
|
||||
* speed up when alpha-blending and depth-test are enabled
|
||||
* at the same time.
|
||||
*/
|
||||
int vram_pages = dev_priv->vram_size >> PAGE_SHIFT;
|
||||
|
||||
if (nvbo->tile_flags & NOUVEAU_GEM_TILE_ZETA) {
|
||||
nvbo->placement.fpfn = vram_pages / 2;
|
||||
nvbo->placement.lpfn = ~0;
|
||||
} else {
|
||||
nvbo->placement.fpfn = 0;
|
||||
nvbo->placement.lpfn = vram_pages / 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nouveau_bo_placement_set(struct nouveau_bo *nvbo, uint32_t type, uint32_t busy)
|
||||
{
|
||||
|
@ -190,6 +217,8 @@ nouveau_bo_placement_set(struct nouveau_bo *nvbo, uint32_t type, uint32_t busy)
|
|||
pl->busy_placement = nvbo->busy_placements;
|
||||
set_placement_list(nvbo->busy_placements, &pl->num_busy_placement,
|
||||
type | busy, flags);
|
||||
|
||||
set_placement_range(nvbo, type);
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -525,7 +554,8 @@ nv50_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo,
|
|||
stride = 16 * 4;
|
||||
height = amount / stride;
|
||||
|
||||
if (new_mem->mem_type == TTM_PL_VRAM && nvbo->tile_flags) {
|
||||
if (new_mem->mem_type == TTM_PL_VRAM &&
|
||||
nouveau_bo_tile_layout(nvbo)) {
|
||||
ret = RING_SPACE(chan, 8);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -546,7 +576,8 @@ nv50_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo,
|
|||
BEGIN_RING(chan, NvSubM2MF, 0x0200, 1);
|
||||
OUT_RING (chan, 1);
|
||||
}
|
||||
if (old_mem->mem_type == TTM_PL_VRAM && nvbo->tile_flags) {
|
||||
if (old_mem->mem_type == TTM_PL_VRAM &&
|
||||
nouveau_bo_tile_layout(nvbo)) {
|
||||
ret = RING_SPACE(chan, 8);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -753,7 +784,8 @@ nouveau_bo_vm_bind(struct ttm_buffer_object *bo, struct ttm_mem_reg *new_mem,
|
|||
if (dev_priv->card_type == NV_50) {
|
||||
ret = nv50_mem_vm_bind_linear(dev,
|
||||
offset + dev_priv->vm_vram_base,
|
||||
new_mem->size, nvbo->tile_flags,
|
||||
new_mem->size,
|
||||
nouveau_bo_tile_layout(nvbo),
|
||||
offset);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -894,7 +926,8 @@ nouveau_ttm_fault_reserve_notify(struct ttm_buffer_object *bo)
|
|||
* nothing to do here.
|
||||
*/
|
||||
if (bo->mem.mem_type != TTM_PL_VRAM) {
|
||||
if (dev_priv->card_type < NV_50 || !nvbo->tile_flags)
|
||||
if (dev_priv->card_type < NV_50 ||
|
||||
!nouveau_bo_tile_layout(nvbo))
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -281,7 +281,7 @@ detect_analog:
|
|||
nv_encoder = find_encoder_by_type(connector, OUTPUT_ANALOG);
|
||||
if (!nv_encoder && !nouveau_tv_disable)
|
||||
nv_encoder = find_encoder_by_type(connector, OUTPUT_TV);
|
||||
if (nv_encoder) {
|
||||
if (nv_encoder && force) {
|
||||
struct drm_encoder *encoder = to_drm_encoder(nv_encoder);
|
||||
struct drm_encoder_helper_funcs *helper =
|
||||
encoder->helper_private;
|
||||
|
@ -641,11 +641,28 @@ nouveau_connector_get_modes(struct drm_connector *connector)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static unsigned
|
||||
get_tmds_link_bandwidth(struct drm_connector *connector)
|
||||
{
|
||||
struct nouveau_connector *nv_connector = nouveau_connector(connector);
|
||||
struct drm_nouveau_private *dev_priv = connector->dev->dev_private;
|
||||
struct dcb_entry *dcb = nv_connector->detected_encoder->dcb;
|
||||
|
||||
if (dcb->location != DCB_LOC_ON_CHIP ||
|
||||
dev_priv->chipset >= 0x46)
|
||||
return 165000;
|
||||
else if (dev_priv->chipset >= 0x40)
|
||||
return 155000;
|
||||
else if (dev_priv->chipset >= 0x18)
|
||||
return 135000;
|
||||
else
|
||||
return 112000;
|
||||
}
|
||||
|
||||
static int
|
||||
nouveau_connector_mode_valid(struct drm_connector *connector,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
struct drm_nouveau_private *dev_priv = connector->dev->dev_private;
|
||||
struct nouveau_connector *nv_connector = nouveau_connector(connector);
|
||||
struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder;
|
||||
struct drm_encoder *encoder = to_drm_encoder(nv_encoder);
|
||||
|
@ -663,11 +680,9 @@ nouveau_connector_mode_valid(struct drm_connector *connector,
|
|||
max_clock = 400000;
|
||||
break;
|
||||
case OUTPUT_TMDS:
|
||||
if ((dev_priv->card_type >= NV_50 && !nouveau_duallink) ||
|
||||
!nv_encoder->dcb->duallink_possible)
|
||||
max_clock = 165000;
|
||||
else
|
||||
max_clock = 330000;
|
||||
max_clock = get_tmds_link_bandwidth(connector);
|
||||
if (nouveau_duallink && nv_encoder->dcb->duallink_possible)
|
||||
max_clock *= 2;
|
||||
break;
|
||||
case OUTPUT_ANALOG:
|
||||
max_clock = nv_encoder->dcb->crtconf.maxfreq;
|
||||
|
@ -709,44 +724,6 @@ 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,
|
||||
|
@ -872,6 +849,7 @@ nouveau_connector_create(struct drm_device *dev, int index)
|
|||
dev->mode_config.scaling_mode_property,
|
||||
nv_connector->scaling_mode);
|
||||
}
|
||||
connector->polled = DRM_CONNECTOR_POLL_CONNECT;
|
||||
/* fall-through */
|
||||
case DCB_CONNECTOR_TV_0:
|
||||
case DCB_CONNECTOR_TV_1:
|
||||
|
@ -888,11 +866,16 @@ nouveau_connector_create(struct drm_device *dev, int index)
|
|||
dev->mode_config.dithering_mode_property,
|
||||
nv_connector->use_dithering ?
|
||||
DRM_MODE_DITHERING_ON : DRM_MODE_DITHERING_OFF);
|
||||
|
||||
if (dcb->type != DCB_CONNECTOR_LVDS) {
|
||||
if (dev_priv->card_type >= NV_50)
|
||||
connector->polled = DRM_CONNECTOR_POLL_HPD;
|
||||
else
|
||||
connector->polled = DRM_CONNECTOR_POLL_CONNECT;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
nouveau_connector_set_polling(connector);
|
||||
|
||||
drm_sysfs_connector_add(connector);
|
||||
dcb->drm = connector;
|
||||
return dcb->drm;
|
||||
|
|
|
@ -52,9 +52,6 @@ static inline struct nouveau_connector *nouveau_connector(
|
|||
struct drm_connector *
|
||||
nouveau_connector_create(struct drm_device *, int index);
|
||||
|
||||
void
|
||||
nouveau_connector_set_polling(struct drm_connector *);
|
||||
|
||||
int
|
||||
nouveau_connector_bpp(struct drm_connector *);
|
||||
|
||||
|
|
|
@ -100,6 +100,9 @@ struct nouveau_bo {
|
|||
int pin_refcnt;
|
||||
};
|
||||
|
||||
#define nouveau_bo_tile_layout(nvbo) \
|
||||
((nvbo)->tile_flags & NOUVEAU_GEM_TILE_LAYOUT_MASK)
|
||||
|
||||
static inline struct nouveau_bo *
|
||||
nouveau_bo(struct ttm_buffer_object *bo)
|
||||
{
|
||||
|
@ -304,6 +307,7 @@ struct nouveau_fifo_engine {
|
|||
void (*destroy_context)(struct nouveau_channel *);
|
||||
int (*load_context)(struct nouveau_channel *);
|
||||
int (*unload_context)(struct drm_device *);
|
||||
void (*tlb_flush)(struct drm_device *dev);
|
||||
};
|
||||
|
||||
struct nouveau_pgraph_object_method {
|
||||
|
@ -336,6 +340,7 @@ struct nouveau_pgraph_engine {
|
|||
void (*destroy_context)(struct nouveau_channel *);
|
||||
int (*load_context)(struct nouveau_channel *);
|
||||
int (*unload_context)(struct drm_device *);
|
||||
void (*tlb_flush)(struct drm_device *dev);
|
||||
|
||||
void (*set_region_tiling)(struct drm_device *dev, int i, uint32_t addr,
|
||||
uint32_t size, uint32_t pitch);
|
||||
|
@ -485,13 +490,13 @@ enum nv04_fp_display_regs {
|
|||
};
|
||||
|
||||
struct nv04_crtc_reg {
|
||||
unsigned char MiscOutReg; /* */
|
||||
unsigned char MiscOutReg;
|
||||
uint8_t CRTC[0xa0];
|
||||
uint8_t CR58[0x10];
|
||||
uint8_t Sequencer[5];
|
||||
uint8_t Graphics[9];
|
||||
uint8_t Attribute[21];
|
||||
unsigned char DAC[768]; /* Internal Colorlookuptable */
|
||||
unsigned char DAC[768];
|
||||
|
||||
/* PCRTC regs */
|
||||
uint32_t fb_start;
|
||||
|
@ -539,43 +544,9 @@ struct nv04_output_reg {
|
|||
};
|
||||
|
||||
struct nv04_mode_state {
|
||||
uint32_t bpp;
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
uint32_t interlace;
|
||||
uint32_t repaint0;
|
||||
uint32_t repaint1;
|
||||
uint32_t screen;
|
||||
uint32_t scale;
|
||||
uint32_t dither;
|
||||
uint32_t extra;
|
||||
uint32_t fifo;
|
||||
uint32_t pixel;
|
||||
uint32_t horiz;
|
||||
int arbitration0;
|
||||
int arbitration1;
|
||||
uint32_t pll;
|
||||
uint32_t pllB;
|
||||
uint32_t vpll;
|
||||
uint32_t vpll2;
|
||||
uint32_t vpllB;
|
||||
uint32_t vpll2B;
|
||||
struct nv04_crtc_reg crtc_reg[2];
|
||||
uint32_t pllsel;
|
||||
uint32_t sel_clk;
|
||||
uint32_t general;
|
||||
uint32_t crtcOwner;
|
||||
uint32_t head;
|
||||
uint32_t head2;
|
||||
uint32_t cursorConfig;
|
||||
uint32_t cursor0;
|
||||
uint32_t cursor1;
|
||||
uint32_t cursor2;
|
||||
uint32_t timingH;
|
||||
uint32_t timingV;
|
||||
uint32_t displayV;
|
||||
uint32_t crtcSync;
|
||||
|
||||
struct nv04_crtc_reg crtc_reg[2];
|
||||
};
|
||||
|
||||
enum nouveau_card_type {
|
||||
|
@ -613,6 +584,12 @@ struct drm_nouveau_private {
|
|||
struct work_struct irq_work;
|
||||
struct work_struct hpd_work;
|
||||
|
||||
struct {
|
||||
spinlock_t lock;
|
||||
uint32_t hpd0_bits;
|
||||
uint32_t hpd1_bits;
|
||||
} hpd_state;
|
||||
|
||||
struct list_head vbl_waiting;
|
||||
|
||||
struct {
|
||||
|
@ -1045,6 +1022,7 @@ extern int nv50_fifo_create_context(struct nouveau_channel *);
|
|||
extern void nv50_fifo_destroy_context(struct nouveau_channel *);
|
||||
extern int nv50_fifo_load_context(struct nouveau_channel *);
|
||||
extern int nv50_fifo_unload_context(struct drm_device *);
|
||||
extern void nv50_fifo_tlb_flush(struct drm_device *dev);
|
||||
|
||||
/* nvc0_fifo.c */
|
||||
extern int nvc0_fifo_init(struct drm_device *);
|
||||
|
@ -1122,6 +1100,8 @@ extern int nv50_graph_load_context(struct nouveau_channel *);
|
|||
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 *);
|
||||
extern void nv50_graph_tlb_flush(struct drm_device *dev);
|
||||
extern void nv86_graph_tlb_flush(struct drm_device *dev);
|
||||
|
||||
/* nvc0_graph.c */
|
||||
extern int nvc0_graph_init(struct drm_device *);
|
||||
|
@ -1239,7 +1219,6 @@ extern u16 nouveau_bo_rd16(struct nouveau_bo *nvbo, unsigned index);
|
|||
extern void nouveau_bo_wr16(struct nouveau_bo *nvbo, unsigned index, u16 val);
|
||||
extern u32 nouveau_bo_rd32(struct nouveau_bo *nvbo, unsigned index);
|
||||
extern void nouveau_bo_wr32(struct nouveau_bo *nvbo, unsigned index, u32 val);
|
||||
extern int nouveau_bo_sync_gpu(struct nouveau_bo *, struct nouveau_channel *);
|
||||
|
||||
/* nouveau_fence.c */
|
||||
struct nouveau_fence;
|
||||
|
|
|
@ -249,6 +249,7 @@ alloc_semaphore(struct drm_device *dev)
|
|||
{
|
||||
struct drm_nouveau_private *dev_priv = dev->dev_private;
|
||||
struct nouveau_semaphore *sema;
|
||||
int ret;
|
||||
|
||||
if (!USE_SEMA(dev))
|
||||
return NULL;
|
||||
|
@ -257,10 +258,14 @@ alloc_semaphore(struct drm_device *dev)
|
|||
if (!sema)
|
||||
goto fail;
|
||||
|
||||
ret = drm_mm_pre_get(&dev_priv->fence.heap);
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
spin_lock(&dev_priv->fence.lock);
|
||||
sema->mem = drm_mm_search_free(&dev_priv->fence.heap, 4, 0, 0);
|
||||
if (sema->mem)
|
||||
sema->mem = drm_mm_get_block(sema->mem, 4, 0);
|
||||
sema->mem = drm_mm_get_block_atomic(sema->mem, 4, 0);
|
||||
spin_unlock(&dev_priv->fence.lock);
|
||||
|
||||
if (!sema->mem)
|
||||
|
|
|
@ -107,23 +107,29 @@ nouveau_gem_info(struct drm_gem_object *gem, struct drm_nouveau_gem_info *rep)
|
|||
}
|
||||
|
||||
static bool
|
||||
nouveau_gem_tile_flags_valid(struct drm_device *dev, uint32_t tile_flags) {
|
||||
switch (tile_flags) {
|
||||
case 0x0000:
|
||||
case 0x1800:
|
||||
case 0x2800:
|
||||
case 0x4800:
|
||||
case 0x7000:
|
||||
case 0x7400:
|
||||
case 0x7a00:
|
||||
case 0xe000:
|
||||
break;
|
||||
default:
|
||||
NV_ERROR(dev, "bad page flags: 0x%08x\n", tile_flags);
|
||||
return false;
|
||||
nouveau_gem_tile_flags_valid(struct drm_device *dev, uint32_t tile_flags)
|
||||
{
|
||||
struct drm_nouveau_private *dev_priv = dev->dev_private;
|
||||
|
||||
if (dev_priv->card_type >= NV_50) {
|
||||
switch (tile_flags & NOUVEAU_GEM_TILE_LAYOUT_MASK) {
|
||||
case 0x0000:
|
||||
case 0x1800:
|
||||
case 0x2800:
|
||||
case 0x4800:
|
||||
case 0x7000:
|
||||
case 0x7400:
|
||||
case 0x7a00:
|
||||
case 0xe000:
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
if (!(tile_flags & NOUVEAU_GEM_TILE_LAYOUT_MASK))
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
NV_ERROR(dev, "bad page flags: 0x%08x\n", tile_flags);
|
||||
return false;
|
||||
}
|
||||
|
||||
int
|
||||
|
|
|
@ -519,11 +519,11 @@ nouveau_hw_fix_bad_vpll(struct drm_device *dev, int head)
|
|||
|
||||
struct pll_lims pll_lim;
|
||||
struct nouveau_pll_vals pv;
|
||||
uint32_t pllreg = head ? NV_RAMDAC_VPLL2 : NV_PRAMDAC_VPLL_COEFF;
|
||||
enum pll_types pll = head ? PLL_VPLL1 : PLL_VPLL0;
|
||||
|
||||
if (get_pll_limits(dev, pllreg, &pll_lim))
|
||||
if (get_pll_limits(dev, pll, &pll_lim))
|
||||
return;
|
||||
nouveau_hw_get_pllvals(dev, pllreg, &pv);
|
||||
nouveau_hw_get_pllvals(dev, pll, &pv);
|
||||
|
||||
if (pv.M1 >= pll_lim.vco1.min_m && pv.M1 <= pll_lim.vco1.max_m &&
|
||||
pv.N1 >= pll_lim.vco1.min_n && pv.N1 <= pll_lim.vco1.max_n &&
|
||||
|
@ -536,7 +536,7 @@ nouveau_hw_fix_bad_vpll(struct drm_device *dev, int head)
|
|||
pv.M1 = pll_lim.vco1.max_m;
|
||||
pv.N1 = pll_lim.vco1.min_n;
|
||||
pv.log2P = pll_lim.max_usable_log2p;
|
||||
nouveau_hw_setpll(dev, pllreg, &pv);
|
||||
nouveau_hw_setpll(dev, pll_lim.reg, &pv);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -415,6 +415,25 @@ nv_fix_nv40_hw_cursor(struct drm_device *dev, int head)
|
|||
NVWriteRAMDAC(dev, head, NV_PRAMDAC_CU_START_POS, curpos);
|
||||
}
|
||||
|
||||
static inline void
|
||||
nv_set_crtc_base(struct drm_device *dev, int head, uint32_t offset)
|
||||
{
|
||||
struct drm_nouveau_private *dev_priv = dev->dev_private;
|
||||
|
||||
NVWriteCRTC(dev, head, NV_PCRTC_START, offset);
|
||||
|
||||
if (dev_priv->card_type == NV_04) {
|
||||
/*
|
||||
* Hilarious, the 24th bit doesn't want to stick to
|
||||
* PCRTC_START...
|
||||
*/
|
||||
int cre_heb = NVReadVgaCrtc(dev, head, NV_CIO_CRE_HEB__INDEX);
|
||||
|
||||
NVWriteVgaCrtc(dev, head, NV_CIO_CRE_HEB__INDEX,
|
||||
(cre_heb & ~0x40) | ((offset >> 18) & 0x40));
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
nv_show_cursor(struct drm_device *dev, int head, bool show)
|
||||
{
|
||||
|
|
|
@ -256,7 +256,7 @@ nouveau_i2c_find(struct drm_device *dev, int index)
|
|||
if (index >= DCB_MAX_NUM_I2C_ENTRIES)
|
||||
return NULL;
|
||||
|
||||
if (dev_priv->chipset >= NV_50 && (i2c->entry & 0x00000100)) {
|
||||
if (dev_priv->card_type >= NV_50 && (i2c->entry & 0x00000100)) {
|
||||
uint32_t reg = 0xe500, val;
|
||||
|
||||
if (i2c->port_type == 6) {
|
||||
|
|
|
@ -42,6 +42,13 @@
|
|||
#include "nouveau_connector.h"
|
||||
#include "nv50_display.h"
|
||||
|
||||
static DEFINE_RATELIMIT_STATE(nouveau_ratelimit_state, 3 * HZ, 20);
|
||||
|
||||
static int nouveau_ratelimit(void)
|
||||
{
|
||||
return __ratelimit(&nouveau_ratelimit_state);
|
||||
}
|
||||
|
||||
void
|
||||
nouveau_irq_preinstall(struct drm_device *dev)
|
||||
{
|
||||
|
@ -53,6 +60,7 @@ nouveau_irq_preinstall(struct drm_device *dev)
|
|||
if (dev_priv->card_type >= NV_50) {
|
||||
INIT_WORK(&dev_priv->irq_work, nv50_display_irq_handler_bh);
|
||||
INIT_WORK(&dev_priv->hpd_work, nv50_display_irq_hotplug_bh);
|
||||
spin_lock_init(&dev_priv->hpd_state.lock);
|
||||
INIT_LIST_HEAD(&dev_priv->vbl_waiting);
|
||||
}
|
||||
}
|
||||
|
@ -202,8 +210,8 @@ nouveau_fifo_irq_handler(struct drm_device *dev)
|
|||
}
|
||||
|
||||
if (status & NV_PFIFO_INTR_DMA_PUSHER) {
|
||||
u32 get = nv_rd32(dev, 0x003244);
|
||||
u32 put = nv_rd32(dev, 0x003240);
|
||||
u32 dma_get = nv_rd32(dev, 0x003244);
|
||||
u32 dma_put = nv_rd32(dev, 0x003240);
|
||||
u32 push = nv_rd32(dev, 0x003220);
|
||||
u32 state = nv_rd32(dev, 0x003228);
|
||||
|
||||
|
@ -213,16 +221,18 @@ nouveau_fifo_irq_handler(struct drm_device *dev)
|
|||
u32 ib_get = nv_rd32(dev, 0x003334);
|
||||
u32 ib_put = nv_rd32(dev, 0x003330);
|
||||
|
||||
NV_INFO(dev, "PFIFO_DMA_PUSHER - Ch %d Get 0x%02x%08x "
|
||||
if (nouveau_ratelimit())
|
||||
NV_INFO(dev, "PFIFO_DMA_PUSHER - Ch %d Get 0x%02x%08x "
|
||||
"Put 0x%02x%08x IbGet 0x%08x IbPut 0x%08x "
|
||||
"State 0x%08x Push 0x%08x\n",
|
||||
chid, ho_get, get, ho_put, put, ib_get, ib_put,
|
||||
state, push);
|
||||
chid, ho_get, dma_get, ho_put,
|
||||
dma_put, ib_get, ib_put, state,
|
||||
push);
|
||||
|
||||
/* METHOD_COUNT, in DMA_STATE on earlier chipsets */
|
||||
nv_wr32(dev, 0x003364, 0x00000000);
|
||||
if (get != put || ho_get != ho_put) {
|
||||
nv_wr32(dev, 0x003244, put);
|
||||
if (dma_get != dma_put || ho_get != ho_put) {
|
||||
nv_wr32(dev, 0x003244, dma_put);
|
||||
nv_wr32(dev, 0x003328, ho_put);
|
||||
} else
|
||||
if (ib_get != ib_put) {
|
||||
|
@ -231,10 +241,10 @@ nouveau_fifo_irq_handler(struct drm_device *dev)
|
|||
} else {
|
||||
NV_INFO(dev, "PFIFO_DMA_PUSHER - Ch %d Get 0x%08x "
|
||||
"Put 0x%08x State 0x%08x Push 0x%08x\n",
|
||||
chid, get, put, state, push);
|
||||
chid, dma_get, dma_put, state, push);
|
||||
|
||||
if (get != put)
|
||||
nv_wr32(dev, 0x003244, put);
|
||||
if (dma_get != dma_put)
|
||||
nv_wr32(dev, 0x003244, dma_put);
|
||||
}
|
||||
|
||||
nv_wr32(dev, 0x003228, 0x00000000);
|
||||
|
@ -266,8 +276,9 @@ nouveau_fifo_irq_handler(struct drm_device *dev)
|
|||
}
|
||||
|
||||
if (status) {
|
||||
NV_INFO(dev, "PFIFO_INTR 0x%08x - Ch %d\n",
|
||||
status, chid);
|
||||
if (nouveau_ratelimit())
|
||||
NV_INFO(dev, "PFIFO_INTR 0x%08x - Ch %d\n",
|
||||
status, chid);
|
||||
nv_wr32(dev, NV03_PFIFO_INTR_0, status);
|
||||
status = 0;
|
||||
}
|
||||
|
@ -544,13 +555,6 @@ nouveau_pgraph_intr_notify(struct drm_device *dev, uint32_t nsource)
|
|||
nouveau_graph_dump_trap_info(dev, "PGRAPH_NOTIFY", &trap);
|
||||
}
|
||||
|
||||
static DEFINE_RATELIMIT_STATE(nouveau_ratelimit_state, 3 * HZ, 20);
|
||||
|
||||
static int nouveau_ratelimit(void)
|
||||
{
|
||||
return __ratelimit(&nouveau_ratelimit_state);
|
||||
}
|
||||
|
||||
|
||||
static inline void
|
||||
nouveau_pgraph_intr_error(struct drm_device *dev, uint32_t nsource)
|
||||
|
|
|
@ -33,9 +33,9 @@
|
|||
#include "drmP.h"
|
||||
#include "drm.h"
|
||||
#include "drm_sarea.h"
|
||||
#include "nouveau_drv.h"
|
||||
|
||||
#define MIN(a,b) a < b ? a : b
|
||||
#include "nouveau_drv.h"
|
||||
#include "nouveau_pm.h"
|
||||
|
||||
/*
|
||||
* NV10-NV40 tiling helpers
|
||||
|
@ -175,11 +175,10 @@ nv50_mem_vm_bind_linear(struct drm_device *dev, uint64_t virt, uint32_t size,
|
|||
}
|
||||
}
|
||||
}
|
||||
dev_priv->engine.instmem.flush(dev);
|
||||
|
||||
nv50_vm_flush(dev, 5);
|
||||
nv50_vm_flush(dev, 0);
|
||||
nv50_vm_flush(dev, 4);
|
||||
dev_priv->engine.instmem.flush(dev);
|
||||
dev_priv->engine.fifo.tlb_flush(dev);
|
||||
dev_priv->engine.graph.tlb_flush(dev);
|
||||
nv50_vm_flush(dev, 6);
|
||||
return 0;
|
||||
}
|
||||
|
@ -209,11 +208,10 @@ nv50_mem_vm_unbind(struct drm_device *dev, uint64_t virt, uint32_t size)
|
|||
pte++;
|
||||
}
|
||||
}
|
||||
dev_priv->engine.instmem.flush(dev);
|
||||
|
||||
nv50_vm_flush(dev, 5);
|
||||
nv50_vm_flush(dev, 0);
|
||||
nv50_vm_flush(dev, 4);
|
||||
dev_priv->engine.instmem.flush(dev);
|
||||
dev_priv->engine.fifo.tlb_flush(dev);
|
||||
dev_priv->engine.graph.tlb_flush(dev);
|
||||
nv50_vm_flush(dev, 6);
|
||||
}
|
||||
|
||||
|
@ -653,6 +651,7 @@ nouveau_mem_gart_init(struct drm_device *dev)
|
|||
void
|
||||
nouveau_mem_timing_init(struct drm_device *dev)
|
||||
{
|
||||
/* cards < NVC0 only */
|
||||
struct drm_nouveau_private *dev_priv = dev->dev_private;
|
||||
struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
|
||||
struct nouveau_pm_memtimings *memtimings = &pm->memtimings;
|
||||
|
@ -719,14 +718,14 @@ nouveau_mem_timing_init(struct drm_device *dev)
|
|||
tUNK_19 = 1;
|
||||
tUNK_20 = 0;
|
||||
tUNK_21 = 0;
|
||||
switch (MIN(recordlen,21)) {
|
||||
case 21:
|
||||
switch (min(recordlen, 22)) {
|
||||
case 22:
|
||||
tUNK_21 = entry[21];
|
||||
case 20:
|
||||
case 21:
|
||||
tUNK_20 = entry[20];
|
||||
case 19:
|
||||
case 20:
|
||||
tUNK_19 = entry[19];
|
||||
case 18:
|
||||
case 19:
|
||||
tUNK_18 = entry[18];
|
||||
default:
|
||||
tUNK_0 = entry[0];
|
||||
|
@ -756,24 +755,30 @@ nouveau_mem_timing_init(struct drm_device *dev)
|
|||
timing->reg_100228 = (tUNK_12 << 16 | tUNK_11 << 8 | tUNK_10);
|
||||
if(recordlen > 19) {
|
||||
timing->reg_100228 += (tUNK_19 - 1) << 24;
|
||||
} else {
|
||||
}/* I cannot back-up this else-statement right now
|
||||
else {
|
||||
timing->reg_100228 += tUNK_12 << 24;
|
||||
}
|
||||
}*/
|
||||
|
||||
/* XXX: reg_10022c */
|
||||
timing->reg_10022c = tUNK_2 - 1;
|
||||
|
||||
timing->reg_100230 = (tUNK_20 << 24 | tUNK_21 << 16 |
|
||||
tUNK_13 << 8 | tUNK_13);
|
||||
|
||||
/* XXX: +6? */
|
||||
timing->reg_100234 = (tRAS << 24 | (tUNK_19 + 6) << 8 | tRC);
|
||||
if(tUNK_10 > tUNK_11) {
|
||||
timing->reg_100234 += tUNK_10 << 16;
|
||||
} else {
|
||||
timing->reg_100234 += tUNK_11 << 16;
|
||||
timing->reg_100234 += max(tUNK_10,tUNK_11) << 16;
|
||||
|
||||
/* XXX; reg_100238, reg_10023c
|
||||
* reg: 0x00??????
|
||||
* reg_10023c:
|
||||
* 0 for pre-NV50 cards
|
||||
* 0x????0202 for NV50+ cards (empirical evidence) */
|
||||
if(dev_priv->card_type >= NV_50) {
|
||||
timing->reg_10023c = 0x202;
|
||||
}
|
||||
|
||||
/* XXX; reg_100238, reg_10023c */
|
||||
NV_DEBUG(dev, "Entry %d: 220: %08x %08x %08x %08x\n", i,
|
||||
timing->reg_100220, timing->reg_100224,
|
||||
timing->reg_100228, timing->reg_10022c);
|
||||
|
|
|
@ -129,7 +129,7 @@ nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan,
|
|||
if (ramin == NULL) {
|
||||
spin_unlock(&dev_priv->ramin_lock);
|
||||
nouveau_gpuobj_ref(NULL, &gpuobj);
|
||||
return ret;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ramin = drm_mm_get_block_atomic(ramin, size, align);
|
||||
|
|
|
@ -284,6 +284,7 @@ nouveau_sysfs_fini(struct drm_device *dev)
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_HWMON
|
||||
static ssize_t
|
||||
nouveau_hwmon_show_temp(struct device *d, struct device_attribute *a, char *buf)
|
||||
{
|
||||
|
@ -395,10 +396,12 @@ static struct attribute *hwmon_attributes[] = {
|
|||
static const struct attribute_group hwmon_attrgroup = {
|
||||
.attrs = hwmon_attributes,
|
||||
};
|
||||
#endif
|
||||
|
||||
static int
|
||||
nouveau_hwmon_init(struct drm_device *dev)
|
||||
{
|
||||
#ifdef CONFIG_HWMON
|
||||
struct drm_nouveau_private *dev_priv = dev->dev_private;
|
||||
struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
|
||||
struct device *hwmon_dev;
|
||||
|
@ -425,13 +428,14 @@ nouveau_hwmon_init(struct drm_device *dev)
|
|||
}
|
||||
|
||||
pm->hwmon = hwmon_dev;
|
||||
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
nouveau_hwmon_fini(struct drm_device *dev)
|
||||
{
|
||||
#ifdef CONFIG_HWMON
|
||||
struct drm_nouveau_private *dev_priv = dev->dev_private;
|
||||
struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
|
||||
|
||||
|
@ -439,6 +443,7 @@ nouveau_hwmon_fini(struct drm_device *dev)
|
|||
sysfs_remove_group(&pm->hwmon->kobj, &hwmon_attrgroup);
|
||||
hwmon_device_unregister(pm->hwmon);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
|
|
|
@ -153,26 +153,42 @@ nouveau_ramht_insert(struct nouveau_channel *chan, u32 handle,
|
|||
return -ENOMEM;
|
||||
}
|
||||
|
||||
static struct nouveau_ramht_entry *
|
||||
nouveau_ramht_remove_entry(struct nouveau_channel *chan, u32 handle)
|
||||
{
|
||||
struct nouveau_ramht *ramht = chan ? chan->ramht : NULL;
|
||||
struct nouveau_ramht_entry *entry;
|
||||
unsigned long flags;
|
||||
|
||||
if (!ramht)
|
||||
return NULL;
|
||||
|
||||
spin_lock_irqsave(&ramht->lock, flags);
|
||||
list_for_each_entry(entry, &ramht->entries, head) {
|
||||
if (entry->channel == chan &&
|
||||
(!handle || entry->handle == handle)) {
|
||||
list_del(&entry->head);
|
||||
spin_unlock_irqrestore(&ramht->lock, flags);
|
||||
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&ramht->lock, flags);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
nouveau_ramht_remove_locked(struct nouveau_channel *chan, u32 handle)
|
||||
nouveau_ramht_remove_hash(struct nouveau_channel *chan, u32 handle)
|
||||
{
|
||||
struct drm_device *dev = chan->dev;
|
||||
struct drm_nouveau_private *dev_priv = dev->dev_private;
|
||||
struct nouveau_instmem_engine *instmem = &dev_priv->engine.instmem;
|
||||
struct nouveau_gpuobj *ramht = chan->ramht->gpuobj;
|
||||
struct nouveau_ramht_entry *entry, *tmp;
|
||||
unsigned long flags;
|
||||
u32 co, ho;
|
||||
|
||||
list_for_each_entry_safe(entry, tmp, &chan->ramht->entries, head) {
|
||||
if (entry->channel != chan || entry->handle != handle)
|
||||
continue;
|
||||
|
||||
nouveau_gpuobj_ref(NULL, &entry->gpuobj);
|
||||
list_del(&entry->head);
|
||||
kfree(entry);
|
||||
break;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&chan->ramht->lock, flags);
|
||||
co = ho = nouveau_ramht_hash_handle(chan, handle);
|
||||
do {
|
||||
if (nouveau_ramht_entry_valid(dev, ramht, co) &&
|
||||
|
@ -184,7 +200,7 @@ nouveau_ramht_remove_locked(struct nouveau_channel *chan, u32 handle)
|
|||
nv_wo32(ramht, co + 0, 0x00000000);
|
||||
nv_wo32(ramht, co + 4, 0x00000000);
|
||||
instmem->flush(dev);
|
||||
return;
|
||||
goto out;
|
||||
}
|
||||
|
||||
co += 8;
|
||||
|
@ -194,17 +210,22 @@ nouveau_ramht_remove_locked(struct nouveau_channel *chan, u32 handle)
|
|||
|
||||
NV_ERROR(dev, "RAMHT entry not found. ch=%d, handle=0x%08x\n",
|
||||
chan->id, handle);
|
||||
out:
|
||||
spin_unlock_irqrestore(&chan->ramht->lock, flags);
|
||||
}
|
||||
|
||||
void
|
||||
nouveau_ramht_remove(struct nouveau_channel *chan, u32 handle)
|
||||
{
|
||||
struct nouveau_ramht *ramht = chan->ramht;
|
||||
unsigned long flags;
|
||||
struct nouveau_ramht_entry *entry;
|
||||
|
||||
spin_lock_irqsave(&ramht->lock, flags);
|
||||
nouveau_ramht_remove_locked(chan, handle);
|
||||
spin_unlock_irqrestore(&ramht->lock, flags);
|
||||
entry = nouveau_ramht_remove_entry(chan, handle);
|
||||
if (!entry)
|
||||
return;
|
||||
|
||||
nouveau_ramht_remove_hash(chan, entry->handle);
|
||||
nouveau_gpuobj_ref(NULL, &entry->gpuobj);
|
||||
kfree(entry);
|
||||
}
|
||||
|
||||
struct nouveau_gpuobj *
|
||||
|
@ -265,23 +286,19 @@ void
|
|||
nouveau_ramht_ref(struct nouveau_ramht *ref, struct nouveau_ramht **ptr,
|
||||
struct nouveau_channel *chan)
|
||||
{
|
||||
struct nouveau_ramht_entry *entry, *tmp;
|
||||
struct nouveau_ramht_entry *entry;
|
||||
struct nouveau_ramht *ramht;
|
||||
unsigned long flags;
|
||||
|
||||
if (ref)
|
||||
kref_get(&ref->refcount);
|
||||
|
||||
ramht = *ptr;
|
||||
if (ramht) {
|
||||
spin_lock_irqsave(&ramht->lock, flags);
|
||||
list_for_each_entry_safe(entry, tmp, &ramht->entries, head) {
|
||||
if (entry->channel != chan)
|
||||
continue;
|
||||
|
||||
nouveau_ramht_remove_locked(chan, entry->handle);
|
||||
while ((entry = nouveau_ramht_remove_entry(chan, 0))) {
|
||||
nouveau_ramht_remove_hash(chan, entry->handle);
|
||||
nouveau_gpuobj_ref(NULL, &entry->gpuobj);
|
||||
kfree(entry);
|
||||
}
|
||||
spin_unlock_irqrestore(&ramht->lock, flags);
|
||||
|
||||
kref_put(&ramht->refcount, nouveau_ramht_del);
|
||||
}
|
||||
|
|
|
@ -120,8 +120,8 @@ nouveau_sgdma_bind(struct ttm_backend *be, struct ttm_mem_reg *mem)
|
|||
dev_priv->engine.instmem.flush(nvbe->dev);
|
||||
|
||||
if (dev_priv->card_type == NV_50) {
|
||||
nv50_vm_flush(dev, 5); /* PGRAPH */
|
||||
nv50_vm_flush(dev, 0); /* PFIFO */
|
||||
dev_priv->engine.fifo.tlb_flush(dev);
|
||||
dev_priv->engine.graph.tlb_flush(dev);
|
||||
}
|
||||
|
||||
nvbe->bound = true;
|
||||
|
@ -162,8 +162,8 @@ nouveau_sgdma_unbind(struct ttm_backend *be)
|
|||
dev_priv->engine.instmem.flush(nvbe->dev);
|
||||
|
||||
if (dev_priv->card_type == NV_50) {
|
||||
nv50_vm_flush(dev, 5);
|
||||
nv50_vm_flush(dev, 0);
|
||||
dev_priv->engine.fifo.tlb_flush(dev);
|
||||
dev_priv->engine.graph.tlb_flush(dev);
|
||||
}
|
||||
|
||||
nvbe->bound = false;
|
||||
|
@ -224,7 +224,11 @@ nouveau_sgdma_init(struct drm_device *dev)
|
|||
int i, ret;
|
||||
|
||||
if (dev_priv->card_type < NV_50) {
|
||||
aper_size = (64 * 1024 * 1024);
|
||||
if(dev_priv->ramin_rsvd_vram < 2 * 1024 * 1024)
|
||||
aper_size = 64 * 1024 * 1024;
|
||||
else
|
||||
aper_size = 512 * 1024 * 1024;
|
||||
|
||||
obj_size = (aper_size >> NV_CTXDMA_PAGE_SHIFT) * 4;
|
||||
obj_size += 8; /* ctxdma header */
|
||||
} else {
|
||||
|
|
|
@ -354,6 +354,15 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
|
|||
engine->graph.destroy_context = nv50_graph_destroy_context;
|
||||
engine->graph.load_context = nv50_graph_load_context;
|
||||
engine->graph.unload_context = nv50_graph_unload_context;
|
||||
if (dev_priv->chipset != 0x86)
|
||||
engine->graph.tlb_flush = nv50_graph_tlb_flush;
|
||||
else {
|
||||
/* from what i can see nvidia do this on every
|
||||
* pre-NVA3 board except NVAC, but, we've only
|
||||
* ever seen problems on NV86
|
||||
*/
|
||||
engine->graph.tlb_flush = nv86_graph_tlb_flush;
|
||||
}
|
||||
engine->fifo.channels = 128;
|
||||
engine->fifo.init = nv50_fifo_init;
|
||||
engine->fifo.takedown = nv50_fifo_takedown;
|
||||
|
@ -365,6 +374,7 @@ 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->fifo.tlb_flush = nv50_fifo_tlb_flush;
|
||||
engine->display.early_init = nv50_display_early_init;
|
||||
engine->display.late_takedown = nv50_display_late_takedown;
|
||||
engine->display.create = nv50_display_create;
|
||||
|
@ -1041,6 +1051,9 @@ int nouveau_ioctl_getparam(struct drm_device *dev, void *data,
|
|||
case NOUVEAU_GETPARAM_PTIMER_TIME:
|
||||
getparam->value = dev_priv->engine.timer.read(dev);
|
||||
break;
|
||||
case NOUVEAU_GETPARAM_HAS_BO_USAGE:
|
||||
getparam->value = 1;
|
||||
break;
|
||||
case NOUVEAU_GETPARAM_GRAPH_UNITS:
|
||||
/* NV40 and NV50 versions are quite different, but register
|
||||
* address is the same. User is supposed to know the card
|
||||
|
@ -1051,7 +1064,7 @@ int nouveau_ioctl_getparam(struct drm_device *dev, void *data,
|
|||
}
|
||||
/* FALLTHRU */
|
||||
default:
|
||||
NV_ERROR(dev, "unknown parameter %lld\n", getparam->param);
|
||||
NV_DEBUG(dev, "unknown parameter %lld\n", getparam->param);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -1066,7 +1079,7 @@ nouveau_ioctl_setparam(struct drm_device *dev, void *data,
|
|||
|
||||
switch (setparam->param) {
|
||||
default:
|
||||
NV_ERROR(dev, "unknown parameter %lld\n", setparam->param);
|
||||
NV_DEBUG(dev, "unknown parameter %lld\n", setparam->param);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
|
|
@ -191,7 +191,7 @@ nv40_temp_get(struct drm_device *dev)
|
|||
int offset = sensor->offset_mult / sensor->offset_div;
|
||||
int core_temp;
|
||||
|
||||
if (dev_priv->chipset >= 0x50) {
|
||||
if (dev_priv->card_type >= NV_50) {
|
||||
core_temp = nv_rd32(dev, 0x20008);
|
||||
} else {
|
||||
core_temp = nv_rd32(dev, 0x0015b4) & 0x1fff;
|
||||
|
|
|
@ -158,7 +158,6 @@ 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;
|
||||
|
||||
|
@ -213,10 +212,6 @@ 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
|
||||
|
@ -831,7 +826,7 @@ nv04_crtc_do_mode_set_base(struct drm_crtc *crtc,
|
|||
/* Update the framebuffer location. */
|
||||
regp->fb_start = nv_crtc->fb.offset & ~3;
|
||||
regp->fb_start += (y * drm_fb->pitch) + (x * drm_fb->bits_per_pixel / 8);
|
||||
NVWriteCRTC(dev, nv_crtc->index, NV_PCRTC_START, regp->fb_start);
|
||||
nv_set_crtc_base(dev, nv_crtc->index, regp->fb_start);
|
||||
|
||||
/* Update the arbitration parameters. */
|
||||
nouveau_calc_arb(dev, crtc->mode.clock, drm_fb->bits_per_pixel,
|
||||
|
|
|
@ -185,14 +185,15 @@ static bool nv04_dfp_mode_fixup(struct drm_encoder *encoder,
|
|||
struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
|
||||
struct nouveau_connector *nv_connector = nouveau_encoder_connector_get(nv_encoder);
|
||||
|
||||
/* For internal panels and gpu scaling on DVI we need the native mode */
|
||||
if (nv_connector->scaling_mode != DRM_MODE_SCALE_NONE) {
|
||||
if (!nv_connector->native_mode)
|
||||
return false;
|
||||
if (!nv_connector->native_mode ||
|
||||
nv_connector->scaling_mode == DRM_MODE_SCALE_NONE ||
|
||||
mode->hdisplay > nv_connector->native_mode->hdisplay ||
|
||||
mode->vdisplay > nv_connector->native_mode->vdisplay) {
|
||||
nv_encoder->mode = *adjusted_mode;
|
||||
|
||||
} else {
|
||||
nv_encoder->mode = *nv_connector->native_mode;
|
||||
adjusted_mode->clock = nv_connector->native_mode->clock;
|
||||
} else {
|
||||
nv_encoder->mode = *adjusted_mode;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
|
@ -76,6 +76,15 @@ nv04_pm_clock_set(struct drm_device *dev, void *pre_state)
|
|||
reg += 4;
|
||||
|
||||
nouveau_hw_setpll(dev, reg, &state->calc);
|
||||
|
||||
if (dev_priv->card_type < NV_30 && reg == NV_PRAMDAC_MPLL_COEFF) {
|
||||
if (dev_priv->card_type == NV_20)
|
||||
nv_mask(dev, 0x1002c4, 0, 1 << 20);
|
||||
|
||||
/* Reset the DLLs */
|
||||
nv_mask(dev, 0x1002c0, 0, 1 << 8);
|
||||
}
|
||||
|
||||
kfree(state);
|
||||
}
|
||||
|
||||
|
|
|
@ -51,24 +51,28 @@ nv50_calc_pll2(struct drm_device *dev, struct pll_lims *pll, int clk,
|
|||
int *N, int *fN, int *M, int *P)
|
||||
{
|
||||
fixed20_12 fb_div, a, b;
|
||||
u32 refclk = pll->refclk / 10;
|
||||
u32 max_vco_freq = pll->vco1.maxfreq / 10;
|
||||
u32 max_vco_inputfreq = pll->vco1.max_inputfreq / 10;
|
||||
clk /= 10;
|
||||
|
||||
*P = pll->vco1.maxfreq / clk;
|
||||
*P = max_vco_freq / clk;
|
||||
if (*P > pll->max_p)
|
||||
*P = pll->max_p;
|
||||
if (*P < pll->min_p)
|
||||
*P = pll->min_p;
|
||||
|
||||
/* *M = ceil(refclk / pll->vco.max_inputfreq); */
|
||||
a.full = dfixed_const(pll->refclk);
|
||||
b.full = dfixed_const(pll->vco1.max_inputfreq);
|
||||
/* *M = floor((refclk + max_vco_inputfreq) / max_vco_inputfreq); */
|
||||
a.full = dfixed_const(refclk + max_vco_inputfreq);
|
||||
b.full = dfixed_const(max_vco_inputfreq);
|
||||
a.full = dfixed_div(a, b);
|
||||
a.full = dfixed_ceil(a);
|
||||
a.full = dfixed_floor(a);
|
||||
*M = dfixed_trunc(a);
|
||||
|
||||
/* fb_div = (vco * *M) / refclk; */
|
||||
fb_div.full = dfixed_const(clk * *P);
|
||||
fb_div.full = dfixed_mul(fb_div, a);
|
||||
a.full = dfixed_const(pll->refclk);
|
||||
a.full = dfixed_const(refclk);
|
||||
fb_div.full = dfixed_div(fb_div, a);
|
||||
|
||||
/* *N = floor(fb_div); */
|
||||
|
|
|
@ -546,7 +546,7 @@ nv50_crtc_do_mode_set_base(struct drm_crtc *crtc,
|
|||
}
|
||||
|
||||
nv_crtc->fb.offset = fb->nvbo->bo.offset - dev_priv->vm_vram_base;
|
||||
nv_crtc->fb.tile_flags = fb->nvbo->tile_flags;
|
||||
nv_crtc->fb.tile_flags = nouveau_bo_tile_layout(fb->nvbo);
|
||||
nv_crtc->fb.cpp = drm_fb->bits_per_pixel / 8;
|
||||
if (!nv_crtc->fb.blanked && dev_priv->chipset != 0x50) {
|
||||
ret = RING_SPACE(evo, 2);
|
||||
|
@ -578,7 +578,7 @@ nv50_crtc_do_mode_set_base(struct drm_crtc *crtc,
|
|||
fb->nvbo->tile_mode);
|
||||
}
|
||||
if (dev_priv->chipset == 0x50)
|
||||
OUT_RING(evo, (fb->nvbo->tile_flags << 8) | format);
|
||||
OUT_RING(evo, (nv_crtc->fb.tile_flags << 8) | format);
|
||||
else
|
||||
OUT_RING(evo, format);
|
||||
|
||||
|
|
|
@ -1032,11 +1032,18 @@ nv50_display_irq_hotplug_bh(struct work_struct *work)
|
|||
struct drm_connector *connector;
|
||||
const uint32_t gpio_reg[4] = { 0xe104, 0xe108, 0xe280, 0xe284 };
|
||||
uint32_t unplug_mask, plug_mask, change_mask;
|
||||
uint32_t hpd0, hpd1 = 0;
|
||||
uint32_t hpd0, hpd1;
|
||||
|
||||
hpd0 = nv_rd32(dev, 0xe054) & nv_rd32(dev, 0xe050);
|
||||
spin_lock_irq(&dev_priv->hpd_state.lock);
|
||||
hpd0 = dev_priv->hpd_state.hpd0_bits;
|
||||
dev_priv->hpd_state.hpd0_bits = 0;
|
||||
hpd1 = dev_priv->hpd_state.hpd1_bits;
|
||||
dev_priv->hpd_state.hpd1_bits = 0;
|
||||
spin_unlock_irq(&dev_priv->hpd_state.lock);
|
||||
|
||||
hpd0 &= nv_rd32(dev, 0xe050);
|
||||
if (dev_priv->chipset >= 0x90)
|
||||
hpd1 = nv_rd32(dev, 0xe074) & nv_rd32(dev, 0xe070);
|
||||
hpd1 &= nv_rd32(dev, 0xe070);
|
||||
|
||||
plug_mask = (hpd0 & 0x0000ffff) | (hpd1 << 16);
|
||||
unplug_mask = (hpd0 >> 16) | (hpd1 & 0xffff0000);
|
||||
|
@ -1078,10 +1085,6 @@ nv50_display_irq_hotplug_bh(struct work_struct *work)
|
|||
helper->dpms(connector->encoder, DRM_MODE_DPMS_OFF);
|
||||
}
|
||||
|
||||
nv_wr32(dev, 0xe054, nv_rd32(dev, 0xe054));
|
||||
if (dev_priv->chipset >= 0x90)
|
||||
nv_wr32(dev, 0xe074, nv_rd32(dev, 0xe074));
|
||||
|
||||
drm_helper_hpd_irq_event(dev);
|
||||
}
|
||||
|
||||
|
@ -1092,8 +1095,22 @@ nv50_display_irq_handler(struct drm_device *dev)
|
|||
uint32_t delayed = 0;
|
||||
|
||||
if (nv_rd32(dev, NV50_PMC_INTR_0) & NV50_PMC_INTR_0_HOTPLUG) {
|
||||
if (!work_pending(&dev_priv->hpd_work))
|
||||
queue_work(dev_priv->wq, &dev_priv->hpd_work);
|
||||
uint32_t hpd0_bits, hpd1_bits = 0;
|
||||
|
||||
hpd0_bits = nv_rd32(dev, 0xe054);
|
||||
nv_wr32(dev, 0xe054, hpd0_bits);
|
||||
|
||||
if (dev_priv->chipset >= 0x90) {
|
||||
hpd1_bits = nv_rd32(dev, 0xe074);
|
||||
nv_wr32(dev, 0xe074, hpd1_bits);
|
||||
}
|
||||
|
||||
spin_lock(&dev_priv->hpd_state.lock);
|
||||
dev_priv->hpd_state.hpd0_bits |= hpd0_bits;
|
||||
dev_priv->hpd_state.hpd1_bits |= hpd1_bits;
|
||||
spin_unlock(&dev_priv->hpd_state.lock);
|
||||
|
||||
queue_work(dev_priv->wq, &dev_priv->hpd_work);
|
||||
}
|
||||
|
||||
while (nv_rd32(dev, NV50_PMC_INTR_0) & NV50_PMC_INTR_0_DISPLAY) {
|
||||
|
|
|
@ -464,3 +464,8 @@ nv50_fifo_unload_context(struct drm_device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
nv50_fifo_tlb_flush(struct drm_device *dev)
|
||||
{
|
||||
nv50_vm_flush(dev, 5);
|
||||
}
|
||||
|
|
|
@ -402,3 +402,55 @@ struct nouveau_pgraph_object_class nv50_graph_grclass[] = {
|
|||
{ 0x8597, false, NULL }, /* tesla (nva3, nva5, nva8) */
|
||||
{}
|
||||
};
|
||||
|
||||
void
|
||||
nv50_graph_tlb_flush(struct drm_device *dev)
|
||||
{
|
||||
nv50_vm_flush(dev, 0);
|
||||
}
|
||||
|
||||
void
|
||||
nv86_graph_tlb_flush(struct drm_device *dev)
|
||||
{
|
||||
struct drm_nouveau_private *dev_priv = dev->dev_private;
|
||||
struct nouveau_timer_engine *ptimer = &dev_priv->engine.timer;
|
||||
bool idle, timeout = false;
|
||||
unsigned long flags;
|
||||
u64 start;
|
||||
u32 tmp;
|
||||
|
||||
spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
|
||||
nv_mask(dev, 0x400500, 0x00000001, 0x00000000);
|
||||
|
||||
start = ptimer->read(dev);
|
||||
do {
|
||||
idle = true;
|
||||
|
||||
for (tmp = nv_rd32(dev, 0x400380); tmp && idle; tmp >>= 3) {
|
||||
if ((tmp & 7) == 1)
|
||||
idle = false;
|
||||
}
|
||||
|
||||
for (tmp = nv_rd32(dev, 0x400384); tmp && idle; tmp >>= 3) {
|
||||
if ((tmp & 7) == 1)
|
||||
idle = false;
|
||||
}
|
||||
|
||||
for (tmp = nv_rd32(dev, 0x400388); tmp && idle; tmp >>= 3) {
|
||||
if ((tmp & 7) == 1)
|
||||
idle = false;
|
||||
}
|
||||
} while (!idle && !(timeout = ptimer->read(dev) - start > 2000000000));
|
||||
|
||||
if (timeout) {
|
||||
NV_ERROR(dev, "PGRAPH TLB flush idle timeout fail: "
|
||||
"0x%08x 0x%08x 0x%08x 0x%08x\n",
|
||||
nv_rd32(dev, 0x400700), nv_rd32(dev, 0x400380),
|
||||
nv_rd32(dev, 0x400384), nv_rd32(dev, 0x400388));
|
||||
}
|
||||
|
||||
nv50_vm_flush(dev, 0);
|
||||
|
||||
nv_mask(dev, 0x400500, 0x00000001, 0x00000001);
|
||||
spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
|
||||
}
|
||||
|
|
|
@ -402,7 +402,6 @@ nv50_instmem_bind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj)
|
|||
}
|
||||
dev_priv->engine.instmem.flush(dev);
|
||||
|
||||
nv50_vm_flush(dev, 4);
|
||||
nv50_vm_flush(dev, 6);
|
||||
|
||||
gpuobj->im_bound = 1;
|
||||
|
|
|
@ -80,6 +80,7 @@ struct drm_nouveau_gpuobj_free {
|
|||
#define NOUVEAU_GETPARAM_VM_VRAM_BASE 12
|
||||
#define NOUVEAU_GETPARAM_GRAPH_UNITS 13
|
||||
#define NOUVEAU_GETPARAM_PTIMER_TIME 14
|
||||
#define NOUVEAU_GETPARAM_HAS_BO_USAGE 15
|
||||
struct drm_nouveau_getparam {
|
||||
uint64_t param;
|
||||
uint64_t value;
|
||||
|
@ -95,6 +96,12 @@ struct drm_nouveau_setparam {
|
|||
#define NOUVEAU_GEM_DOMAIN_GART (1 << 2)
|
||||
#define NOUVEAU_GEM_DOMAIN_MAPPABLE (1 << 3)
|
||||
|
||||
#define NOUVEAU_GEM_TILE_LAYOUT_MASK 0x0000ff00
|
||||
#define NOUVEAU_GEM_TILE_16BPP 0x00000001
|
||||
#define NOUVEAU_GEM_TILE_32BPP 0x00000002
|
||||
#define NOUVEAU_GEM_TILE_ZETA 0x00000004
|
||||
#define NOUVEAU_GEM_TILE_NONCONTIG 0x00000008
|
||||
|
||||
struct drm_nouveau_gem_info {
|
||||
uint32_t handle;
|
||||
uint32_t domain;
|
||||
|
|
Loading…
Reference in New Issue