Commit df696a6f authored by Dave Airlie's avatar Dave Airlie

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

* nouveau/for-airlied:
  drm/nouveau: fix i2c-related init table handlers
  drm/nouveau: support init table i2c device identifier 0x81
  drm/nouveau: ensure we've parsed i2c table entry for INIT_*I2C* handlers
  drm/nouveau: display error message for any failed init table opcode
  drm/nouveau: fix init table handlers to return proper error codes
  drm/nv50: support fractional feedback divider on newer chips
  drm/nv50: fix monitor detection on certain chipsets
  drm/nv50: store full dcb i2c entry from vbios
  drm/nv50: fix suspend/resume with DP outputs
  drm/nv50: output calculated crtc pll when debugging on
  drm/nouveau: dump pll limits entries when debugging is on
  drm/nouveau: bios parser fixes for eDP boards
  drm/nouveau: fix a nouveau_bo dereference after it's been destroyed
  drm/nv40: remove some completed ctxprog TODOs
  drm/nv04: Implement missing nv04 PGRAPH methods in software.
  drm/nouveau: Use 0x5f instead of 0x9f as imageblit on original NV10.
parents 5d9b7e2d 893887ed
...@@ -22,7 +22,8 @@ nouveau-y := nouveau_drv.o nouveau_state.o nouveau_channel.o nouveau_mem.o \ ...@@ -22,7 +22,8 @@ nouveau-y := nouveau_drv.o nouveau_state.o nouveau_channel.o nouveau_mem.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 \
nv04_crtc.o nv04_display.o nv04_cursor.o nv04_fbcon.o \ nv04_crtc.o nv04_display.o nv04_cursor.o nv04_fbcon.o \
nv17_gpio.o nv50_gpio.o nv17_gpio.o nv50_gpio.o \
nv50_calc.o
nouveau-$(CONFIG_DRM_NOUVEAU_DEBUG) += nouveau_debugfs.o nouveau-$(CONFIG_DRM_NOUVEAU_DEBUG) += nouveau_debugfs.o
nouveau-$(CONFIG_COMPAT) += nouveau_ioc32.o nouveau-$(CONFIG_COMPAT) += nouveau_ioc32.o
......
This diff is collapsed.
...@@ -35,6 +35,7 @@ ...@@ -35,6 +35,7 @@
#define DCB_LOC_ON_CHIP 0 #define DCB_LOC_ON_CHIP 0
struct dcb_i2c_entry { struct dcb_i2c_entry {
uint32_t entry;
uint8_t port_type; uint8_t port_type;
uint8_t read, write; uint8_t read, write;
struct nouveau_i2c_chan *chan; struct nouveau_i2c_chan *chan;
......
...@@ -160,11 +160,11 @@ nouveau_bo_new(struct drm_device *dev, struct nouveau_channel *chan, ...@@ -160,11 +160,11 @@ nouveau_bo_new(struct drm_device *dev, struct nouveau_channel *chan,
ret = ttm_bo_init(&dev_priv->ttm.bdev, &nvbo->bo, size, ret = ttm_bo_init(&dev_priv->ttm.bdev, &nvbo->bo, size,
ttm_bo_type_device, &nvbo->placement, align, 0, ttm_bo_type_device, &nvbo->placement, align, 0,
false, NULL, size, nouveau_bo_del_ttm); false, NULL, size, nouveau_bo_del_ttm);
nvbo->channel = NULL;
if (ret) { if (ret) {
/* ttm will call nouveau_bo_del_ttm if it fails.. */ /* ttm will call nouveau_bo_del_ttm if it fails.. */
return ret; return ret;
} }
nvbo->channel = NULL;
spin_lock(&dev_priv->ttm.bo_list_lock); spin_lock(&dev_priv->ttm.bo_list_lock);
list_add_tail(&nvbo->head, &dev_priv->ttm.bo_list); list_add_tail(&nvbo->head, &dev_priv->ttm.bo_list);
......
...@@ -1170,6 +1170,12 @@ int nv17_gpio_set(struct drm_device *dev, enum dcb_gpio_tag tag, int state); ...@@ -1170,6 +1170,12 @@ int nv17_gpio_set(struct drm_device *dev, enum dcb_gpio_tag tag, int state);
int nv50_gpio_get(struct drm_device *dev, enum dcb_gpio_tag tag); int nv50_gpio_get(struct drm_device *dev, enum dcb_gpio_tag tag);
int nv50_gpio_set(struct drm_device *dev, enum dcb_gpio_tag tag, int state); int nv50_gpio_set(struct drm_device *dev, enum dcb_gpio_tag tag, int state);
/* nv50_calc. */
int nv50_calc_pll(struct drm_device *, struct pll_lims *, int clk,
int *N1, int *M1, int *N2, int *M2, int *P);
int nv50_calc_pll2(struct drm_device *, struct pll_lims *,
int clk, int *N, int *fN, int *M, int *P);
#ifndef ioread32_native #ifndef ioread32_native
#ifdef __BIG_ENDIAN #ifdef __BIG_ENDIAN
#define ioread16_native ioread16be #define ioread16_native ioread16be
......
...@@ -48,6 +48,8 @@ struct nouveau_encoder { ...@@ -48,6 +48,8 @@ struct nouveau_encoder {
union { union {
struct { struct {
int mc_unknown; int mc_unknown;
uint32_t unk0;
uint32_t unk1;
int dpcd_version; int dpcd_version;
int link_nr; int link_nr;
int link_bw; int link_bw;
......
...@@ -254,16 +254,27 @@ struct nouveau_i2c_chan * ...@@ -254,16 +254,27 @@ struct nouveau_i2c_chan *
nouveau_i2c_find(struct drm_device *dev, int index) nouveau_i2c_find(struct drm_device *dev, int index)
{ {
struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nvbios *bios = &dev_priv->vbios; struct dcb_i2c_entry *i2c = &dev_priv->vbios.dcb.i2c[index];
if (index >= DCB_MAX_NUM_I2C_ENTRIES) if (index >= DCB_MAX_NUM_I2C_ENTRIES)
return NULL; return NULL;
if (!bios->dcb.i2c[index].chan) { if (dev_priv->chipset >= NV_50 && (i2c->entry & 0x00000100)) {
if (nouveau_i2c_init(dev, &bios->dcb.i2c[index], index)) uint32_t reg = 0xe500, val;
return NULL;
if (i2c->port_type == 6) {
reg += i2c->read * 0x50;
val = 0x2002;
} else {
reg += ((i2c->entry & 0x1e00) >> 9) * 0x50;
val = 0xe001;
}
nv_wr32(dev, reg, (nv_rd32(dev, reg) & ~0xf003) | val);
} }
return bios->dcb.i2c[index].chan; if (!i2c->chan && nouveau_i2c_init(dev, i2c, index))
return NULL;
return i2c->chan;
} }
...@@ -826,6 +826,7 @@ ...@@ -826,6 +826,7 @@
#define NV50_SOR_DP_CTRL_TRAINING_PATTERN_2 0x02000000 #define NV50_SOR_DP_CTRL_TRAINING_PATTERN_2 0x02000000
#define NV50_SOR_DP_UNK118(i,l) (0x0061c118 + (i) * 0x800 + (l) * 0x80) #define NV50_SOR_DP_UNK118(i,l) (0x0061c118 + (i) * 0x800 + (l) * 0x80)
#define NV50_SOR_DP_UNK120(i,l) (0x0061c120 + (i) * 0x800 + (l) * 0x80) #define NV50_SOR_DP_UNK120(i,l) (0x0061c120 + (i) * 0x800 + (l) * 0x80)
#define NV50_SOR_DP_UNK128(i,l) (0x0061c128 + (i) * 0x800 + (l) * 0x80)
#define NV50_SOR_DP_UNK130(i,l) (0x0061c130 + (i) * 0x800 + (l) * 0x80) #define NV50_SOR_DP_UNK130(i,l) (0x0061c130 + (i) * 0x800 + (l) * 0x80)
#define NV50_PDISPLAY_USER(i) ((i) * 0x1000 + 0x00640000) #define NV50_PDISPLAY_USER(i) ((i) * 0x1000 + 0x00640000)
......
...@@ -236,7 +236,7 @@ nv04_fbcon_accel_init(struct fb_info *info) ...@@ -236,7 +236,7 @@ nv04_fbcon_accel_init(struct fb_info *info)
if (ret) if (ret)
return ret; return ret;
ret = nv04_fbcon_grobj_new(dev, dev_priv->card_type >= NV_10 ? ret = nv04_fbcon_grobj_new(dev, dev_priv->chipset >= 0x11 ?
0x009f : 0x005f, NvImageBlit); 0x009f : 0x005f, NvImageBlit);
if (ret) if (ret)
return ret; return ret;
......
This diff is collapsed.
...@@ -115,11 +115,6 @@ ...@@ -115,11 +115,6 @@
/* TODO: /* TODO:
* - get vs count from 0x1540 * - get vs count from 0x1540
* - document unimplemented bits compared to nvidia
* - nsource handling
* - R0 & 0x0200 handling
* - single-vs handling
* - 400314 bit 0
*/ */
static int static int
......
/*
* 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 "drm_fixed.h"
#include "nouveau_drv.h"
#include "nouveau_hw.h"
int
nv50_calc_pll(struct drm_device *dev, struct pll_lims *pll, int clk,
int *N1, int *M1, int *N2, int *M2, int *P)
{
struct nouveau_pll_vals pll_vals;
int ret;
ret = nouveau_calc_pll_mnp(dev, pll, clk, &pll_vals);
if (ret <= 0)
return ret;
*N1 = pll_vals.N1;
*M1 = pll_vals.M1;
*N2 = pll_vals.N2;
*M2 = pll_vals.M2;
*P = pll_vals.log2P;
return ret;
}
int
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;
*P = pll->vco1.maxfreq / 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);
a.full = dfixed_div(a, b);
a.full = dfixed_ceil(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);
fb_div.full = dfixed_div(fb_div, a);
/* *N = floor(fb_div); */
a.full = dfixed_floor(fb_div);
*N = dfixed_trunc(fb_div);
/* *fN = (fmod(fb_div, 1.0) * 8192) - 4096; */
b.full = dfixed_const(8192);
a.full = dfixed_mul(a, b);
fb_div.full = dfixed_mul(fb_div, b);
fb_div.full = fb_div.full - a.full;
*fN = dfixed_trunc(fb_div) - 4096;
*fN &= 0xffff;
return clk;
}
...@@ -264,32 +264,40 @@ nv50_crtc_set_scale(struct nouveau_crtc *nv_crtc, int scaling_mode, bool update) ...@@ -264,32 +264,40 @@ 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 pll_reg = NV50_PDISPLAY_CRTC_CLK_CTRL1(head); uint32_t reg = NV50_PDISPLAY_CRTC_CLK_CTRL1(head);
struct nouveau_pll_vals pll; struct pll_lims pll;
struct pll_lims limits;
uint32_t reg1, reg2; uint32_t reg1, reg2;
int ret; int ret, N1, M1, N2, M2, P;
ret = get_pll_limits(dev, pll_reg, &limits); ret = get_pll_limits(dev, reg, &pll);
if (ret) if (ret)
return ret; return ret;
ret = nouveau_calc_pll_mnp(dev, &limits, pclk, &pll); if (pll.vco2.maxfreq) {
if (ret <= 0) ret = nv50_calc_pll(dev, &pll, pclk, &N1, &M1, &N2, &M2, &P);
return ret; if (ret <= 0)
return 0;
NV_DEBUG(dev, "pclk %d out %d NM1 %d %d NM2 %d %d P %d\n",
pclk, ret, N1, M1, N2, M2, P);
if (limits.vco2.maxfreq) { reg1 = nv_rd32(dev, reg + 4) & 0xff00ff00;
reg1 = nv_rd32(dev, pll_reg + 4) & 0xff00ff00; reg2 = nv_rd32(dev, reg + 8) & 0x8000ff00;
reg2 = nv_rd32(dev, pll_reg + 8) & 0x8000ff00; nv_wr32(dev, reg, 0x10000611);
nv_wr32(dev, pll_reg, 0x10000611); nv_wr32(dev, reg + 4, reg1 | (M1 << 16) | N1);
nv_wr32(dev, pll_reg + 4, reg1 | (pll.M1 << 16) | pll.N1); nv_wr32(dev, reg + 8, reg2 | (P << 28) | (M2 << 16) | N2);
nv_wr32(dev, pll_reg + 8,
reg2 | (pll.log2P << 28) | (pll.M2 << 16) | pll.N2);
} else { } else {
reg1 = nv_rd32(dev, pll_reg + 4) & 0xffc00000; ret = nv50_calc_pll2(dev, &pll, pclk, &N1, &N2, &M1, &P);
nv_wr32(dev, pll_reg, 0x50000610); if (ret <= 0)
nv_wr32(dev, pll_reg + 4, reg1 | return 0;
(pll.log2P << 16) | (pll.M1 << 8) | pll.N1);
NV_DEBUG(dev, "pclk %d out %d N %d fN 0x%04x M %d P %d\n",
pclk, ret, N1, N2, M1, P);
reg1 = nv_rd32(dev, reg + 4) & 0xffc00000;
nv_wr32(dev, reg, 0x50000610);
nv_wr32(dev, reg + 4, reg1 | (P << 16) | (M1 << 8) | N1);
nv_wr32(dev, reg + 8, N2);
} }
return 0; return 0;
......
...@@ -783,6 +783,37 @@ nv50_display_unk10_handler(struct drm_device *dev) ...@@ -783,6 +783,37 @@ nv50_display_unk10_handler(struct drm_device *dev)
nv_wr32(dev, 0x610030, 0x80000000); nv_wr32(dev, 0x610030, 0x80000000);
} }
static void
nv50_display_unk20_dp_hack(struct drm_device *dev, struct dcb_entry *dcb)
{
int or = ffs(dcb->or) - 1, link = !(dcb->dpconf.sor.link & 1);
struct drm_encoder *encoder;
uint32_t tmp, unk0 = 0, unk1 = 0;
if (dcb->type != OUTPUT_DP)
return;
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
if (nv_encoder->dcb == dcb) {
unk0 = nv_encoder->dp.unk0;
unk1 = nv_encoder->dp.unk1;
break;
}
}
if (unk0 || unk1) {
tmp = nv_rd32(dev, NV50_SOR_DP_CTRL(or, link));
tmp &= 0xfffffe03;
nv_wr32(dev, NV50_SOR_DP_CTRL(or, link), tmp | unk0);
tmp = nv_rd32(dev, NV50_SOR_DP_UNK128(or, link));
tmp &= 0xfef080c0;
nv_wr32(dev, NV50_SOR_DP_UNK128(or, link), tmp | unk1);
}
}
static void static void
nv50_display_unk20_handler(struct drm_device *dev) nv50_display_unk20_handler(struct drm_device *dev)
{ {
...@@ -806,6 +837,8 @@ nv50_display_unk20_handler(struct drm_device *dev) ...@@ -806,6 +837,8 @@ nv50_display_unk20_handler(struct drm_device *dev)
nouveau_bios_run_display_table(dev, dcbent, script, pclk); nouveau_bios_run_display_table(dev, dcbent, script, pclk);
nv50_display_unk20_dp_hack(dev, dcbent);
tmp = nv_rd32(dev, NV50_PDISPLAY_CRTC_CLK_CTRL2(head)); tmp = nv_rd32(dev, NV50_PDISPLAY_CRTC_CLK_CTRL2(head));
tmp &= ~0x000000f; tmp &= ~0x000000f;
nv_wr32(dev, NV50_PDISPLAY_CRTC_CLK_CTRL2(head), tmp); nv_wr32(dev, NV50_PDISPLAY_CRTC_CLK_CTRL2(head), tmp);
......
...@@ -321,18 +321,23 @@ nv50_sor_create(struct drm_device *dev, struct dcb_entry *entry) ...@@ -321,18 +321,23 @@ nv50_sor_create(struct drm_device *dev, struct dcb_entry *entry)
encoder->possible_clones = 0; encoder->possible_clones = 0;
if (nv_encoder->dcb->type == OUTPUT_DP) { if (nv_encoder->dcb->type == OUTPUT_DP) {
uint32_t mc, or = nv_encoder->or; int or = nv_encoder->or, link = !(entry->dpconf.sor.link & 1);
uint32_t tmp;
if (dev_priv->chipset < 0x90 || if (dev_priv->chipset < 0x90 ||
dev_priv->chipset == 0x92 || dev_priv->chipset == 0xa0) dev_priv->chipset == 0x92 || dev_priv->chipset == 0xa0)
mc = nv_rd32(dev, NV50_PDISPLAY_SOR_MODE_CTRL_C(or)); tmp = nv_rd32(dev, NV50_PDISPLAY_SOR_MODE_CTRL_C(or));
else else
mc = nv_rd32(dev, NV90_PDISPLAY_SOR_MODE_CTRL_C(or)); tmp = nv_rd32(dev, NV90_PDISPLAY_SOR_MODE_CTRL_C(or));
switch ((mc & 0x00000f00) >> 8) { switch ((tmp & 0x00000f00) >> 8) {
case 8: case 8:
case 9: case 9:
nv_encoder->dp.mc_unknown = (mc & 0x000f0000) >> 16; nv_encoder->dp.mc_unknown = (tmp & 0x000f0000) >> 16;
tmp = nv_rd32(dev, NV50_SOR_DP_CTRL(or, link));
nv_encoder->dp.unk0 = tmp & 0x000001fc;
tmp = nv_rd32(dev, NV50_SOR_DP_UNK128(or, link));
nv_encoder->dp.unk1 = tmp & 0x010f7f3f;
break; break;
default: default:
break; break;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment