diff options
author | Josh Boyer <jwboyer@redhat.com> | 2011-10-28 15:04:37 -0400 |
---|---|---|
committer | Josh Boyer <jwboyer@redhat.com> | 2011-10-28 15:42:03 -0400 |
commit | dff08547967b51d0c1a79626647971c508e4106e (patch) | |
tree | 40b21551bb741e71b5cddd31a6f156e660a1a23e /drm-nouveau-updates.patch | |
parent | c813c0daaebd5c4ceeee6faea3580d9c2e50336d (diff) | |
download | kernel-dff08547967b51d0c1a79626647971c508e4106e.tar.gz kernel-dff08547967b51d0c1a79626647971c508e4106e.tar.xz kernel-dff08547967b51d0c1a79626647971c508e4106e.zip |
Linux 3.1-git2 snapshot (upstream f362f98e7c)
Diffstat (limited to 'drm-nouveau-updates.patch')
-rw-r--r-- | drm-nouveau-updates.patch | 8536 |
1 files changed, 0 insertions, 8536 deletions
diff --git a/drm-nouveau-updates.patch b/drm-nouveau-updates.patch deleted file mode 100644 index 1e7c9279e..000000000 --- a/drm-nouveau-updates.patch +++ /dev/null @@ -1,8536 +0,0 @@ -diff --git a/drivers/gpu/drm/nouveau/Makefile b/drivers/gpu/drm/nouveau/Makefile -index 0583677..35ef5b1 100644 ---- a/drivers/gpu/drm/nouveau/Makefile -+++ b/drivers/gpu/drm/nouveau/Makefile -@@ -21,16 +21,17 @@ nouveau-y := nouveau_drv.o nouveau_state.o nouveau_channel.o nouveau_mem.o \ - nv40_grctx.o nv50_grctx.o nvc0_grctx.o \ - nv84_crypt.o \ - nva3_copy.o nvc0_copy.o \ -- nv40_mpeg.o nv50_mpeg.o \ -+ nv31_mpeg.o nv50_mpeg.o \ - nv04_instmem.o nv50_instmem.o nvc0_instmem.o \ -- nv50_evo.o nv50_crtc.o nv50_dac.o nv50_sor.o \ -- nv50_cursor.o nv50_display.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 \ -+ nv50_evo.o nv50_crtc.o nv50_dac.o nv50_sor.o \ -+ nv50_cursor.o nv50_display.o \ -+ nvd0_display.o \ - nv04_fbcon.o nv50_fbcon.o nvc0_fbcon.o \ - nv10_gpio.o nv50_gpio.o \ - nv50_calc.o \ -- nv04_pm.o nv50_pm.o nva3_pm.o \ -+ nv04_pm.o nv40_pm.o nv50_pm.o nva3_pm.o nvc0_pm.o \ - nv50_vram.o nvc0_vram.o \ - nv50_vm.o nvc0_vm.o - -diff --git a/drivers/gpu/drm/nouveau/nouveau_backlight.c b/drivers/gpu/drm/nouveau/nouveau_backlight.c -index 00a55df..fa22b28 100644 ---- a/drivers/gpu/drm/nouveau/nouveau_backlight.c -+++ b/drivers/gpu/drm/nouveau/nouveau_backlight.c -@@ -37,8 +37,10 @@ - #include "nouveau_drv.h" - #include "nouveau_drm.h" - #include "nouveau_reg.h" -+#include "nouveau_encoder.h" - --static int nv40_get_intensity(struct backlight_device *bd) -+static int -+nv40_get_intensity(struct backlight_device *bd) - { - struct drm_device *dev = bl_get_data(bd); - int val = (nv_rd32(dev, NV40_PMC_BACKLIGHT) & NV40_PMC_BACKLIGHT_MASK) -@@ -47,7 +49,8 @@ static int nv40_get_intensity(struct backlight_device *bd) - return val; - } - --static int nv40_set_intensity(struct backlight_device *bd) -+static int -+nv40_set_intensity(struct backlight_device *bd) - { - struct drm_device *dev = bl_get_data(bd); - int val = bd->props.brightness; -@@ -65,30 +68,8 @@ static const struct backlight_ops nv40_bl_ops = { - .update_status = nv40_set_intensity, - }; - --static int nv50_get_intensity(struct backlight_device *bd) --{ -- struct drm_device *dev = bl_get_data(bd); -- -- return nv_rd32(dev, NV50_PDISPLAY_SOR_BACKLIGHT); --} -- --static int nv50_set_intensity(struct backlight_device *bd) --{ -- struct drm_device *dev = bl_get_data(bd); -- int val = bd->props.brightness; -- -- nv_wr32(dev, NV50_PDISPLAY_SOR_BACKLIGHT, -- val | NV50_PDISPLAY_SOR_BACKLIGHT_ENABLE); -- return 0; --} -- --static const struct backlight_ops nv50_bl_ops = { -- .options = BL_CORE_SUSPENDRESUME, -- .get_brightness = nv50_get_intensity, -- .update_status = nv50_set_intensity, --}; -- --static int nouveau_nv40_backlight_init(struct drm_connector *connector) -+static int -+nv40_backlight_init(struct drm_connector *connector) - { - struct drm_device *dev = connector->dev; - struct drm_nouveau_private *dev_priv = dev->dev_private; -@@ -113,34 +94,129 @@ static int nouveau_nv40_backlight_init(struct drm_connector *connector) - return 0; - } - --static int nouveau_nv50_backlight_init(struct drm_connector *connector) -+static int -+nv50_get_intensity(struct backlight_device *bd) -+{ -+ struct nouveau_encoder *nv_encoder = bl_get_data(bd); -+ struct drm_device *dev = nv_encoder->base.base.dev; -+ int or = nv_encoder->or; -+ u32 div = 1025; -+ u32 val; -+ -+ val = nv_rd32(dev, NV50_PDISP_SOR_PWM_CTL(or)); -+ val &= NV50_PDISP_SOR_PWM_CTL_VAL; -+ return ((val * 100) + (div / 2)) / div; -+} -+ -+static int -+nv50_set_intensity(struct backlight_device *bd) -+{ -+ struct nouveau_encoder *nv_encoder = bl_get_data(bd); -+ struct drm_device *dev = nv_encoder->base.base.dev; -+ int or = nv_encoder->or; -+ u32 div = 1025; -+ u32 val = (bd->props.brightness * div) / 100; -+ -+ nv_wr32(dev, NV50_PDISP_SOR_PWM_CTL(or), -+ NV50_PDISP_SOR_PWM_CTL_NEW | val); -+ return 0; -+} -+ -+static const struct backlight_ops nv50_bl_ops = { -+ .options = BL_CORE_SUSPENDRESUME, -+ .get_brightness = nv50_get_intensity, -+ .update_status = nv50_set_intensity, -+}; -+ -+static int -+nva3_get_intensity(struct backlight_device *bd) -+{ -+ struct nouveau_encoder *nv_encoder = bl_get_data(bd); -+ struct drm_device *dev = nv_encoder->base.base.dev; -+ int or = nv_encoder->or; -+ u32 div, val; -+ -+ div = nv_rd32(dev, NV50_PDISP_SOR_PWM_DIV(or)); -+ val = nv_rd32(dev, NV50_PDISP_SOR_PWM_CTL(or)); -+ val &= NVA3_PDISP_SOR_PWM_CTL_VAL; -+ if (div && div >= val) -+ return ((val * 100) + (div / 2)) / div; -+ -+ return 100; -+} -+ -+static int -+nva3_set_intensity(struct backlight_device *bd) -+{ -+ struct nouveau_encoder *nv_encoder = bl_get_data(bd); -+ struct drm_device *dev = nv_encoder->base.base.dev; -+ int or = nv_encoder->or; -+ u32 div, val; -+ -+ div = nv_rd32(dev, NV50_PDISP_SOR_PWM_DIV(or)); -+ val = (bd->props.brightness * div) / 100; -+ if (div) { -+ nv_wr32(dev, NV50_PDISP_SOR_PWM_CTL(or), val | -+ NV50_PDISP_SOR_PWM_CTL_NEW | -+ NVA3_PDISP_SOR_PWM_CTL_UNK); -+ return 0; -+ } -+ -+ return -EINVAL; -+} -+ -+static const struct backlight_ops nva3_bl_ops = { -+ .options = BL_CORE_SUSPENDRESUME, -+ .get_brightness = nva3_get_intensity, -+ .update_status = nva3_set_intensity, -+}; -+ -+static int -+nv50_backlight_init(struct drm_connector *connector) - { - struct drm_device *dev = connector->dev; - struct drm_nouveau_private *dev_priv = dev->dev_private; -+ struct nouveau_encoder *nv_encoder; - struct backlight_properties props; - struct backlight_device *bd; -+ const struct backlight_ops *ops; -+ -+ nv_encoder = find_encoder(connector, OUTPUT_LVDS); -+ if (!nv_encoder) { -+ nv_encoder = find_encoder(connector, OUTPUT_DP); -+ if (!nv_encoder) -+ return -ENODEV; -+ } - -- if (!nv_rd32(dev, NV50_PDISPLAY_SOR_BACKLIGHT)) -+ if (!nv_rd32(dev, NV50_PDISP_SOR_PWM_CTL(nv_encoder->or))) - return 0; - -+ if (dev_priv->chipset <= 0xa0 || -+ dev_priv->chipset == 0xaa || -+ dev_priv->chipset == 0xac) -+ ops = &nv50_bl_ops; -+ else -+ ops = &nva3_bl_ops; -+ - memset(&props, 0, sizeof(struct backlight_properties)); - props.type = BACKLIGHT_RAW; -- props.max_brightness = 1025; -- bd = backlight_device_register("nv_backlight", &connector->kdev, dev, -- &nv50_bl_ops, &props); -+ props.max_brightness = 100; -+ bd = backlight_device_register("nv_backlight", &connector->kdev, -+ nv_encoder, ops, &props); - if (IS_ERR(bd)) - return PTR_ERR(bd); - - dev_priv->backlight = bd; -- bd->props.brightness = nv50_get_intensity(bd); -+ bd->props.brightness = bd->ops->get_brightness(bd); - backlight_update_status(bd); - return 0; - } - --int nouveau_backlight_init(struct drm_connector *connector) -+int -+nouveau_backlight_init(struct drm_device *dev) - { -- struct drm_device *dev = connector->dev; - struct drm_nouveau_private *dev_priv = dev->dev_private; -+ struct drm_connector *connector; - - #ifdef CONFIG_ACPI - if (acpi_video_backlight_support()) { -@@ -150,21 +226,28 @@ int nouveau_backlight_init(struct drm_connector *connector) - } - #endif - -- switch (dev_priv->card_type) { -- case NV_40: -- return nouveau_nv40_backlight_init(connector); -- case NV_50: -- return nouveau_nv50_backlight_init(connector); -- default: -- break; -+ list_for_each_entry(connector, &dev->mode_config.connector_list, head) { -+ if (connector->connector_type != DRM_MODE_CONNECTOR_LVDS && -+ connector->connector_type != DRM_MODE_CONNECTOR_eDP) -+ continue; -+ -+ switch (dev_priv->card_type) { -+ case NV_40: -+ return nv40_backlight_init(connector); -+ case NV_50: -+ return nv50_backlight_init(connector); -+ default: -+ break; -+ } - } - -+ - return 0; - } - --void nouveau_backlight_exit(struct drm_connector *connector) -+void -+nouveau_backlight_exit(struct drm_device *dev) - { -- struct drm_device *dev = connector->dev; - struct drm_nouveau_private *dev_priv = dev->dev_private; - - if (dev_priv->backlight) { -diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c -index b311fab..032a820 100644 ---- a/drivers/gpu/drm/nouveau/nouveau_bios.c -+++ b/drivers/gpu/drm/nouveau/nouveau_bios.c -@@ -296,6 +296,11 @@ munge_reg(struct nvbios *bios, uint32_t reg) - if (dev_priv->card_type < NV_50) - return reg; - -+ if (reg & 0x80000000) { -+ BUG_ON(bios->display.crtc < 0); -+ reg += bios->display.crtc * 0x800; -+ } -+ - if (reg & 0x40000000) { - BUG_ON(!dcbent); - -@@ -304,7 +309,7 @@ munge_reg(struct nvbios *bios, uint32_t reg) - reg += 0x00000080; - } - -- reg &= ~0x60000000; -+ reg &= ~0xe0000000; - return reg; - } - -@@ -1174,22 +1179,19 @@ init_dp_condition(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) - * - */ - -- struct bit_displayport_encoder_table *dpe = NULL; - struct dcb_entry *dcb = bios->display.output; - struct drm_device *dev = bios->dev; - uint8_t cond = bios->data[offset + 1]; -- int dummy; -+ uint8_t *table, *entry; - - BIOSLOG(bios, "0x%04X: subop 0x%02X\n", offset, cond); - - if (!iexec->execute) - return 3; - -- dpe = nouveau_bios_dp_table(dev, dcb, &dummy); -- if (!dpe) { -- NV_ERROR(dev, "0x%04X: INIT_3A: no encoder table!!\n", offset); -+ table = nouveau_dp_bios_data(dev, dcb, &entry); -+ if (!table) - return 3; -- } - - switch (cond) { - case 0: -@@ -1203,7 +1205,7 @@ init_dp_condition(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) - break; - case 1: - case 2: -- if (!(dpe->unknown & cond)) -+ if (!(entry[5] & cond)) - iexec->execute = false; - break; - case 5: -@@ -3221,6 +3223,49 @@ init_8d(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) - return 1; - } - -+static void -+init_gpio_unknv50(struct nvbios *bios, struct dcb_gpio_entry *gpio) -+{ -+ const uint32_t nv50_gpio_ctl[2] = { 0xe100, 0xe28c }; -+ u32 r, s, v; -+ -+ /* Not a clue, needs de-magicing */ -+ r = nv50_gpio_ctl[gpio->line >> 4]; -+ s = (gpio->line & 0x0f); -+ v = bios_rd32(bios, r) & ~(0x00010001 << s); -+ switch ((gpio->entry & 0x06000000) >> 25) { -+ case 1: -+ v |= (0x00000001 << s); -+ break; -+ case 2: -+ v |= (0x00010000 << s); -+ break; -+ default: -+ break; -+ } -+ -+ bios_wr32(bios, r, v); -+} -+ -+static void -+init_gpio_unknvd0(struct nvbios *bios, struct dcb_gpio_entry *gpio) -+{ -+ u32 v, i; -+ -+ v = bios_rd32(bios, 0x00d610 + (gpio->line * 4)); -+ v &= 0xffffff00; -+ v |= (gpio->entry & 0x00ff0000) >> 16; -+ bios_wr32(bios, 0x00d610 + (gpio->line * 4), v); -+ -+ i = (gpio->entry & 0x1f000000) >> 24; -+ if (i) { -+ v = bios_rd32(bios, 0x00d640 + ((i - 1) * 4)); -+ v &= 0xffffff00; -+ v |= gpio->line; -+ bios_wr32(bios, 0x00d640 + ((i - 1) * 4), v); -+ } -+} -+ - static int - init_gpio(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) - { -@@ -3235,7 +3280,6 @@ init_gpio(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) - - struct drm_nouveau_private *dev_priv = bios->dev->dev_private; - struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio; -- const uint32_t nv50_gpio_ctl[2] = { 0xe100, 0xe28c }; - int i; - - if (dev_priv->card_type < NV_50) { -@@ -3248,33 +3292,20 @@ init_gpio(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) - - for (i = 0; i < bios->dcb.gpio.entries; i++) { - struct dcb_gpio_entry *gpio = &bios->dcb.gpio.entry[i]; -- uint32_t r, s, v; - - BIOSLOG(bios, "0x%04X: Entry: 0x%08X\n", offset, gpio->entry); - - BIOSLOG(bios, "0x%04X: set gpio 0x%02x, state %d\n", - offset, gpio->tag, gpio->state_default); -- if (bios->execute) -- pgpio->set(bios->dev, gpio->tag, gpio->state_default); - -- /* The NVIDIA binary driver doesn't appear to actually do -- * any of this, my VBIOS does however. -- */ -- /* Not a clue, needs de-magicing */ -- r = nv50_gpio_ctl[gpio->line >> 4]; -- s = (gpio->line & 0x0f); -- v = bios_rd32(bios, r) & ~(0x00010001 << s); -- switch ((gpio->entry & 0x06000000) >> 25) { -- case 1: -- v |= (0x00000001 << s); -- break; -- case 2: -- v |= (0x00010000 << s); -- break; -- default: -- break; -- } -- bios_wr32(bios, r, v); -+ if (!bios->execute) -+ continue; -+ -+ pgpio->set(bios->dev, gpio->tag, gpio->state_default); -+ if (dev_priv->card_type < NV_D0) -+ init_gpio_unknv50(bios, gpio); -+ else -+ init_gpio_unknvd0(bios, gpio); - } - - return 1; -@@ -3737,6 +3768,10 @@ parse_init_table(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) - int count = 0, i, ret; - uint8_t id; - -+ /* catch NULL script pointers */ -+ if (offset == 0) -+ return 0; -+ - /* - * Loop until INIT_DONE causes us to break out of the loop - * (or until offset > bios length just in case... ) -@@ -4389,86 +4424,37 @@ int nouveau_bios_parse_lvds_table(struct drm_device *dev, int pxclk, bool *dl, b - return 0; - } - --static uint8_t * --bios_output_config_match(struct drm_device *dev, struct dcb_entry *dcbent, -- uint16_t record, int record_len, int record_nr, -- bool match_link) -+/* BIT 'U'/'d' table encoder subtables have hashes matching them to -+ * a particular set of encoders. -+ * -+ * This function returns true if a particular DCB entry matches. -+ */ -+bool -+bios_encoder_match(struct dcb_entry *dcb, u32 hash) - { -- struct drm_nouveau_private *dev_priv = dev->dev_private; -- struct nvbios *bios = &dev_priv->vbios; -- uint32_t entry; -- uint16_t table; -- int i, v; -+ if ((hash & 0x000000f0) != (dcb->location << 4)) -+ return false; -+ if ((hash & 0x0000000f) != dcb->type) -+ return false; -+ if (!(hash & (dcb->or << 16))) -+ return false; - -- switch (dcbent->type) { -+ switch (dcb->type) { - case OUTPUT_TMDS: - case OUTPUT_LVDS: - case OUTPUT_DP: -- break; -- default: -- match_link = false; -- break; -- } -- -- for (i = 0; i < record_nr; i++, record += record_len) { -- table = ROM16(bios->data[record]); -- if (!table) -- continue; -- entry = ROM32(bios->data[table]); -- -- if (match_link) { -- v = (entry & 0x00c00000) >> 22; -- if (!(v & dcbent->sorconf.link)) -- continue; -+ if (hash & 0x00c00000) { -+ if (!(hash & (dcb->sorconf.link << 22))) -+ return false; - } -- -- v = (entry & 0x000f0000) >> 16; -- if (!(v & dcbent->or)) -- continue; -- -- v = (entry & 0x000000f0) >> 4; -- if (v != dcbent->location) -- continue; -- -- v = (entry & 0x0000000f); -- if (v != dcbent->type) -- continue; -- -- return &bios->data[table]; -- } -- -- return NULL; --} -- --void * --nouveau_bios_dp_table(struct drm_device *dev, struct dcb_entry *dcbent, -- int *length) --{ -- struct drm_nouveau_private *dev_priv = dev->dev_private; -- struct nvbios *bios = &dev_priv->vbios; -- uint8_t *table; -- -- if (!bios->display.dp_table_ptr) { -- NV_ERROR(dev, "No pointer to DisplayPort table\n"); -- return NULL; -- } -- table = &bios->data[bios->display.dp_table_ptr]; -- -- if (table[0] != 0x20 && table[0] != 0x21) { -- NV_ERROR(dev, "DisplayPort table version 0x%02x unknown\n", -- table[0]); -- return NULL; -+ default: -+ return true; - } -- -- *length = table[4]; -- return bios_output_config_match(dev, dcbent, -- bios->display.dp_table_ptr + table[1], -- table[2], table[3], table[0] >= 0x21); - } - - int --nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent, -- uint32_t sub, int pxclk) -+nouveau_bios_run_display_table(struct drm_device *dev, u16 type, int pclk, -+ struct dcb_entry *dcbent, int crtc) - { - /* - * The display script table is located by the BIT 'U' table. -@@ -4498,7 +4484,7 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent, - uint8_t *table = &bios->data[bios->display.script_table_ptr]; - uint8_t *otable = NULL; - uint16_t script; -- int i = 0; -+ int i; - - if (!bios->display.script_table_ptr) { - NV_ERROR(dev, "No pointer to output script table\n"); -@@ -4550,30 +4536,33 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent, - - NV_DEBUG_KMS(dev, "Searching for output entry for %d %d %d\n", - dcbent->type, dcbent->location, dcbent->or); -- otable = bios_output_config_match(dev, dcbent, table[1] + -- bios->display.script_table_ptr, -- table[2], table[3], table[0] >= 0x21); -+ for (i = 0; i < table[3]; i++) { -+ otable = ROMPTR(bios, table[table[1] + (i * table[2])]); -+ if (otable && bios_encoder_match(dcbent, ROM32(otable[0]))) -+ break; -+ } -+ - if (!otable) { - NV_DEBUG_KMS(dev, "failed to match any output table\n"); - return 1; - } - -- if (pxclk < -2 || pxclk > 0) { -+ if (pclk < -2 || pclk > 0) { - /* Try to find matching script table entry */ - for (i = 0; i < otable[5]; i++) { -- if (ROM16(otable[table[4] + i*6]) == sub) -+ if (ROM16(otable[table[4] + i*6]) == type) - break; - } - - if (i == otable[5]) { - NV_ERROR(dev, "Table 0x%04x not found for %d/%d, " - "using first\n", -- sub, dcbent->type, dcbent->or); -+ type, dcbent->type, dcbent->or); - i = 0; - } - } - -- if (pxclk == 0) { -+ if (pclk == 0) { - script = ROM16(otable[6]); - if (!script) { - NV_DEBUG_KMS(dev, "output script 0 not found\n"); -@@ -4581,9 +4570,9 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent, - } - - NV_DEBUG_KMS(dev, "0x%04X: parsing output script 0\n", script); -- nouveau_bios_run_init_table(dev, script, dcbent); -+ nouveau_bios_run_init_table(dev, script, dcbent, crtc); - } else -- if (pxclk == -1) { -+ if (pclk == -1) { - script = ROM16(otable[8]); - if (!script) { - NV_DEBUG_KMS(dev, "output script 1 not found\n"); -@@ -4591,9 +4580,9 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent, - } - - NV_DEBUG_KMS(dev, "0x%04X: parsing output script 1\n", script); -- nouveau_bios_run_init_table(dev, script, dcbent); -+ nouveau_bios_run_init_table(dev, script, dcbent, crtc); - } else -- if (pxclk == -2) { -+ if (pclk == -2) { - if (table[4] >= 12) - script = ROM16(otable[10]); - else -@@ -4604,31 +4593,31 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent, - } - - NV_DEBUG_KMS(dev, "0x%04X: parsing output script 2\n", script); -- nouveau_bios_run_init_table(dev, script, dcbent); -+ nouveau_bios_run_init_table(dev, script, dcbent, crtc); - } else -- if (pxclk > 0) { -+ if (pclk > 0) { - script = ROM16(otable[table[4] + i*6 + 2]); - if (script) -- script = clkcmptable(bios, script, pxclk); -+ script = clkcmptable(bios, script, pclk); - if (!script) { - NV_DEBUG_KMS(dev, "clock script 0 not found\n"); - return 1; - } - - NV_DEBUG_KMS(dev, "0x%04X: parsing clock script 0\n", script); -- nouveau_bios_run_init_table(dev, script, dcbent); -+ nouveau_bios_run_init_table(dev, script, dcbent, crtc); - } else -- if (pxclk < 0) { -+ if (pclk < 0) { - script = ROM16(otable[table[4] + i*6 + 4]); - if (script) -- script = clkcmptable(bios, script, -pxclk); -+ script = clkcmptable(bios, script, -pclk); - if (!script) { - NV_DEBUG_KMS(dev, "clock script 1 not found\n"); - return 1; - } - - NV_DEBUG_KMS(dev, "0x%04X: parsing clock script 1\n", script); -- nouveau_bios_run_init_table(dev, script, dcbent); -+ nouveau_bios_run_init_table(dev, script, dcbent, crtc); - } - - return 0; -@@ -5478,14 +5467,6 @@ parse_bit_U_tbl_entry(struct drm_device *dev, struct nvbios *bios, - return 0; - } - --static int --parse_bit_displayport_tbl_entry(struct drm_device *dev, struct nvbios *bios, -- struct bit_entry *bitentry) --{ -- bios->display.dp_table_ptr = ROM16(bios->data[bitentry->offset]); -- return 0; --} -- - struct bit_table { - const char id; - int (* const parse_fn)(struct drm_device *, struct nvbios *, struct bit_entry *); -@@ -5559,7 +5540,6 @@ parse_bit_structure(struct nvbios *bios, const uint16_t bitoffset) - parse_bit_table(bios, bitoffset, &BIT_TABLE('L', lvds)); - parse_bit_table(bios, bitoffset, &BIT_TABLE('T', tmds)); - parse_bit_table(bios, bitoffset, &BIT_TABLE('U', U)); -- parse_bit_table(bios, bitoffset, &BIT_TABLE('d', displayport)); - - return 0; - } -@@ -5884,9 +5864,15 @@ parse_dcb_gpio_table(struct nvbios *bios) - } - - e->line = (e->entry & 0x0000001f) >> 0; -- e->state_default = (e->entry & 0x01000000) >> 24; -- e->state[0] = (e->entry & 0x18000000) >> 27; -- e->state[1] = (e->entry & 0x60000000) >> 29; -+ if (gpio[0] == 0x40) { -+ e->state_default = (e->entry & 0x01000000) >> 24; -+ e->state[0] = (e->entry & 0x18000000) >> 27; -+ e->state[1] = (e->entry & 0x60000000) >> 29; -+ } else { -+ e->state_default = (e->entry & 0x00000080) >> 7; -+ e->state[0] = (entry[4] >> 4) & 3; -+ e->state[1] = (entry[4] >> 6) & 3; -+ } - } - } - -@@ -6156,7 +6142,14 @@ parse_dcb20_entry(struct drm_device *dev, struct dcb_table *dcb, - } - case OUTPUT_DP: - entry->dpconf.sor.link = (conf & 0x00000030) >> 4; -- entry->dpconf.link_bw = (conf & 0x00e00000) >> 21; -+ switch ((conf & 0x00e00000) >> 21) { -+ case 0: -+ entry->dpconf.link_bw = 162000; -+ break; -+ default: -+ entry->dpconf.link_bw = 270000; -+ break; -+ } - switch ((conf & 0x0f000000) >> 24) { - case 0xf: - entry->dpconf.link_nr = 4; -@@ -6769,7 +6762,7 @@ uint8_t *nouveau_bios_embedded_edid(struct drm_device *dev) - - void - nouveau_bios_run_init_table(struct drm_device *dev, uint16_t table, -- struct dcb_entry *dcbent) -+ struct dcb_entry *dcbent, int crtc) - { - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nvbios *bios = &dev_priv->vbios; -@@ -6777,11 +6770,22 @@ nouveau_bios_run_init_table(struct drm_device *dev, uint16_t table, - - spin_lock_bh(&bios->lock); - bios->display.output = dcbent; -+ bios->display.crtc = crtc; - parse_init_table(bios, table, &iexec); - bios->display.output = NULL; - spin_unlock_bh(&bios->lock); - } - -+void -+nouveau_bios_init_exec(struct drm_device *dev, uint16_t table) -+{ -+ struct drm_nouveau_private *dev_priv = dev->dev_private; -+ struct nvbios *bios = &dev_priv->vbios; -+ struct init_exec iexec = { true, false }; -+ -+ parse_init_table(bios, table, &iexec); -+} -+ - static bool NVInitVBIOS(struct drm_device *dev) - { - struct drm_nouveau_private *dev_priv = dev->dev_private; -@@ -6863,9 +6867,8 @@ nouveau_run_vbios_init(struct drm_device *dev) - - if (dev_priv->card_type >= NV_50) { - for (i = 0; i < bios->dcb.entries; i++) { -- nouveau_bios_run_display_table(dev, -- &bios->dcb.entry[i], -- 0, 0); -+ nouveau_bios_run_display_table(dev, 0, 0, -+ &bios->dcb.entry[i], -1); - } - } - -diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.h b/drivers/gpu/drm/nouveau/nouveau_bios.h -index 050c314..8adb69e 100644 ---- a/drivers/gpu/drm/nouveau/nouveau_bios.h -+++ b/drivers/gpu/drm/nouveau/nouveau_bios.h -@@ -289,8 +289,8 @@ struct nvbios { - - struct { - struct dcb_entry *output; -+ int crtc; - uint16_t script_table_ptr; -- uint16_t dp_table_ptr; - } display; - - struct { -diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c -index 890d50e..7226f41 100644 ---- a/drivers/gpu/drm/nouveau/nouveau_bo.c -+++ b/drivers/gpu/drm/nouveau/nouveau_bo.c -@@ -956,7 +956,7 @@ nouveau_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem) - break; - } - -- if (dev_priv->card_type == NV_C0) -+ if (dev_priv->card_type >= NV_C0) - page_shift = node->page_shift; - else - page_shift = 12; -diff --git a/drivers/gpu/drm/nouveau/nouveau_channel.c b/drivers/gpu/drm/nouveau/nouveau_channel.c -index b0d753f..a319d56 100644 ---- a/drivers/gpu/drm/nouveau/nouveau_channel.c -+++ b/drivers/gpu/drm/nouveau/nouveau_channel.c -@@ -411,13 +411,17 @@ nouveau_ioctl_fifo_alloc(struct drm_device *dev, void *data, - return ret; - init->channel = chan->id; - -- if (chan->dma.ib_max) -- init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_VRAM | -- NOUVEAU_GEM_DOMAIN_GART; -- else if (chan->pushbuf_bo->bo.mem.mem_type == TTM_PL_VRAM) -+ if (nouveau_vram_pushbuf == 0) { -+ if (chan->dma.ib_max) -+ init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_VRAM | -+ NOUVEAU_GEM_DOMAIN_GART; -+ else if (chan->pushbuf_bo->bo.mem.mem_type == TTM_PL_VRAM) -+ init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_VRAM; -+ else -+ init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_GART; -+ } else { - init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_VRAM; -- else -- init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_GART; -+ } - - if (dev_priv->card_type < NV_C0) { - init->subchan[0].handle = NvM2MF; -diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c -index 939d4df..e0d275e 100644 ---- a/drivers/gpu/drm/nouveau/nouveau_connector.c -+++ b/drivers/gpu/drm/nouveau/nouveau_connector.c -@@ -39,7 +39,7 @@ - - static void nouveau_connector_hotplug(void *, int); - --static struct nouveau_encoder * -+struct nouveau_encoder * - find_encoder(struct drm_connector *connector, int type) - { - struct drm_device *dev = connector->dev; -@@ -116,10 +116,6 @@ nouveau_connector_destroy(struct drm_connector *connector) - nouveau_connector_hotplug, connector); - } - -- if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS || -- connector->connector_type == DRM_MODE_CONNECTOR_eDP) -- nouveau_backlight_exit(connector); -- - kfree(nv_connector->edid); - drm_sysfs_connector_remove(connector); - drm_connector_cleanup(connector); -@@ -712,11 +708,8 @@ nouveau_connector_mode_valid(struct drm_connector *connector, - case OUTPUT_TV: - return get_slave_funcs(encoder)->mode_valid(encoder, mode); - case OUTPUT_DP: -- if (nv_encoder->dp.link_bw == DP_LINK_BW_2_7) -- max_clock = nv_encoder->dp.link_nr * 270000; -- else -- max_clock = nv_encoder->dp.link_nr * 162000; -- -+ max_clock = nv_encoder->dp.link_nr; -+ max_clock *= nv_encoder->dp.link_bw; - clock = clock * nouveau_connector_bpp(connector) / 8; - break; - default: -@@ -871,7 +864,6 @@ 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,27 +880,20 @@ 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 (connector->connector_type != DRM_MODE_CONNECTOR_LVDS) { -- if (dev_priv->card_type >= NV_50) -- connector->polled = DRM_CONNECTOR_POLL_HPD; -- else -- connector->polled = DRM_CONNECTOR_POLL_CONNECT; -- } - break; - } - -- if (pgpio->irq_register) { -+ if (nv_connector->dcb->gpio_tag != 0xff && pgpio->irq_register) { - pgpio->irq_register(dev, nv_connector->dcb->gpio_tag, - nouveau_connector_hotplug, connector); -+ -+ connector->polled = DRM_CONNECTOR_POLL_HPD; -+ } else { -+ connector->polled = DRM_CONNECTOR_POLL_CONNECT; - } - - drm_sysfs_connector_add(connector); - -- if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS || -- connector->connector_type == DRM_MODE_CONNECTOR_eDP) -- nouveau_backlight_init(connector); -- - dcb->drm = connector; - return dcb->drm; - -@@ -925,22 +910,13 @@ nouveau_connector_hotplug(void *data, int plugged) - struct drm_connector *connector = data; - struct drm_device *dev = connector->dev; - -- NV_INFO(dev, "%splugged %s\n", plugged ? "" : "un", -- drm_get_connector_name(connector)); -- -- if (connector->encoder && connector->encoder->crtc && -- connector->encoder->crtc->enabled) { -- struct nouveau_encoder *nv_encoder = nouveau_encoder(connector->encoder); -- struct drm_encoder_helper_funcs *helper = -- connector->encoder->helper_private; -+ NV_DEBUG(dev, "%splugged %s\n", plugged ? "" : "un", -+ drm_get_connector_name(connector)); - -- if (nv_encoder->dcb->type == OUTPUT_DP) { -- if (plugged) -- helper->dpms(connector->encoder, DRM_MODE_DPMS_ON); -- else -- helper->dpms(connector->encoder, DRM_MODE_DPMS_OFF); -- } -- } -+ if (plugged) -+ drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON); -+ else -+ drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF); - - drm_helper_hpd_irq_event(dev); - } -diff --git a/drivers/gpu/drm/nouveau/nouveau_crtc.h b/drivers/gpu/drm/nouveau/nouveau_crtc.h -index cb1ce2a..bf8e128 100644 ---- a/drivers/gpu/drm/nouveau/nouveau_crtc.h -+++ b/drivers/gpu/drm/nouveau/nouveau_crtc.h -@@ -82,14 +82,13 @@ static inline struct drm_crtc *to_drm_crtc(struct nouveau_crtc *crtc) - } - - int nv50_crtc_create(struct drm_device *dev, int index); --int nv50_cursor_init(struct nouveau_crtc *); --void nv50_cursor_fini(struct nouveau_crtc *); - int nv50_crtc_cursor_set(struct drm_crtc *drm_crtc, struct drm_file *file_priv, - uint32_t buffer_handle, uint32_t width, - uint32_t height); - int nv50_crtc_cursor_move(struct drm_crtc *drm_crtc, int x, int y); - - int nv04_cursor_init(struct nouveau_crtc *); -+int nv50_cursor_init(struct nouveau_crtc *); - - struct nouveau_connector * - nouveau_crtc_connector_get(struct nouveau_crtc *crtc); -diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c -index eb514ea..ddbabef 100644 ---- a/drivers/gpu/drm/nouveau/nouveau_display.c -+++ b/drivers/gpu/drm/nouveau/nouveau_display.c -@@ -105,9 +105,12 @@ nouveau_framebuffer_init(struct drm_device *dev, - if (dev_priv->chipset == 0x50) - nv_fb->r_format |= (tile_flags << 8); - -- if (!tile_flags) -- nv_fb->r_pitch = 0x00100000 | fb->pitch; -- else { -+ if (!tile_flags) { -+ if (dev_priv->card_type < NV_D0) -+ nv_fb->r_pitch = 0x00100000 | fb->pitch; -+ else -+ nv_fb->r_pitch = 0x01000000 | fb->pitch; -+ } else { - u32 mode = nvbo->tile_mode; - if (dev_priv->card_type >= NV_C0) - mode >>= 4; -diff --git a/drivers/gpu/drm/nouveau/nouveau_dp.c b/drivers/gpu/drm/nouveau/nouveau_dp.c -index 7beb82a..de5efe7 100644 ---- a/drivers/gpu/drm/nouveau/nouveau_dp.c -+++ b/drivers/gpu/drm/nouveau/nouveau_dp.c -@@ -28,418 +28,619 @@ - #include "nouveau_i2c.h" - #include "nouveau_connector.h" - #include "nouveau_encoder.h" -+#include "nouveau_crtc.h" -+ -+/****************************************************************************** -+ * aux channel util functions -+ *****************************************************************************/ -+#define AUX_DBG(fmt, args...) do { \ -+ if (nouveau_reg_debug & NOUVEAU_REG_DEBUG_AUXCH) { \ -+ NV_PRINTK(KERN_DEBUG, dev, "AUXCH(%d): " fmt, ch, ##args); \ -+ } \ -+} while (0) -+#define AUX_ERR(fmt, args...) NV_ERROR(dev, "AUXCH(%d): " fmt, ch, ##args) -+ -+static void -+auxch_fini(struct drm_device *dev, int ch) -+{ -+ nv_mask(dev, 0x00e4e4 + (ch * 0x50), 0x00310000, 0x00000000); -+} - - static int --auxch_rd(struct drm_encoder *encoder, int address, uint8_t *buf, int size) -+auxch_init(struct drm_device *dev, int ch) - { -- struct drm_device *dev = encoder->dev; -- struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); -- struct nouveau_i2c_chan *auxch; -- int ret; -- -- auxch = nouveau_i2c_find(dev, nv_encoder->dcb->i2c_index); -- if (!auxch) -- return -ENODEV; -- -- ret = nouveau_dp_auxch(auxch, 9, address, buf, size); -- if (ret) -- return ret; -+ const u32 unksel = 1; /* nfi which to use, or if it matters.. */ -+ const u32 ureq = unksel ? 0x00100000 : 0x00200000; -+ const u32 urep = unksel ? 0x01000000 : 0x02000000; -+ u32 ctrl, timeout; -+ -+ /* wait up to 1ms for any previous transaction to be done... */ -+ timeout = 1000; -+ do { -+ ctrl = nv_rd32(dev, 0x00e4e4 + (ch * 0x50)); -+ udelay(1); -+ if (!timeout--) { -+ AUX_ERR("begin idle timeout 0x%08x", ctrl); -+ return -EBUSY; -+ } -+ } while (ctrl & 0x03010000); -+ -+ /* set some magic, and wait up to 1ms for it to appear */ -+ nv_mask(dev, 0x00e4e4 + (ch * 0x50), 0x00300000, ureq); -+ timeout = 1000; -+ do { -+ ctrl = nv_rd32(dev, 0x00e4e4 + (ch * 0x50)); -+ udelay(1); -+ if (!timeout--) { -+ AUX_ERR("magic wait 0x%08x\n", ctrl); -+ auxch_fini(dev, ch); -+ return -EBUSY; -+ } -+ } while ((ctrl & 0x03000000) != urep); - - return 0; - } - - static int --auxch_wr(struct drm_encoder *encoder, int address, uint8_t *buf, int size) -+auxch_tx(struct drm_device *dev, int ch, u8 type, u32 addr, u8 *data, u8 size) - { -- struct drm_device *dev = encoder->dev; -- struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); -- struct nouveau_i2c_chan *auxch; -- int ret; -+ u32 ctrl, stat, timeout, retries; -+ u32 xbuf[4] = {}; -+ int ret, i; - -- auxch = nouveau_i2c_find(dev, nv_encoder->dcb->i2c_index); -- if (!auxch) -- return -ENODEV; -+ AUX_DBG("%d: 0x%08x %d\n", type, addr, size); - -- ret = nouveau_dp_auxch(auxch, 8, address, buf, size); -- return ret; --} -+ ret = auxch_init(dev, ch); -+ if (ret) -+ goto out; - --static int --nouveau_dp_lane_count_set(struct drm_encoder *encoder, uint8_t cmd) --{ -- struct drm_device *dev = encoder->dev; -- struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); -- uint32_t tmp; -- int or = nv_encoder->or, link = !(nv_encoder->dcb->sorconf.link & 1); -- -- tmp = nv_rd32(dev, NV50_SOR_DP_CTRL(or, link)); -- tmp &= ~(NV50_SOR_DP_CTRL_ENHANCED_FRAME_ENABLED | -- NV50_SOR_DP_CTRL_LANE_MASK); -- tmp |= ((1 << (cmd & DP_LANE_COUNT_MASK)) - 1) << 16; -- if (cmd & DP_LANE_COUNT_ENHANCED_FRAME_EN) -- tmp |= NV50_SOR_DP_CTRL_ENHANCED_FRAME_ENABLED; -- nv_wr32(dev, NV50_SOR_DP_CTRL(or, link), tmp); -- -- return auxch_wr(encoder, DP_LANE_COUNT_SET, &cmd, 1); --} -+ stat = nv_rd32(dev, 0x00e4e8 + (ch * 0x50)); -+ if (!(stat & 0x10000000)) { -+ AUX_DBG("sink not detected\n"); -+ ret = -ENXIO; -+ goto out; -+ } - --static int --nouveau_dp_link_bw_set(struct drm_encoder *encoder, uint8_t cmd) --{ -- struct drm_device *dev = encoder->dev; -- struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); -- uint32_t tmp; -- int reg = 0x614300 + (nv_encoder->or * 0x800); -+ if (!(type & 1)) { -+ memcpy(xbuf, data, size); -+ for (i = 0; i < 16; i += 4) { -+ AUX_DBG("wr 0x%08x\n", xbuf[i / 4]); -+ nv_wr32(dev, 0x00e4c0 + (ch * 0x50) + i, xbuf[i / 4]); -+ } -+ } - -- tmp = nv_rd32(dev, reg); -- tmp &= 0xfff3ffff; -- if (cmd == DP_LINK_BW_2_7) -- tmp |= 0x00040000; -- nv_wr32(dev, reg, tmp); -+ ctrl = nv_rd32(dev, 0x00e4e4 + (ch * 0x50)); -+ ctrl &= ~0x0001f0ff; -+ ctrl |= type << 12; -+ ctrl |= size - 1; -+ nv_wr32(dev, 0x00e4e0 + (ch * 0x50), addr); -+ -+ /* retry transaction a number of times on failure... */ -+ ret = -EREMOTEIO; -+ for (retries = 0; retries < 32; retries++) { -+ /* reset, and delay a while if this is a retry */ -+ nv_wr32(dev, 0x00e4e4 + (ch * 0x50), 0x80000000 | ctrl); -+ nv_wr32(dev, 0x00e4e4 + (ch * 0x50), 0x00000000 | ctrl); -+ if (retries) -+ udelay(400); -+ -+ /* transaction request, wait up to 1ms for it to complete */ -+ nv_wr32(dev, 0x00e4e4 + (ch * 0x50), 0x00010000 | ctrl); -+ -+ timeout = 1000; -+ do { -+ ctrl = nv_rd32(dev, 0x00e4e4 + (ch * 0x50)); -+ udelay(1); -+ if (!timeout--) { -+ AUX_ERR("tx req timeout 0x%08x\n", ctrl); -+ goto out; -+ } -+ } while (ctrl & 0x00010000); - -- return auxch_wr(encoder, DP_LINK_BW_SET, &cmd, 1); --} -+ /* read status, and check if transaction completed ok */ -+ stat = nv_mask(dev, 0x00e4e8 + (ch * 0x50), 0, 0); -+ if (!(stat & 0x000f0f00)) { -+ ret = 0; -+ break; -+ } - --static int --nouveau_dp_link_train_set(struct drm_encoder *encoder, int pattern) --{ -- struct drm_device *dev = encoder->dev; -- struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); -- uint32_t tmp; -- uint8_t cmd; -- int or = nv_encoder->or, link = !(nv_encoder->dcb->sorconf.link & 1); -- int ret; -+ AUX_DBG("%02d 0x%08x 0x%08x\n", retries, ctrl, stat); -+ } - -- tmp = nv_rd32(dev, NV50_SOR_DP_CTRL(or, link)); -- tmp &= ~NV50_SOR_DP_CTRL_TRAINING_PATTERN; -- tmp |= (pattern << 24); -- nv_wr32(dev, NV50_SOR_DP_CTRL(or, link), tmp); -+ if (type & 1) { -+ for (i = 0; i < 16; i += 4) { -+ xbuf[i / 4] = nv_rd32(dev, 0x00e4d0 + (ch * 0x50) + i); -+ AUX_DBG("rd 0x%08x\n", xbuf[i / 4]); -+ } -+ memcpy(data, xbuf, size); -+ } - -- ret = auxch_rd(encoder, DP_TRAINING_PATTERN_SET, &cmd, 1); -- if (ret) -- return ret; -- cmd &= ~DP_TRAINING_PATTERN_MASK; -- cmd |= (pattern & DP_TRAINING_PATTERN_MASK); -- return auxch_wr(encoder, DP_TRAINING_PATTERN_SET, &cmd, 1); -+out: -+ auxch_fini(dev, ch); -+ return ret; - } - --static int --nouveau_dp_max_voltage_swing(struct drm_encoder *encoder) -+static u32 -+dp_link_bw_get(struct drm_device *dev, int or, int link) - { -- struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); -- struct drm_device *dev = encoder->dev; -- struct bit_displayport_encoder_table_entry *dpse; -- struct bit_displayport_encoder_table *dpe; -- int i, dpe_headerlen, max_vs = 0; -- -- dpe = nouveau_bios_dp_table(dev, nv_encoder->dcb, &dpe_headerlen); -- if (!dpe) -- return false; -- dpse = (void *)((char *)dpe + dpe_headerlen); -+ u32 ctrl = nv_rd32(dev, 0x614300 + (or * 0x800)); -+ if (!(ctrl & 0x000c0000)) -+ return 162000; -+ return 270000; -+} - -- for (i = 0; i < dpe_headerlen; i++, dpse++) { -- if (dpse->vs_level > max_vs) -- max_vs = dpse->vs_level; -+static int -+dp_lane_count_get(struct drm_device *dev, int or, int link) -+{ -+ u32 ctrl = nv_rd32(dev, NV50_SOR_DP_CTRL(or, link)); -+ switch (ctrl & 0x000f0000) { -+ case 0x00010000: return 1; -+ case 0x00030000: return 2; -+ default: -+ return 4; - } -- -- return max_vs; - } - --static int --nouveau_dp_max_pre_emphasis(struct drm_encoder *encoder, int vs) -+void -+nouveau_dp_tu_update(struct drm_device *dev, int or, int link, u32 clk, u32 bpp) - { -- struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); -- struct drm_device *dev = encoder->dev; -- struct bit_displayport_encoder_table_entry *dpse; -- struct bit_displayport_encoder_table *dpe; -- int i, dpe_headerlen, max_pre = 0; -+ const u32 symbol = 100000; -+ int bestTU = 0, bestVTUi = 0, bestVTUf = 0, bestVTUa = 0; -+ int TU, VTUi, VTUf, VTUa; -+ u64 link_data_rate, link_ratio, unk; -+ u32 best_diff = 64 * symbol; -+ u32 link_nr, link_bw, r; -+ -+ /* calculate packed data rate for each lane */ -+ link_nr = dp_lane_count_get(dev, or, link); -+ link_data_rate = (clk * bpp / 8) / link_nr; -+ -+ /* calculate ratio of packed data rate to link symbol rate */ -+ link_bw = dp_link_bw_get(dev, or, link); -+ link_ratio = link_data_rate * symbol; -+ r = do_div(link_ratio, link_bw); -+ -+ for (TU = 64; TU >= 32; TU--) { -+ /* calculate average number of valid symbols in each TU */ -+ u32 tu_valid = link_ratio * TU; -+ u32 calc, diff; -+ -+ /* find a hw representation for the fraction.. */ -+ VTUi = tu_valid / symbol; -+ calc = VTUi * symbol; -+ diff = tu_valid - calc; -+ if (diff) { -+ if (diff >= (symbol / 2)) { -+ VTUf = symbol / (symbol - diff); -+ if (symbol - (VTUf * diff)) -+ VTUf++; -+ -+ if (VTUf <= 15) { -+ VTUa = 1; -+ calc += symbol - (symbol / VTUf); -+ } else { -+ VTUa = 0; -+ VTUf = 1; -+ calc += symbol; -+ } -+ } else { -+ VTUa = 0; -+ VTUf = min((int)(symbol / diff), 15); -+ calc += symbol / VTUf; -+ } - -- dpe = nouveau_bios_dp_table(dev, nv_encoder->dcb, &dpe_headerlen); -- if (!dpe) -- return false; -- dpse = (void *)((char *)dpe + dpe_headerlen); -+ diff = calc - tu_valid; -+ } else { -+ /* no remainder, but the hw doesn't like the fractional -+ * part to be zero. decrement the integer part and -+ * have the fraction add a whole symbol back -+ */ -+ VTUa = 0; -+ VTUf = 1; -+ VTUi--; -+ } - -- for (i = 0; i < dpe_headerlen; i++, dpse++) { -- if (dpse->vs_level != vs) -- continue; -+ if (diff < best_diff) { -+ best_diff = diff; -+ bestTU = TU; -+ bestVTUa = VTUa; -+ bestVTUf = VTUf; -+ bestVTUi = VTUi; -+ if (diff == 0) -+ break; -+ } -+ } - -- if (dpse->pre_level > max_pre) -- max_pre = dpse->pre_level; -+ if (!bestTU) { -+ NV_ERROR(dev, "DP: unable to find suitable config\n"); -+ return; - } - -- return max_pre; -+ /* XXX close to vbios numbers, but not right */ -+ unk = (symbol - link_ratio) * bestTU; -+ unk *= link_ratio; -+ r = do_div(unk, symbol); -+ r = do_div(unk, symbol); -+ unk += 6; -+ -+ nv_mask(dev, NV50_SOR_DP_CTRL(or, link), 0x000001fc, bestTU << 2); -+ nv_mask(dev, NV50_SOR_DP_SCFG(or, link), 0x010f7f3f, bestVTUa << 24 | -+ bestVTUf << 16 | -+ bestVTUi << 8 | -+ unk); - } - --static bool --nouveau_dp_link_train_adjust(struct drm_encoder *encoder, uint8_t *config) -+u8 * -+nouveau_dp_bios_data(struct drm_device *dev, struct dcb_entry *dcb, u8 **entry) - { -- struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); -- struct drm_device *dev = encoder->dev; -- struct bit_displayport_encoder_table *dpe; -- int ret, i, dpe_headerlen, vs = 0, pre = 0; -- uint8_t request[2]; -- -- dpe = nouveau_bios_dp_table(dev, nv_encoder->dcb, &dpe_headerlen); -- if (!dpe) -- return false; -- -- ret = auxch_rd(encoder, DP_ADJUST_REQUEST_LANE0_1, request, 2); -- if (ret) -- return false; -- -- NV_DEBUG_KMS(dev, "\t\tadjust 0x%02x 0x%02x\n", request[0], request[1]); -- -- /* Keep all lanes at the same level.. */ -- for (i = 0; i < nv_encoder->dp.link_nr; i++) { -- int lane_req = (request[i >> 1] >> ((i & 1) << 2)) & 0xf; -- int lane_vs = lane_req & 3; -- int lane_pre = (lane_req >> 2) & 3; -+ struct drm_nouveau_private *dev_priv = dev->dev_private; -+ struct nvbios *bios = &dev_priv->vbios; -+ struct bit_entry d; -+ u8 *table; -+ int i; -+ -+ if (bit_table(dev, 'd', &d)) { -+ NV_ERROR(dev, "BIT 'd' table not found\n"); -+ return NULL; -+ } - -- if (lane_vs > vs) -- vs = lane_vs; -- if (lane_pre > pre) -- pre = lane_pre; -+ if (d.version != 1) { -+ NV_ERROR(dev, "BIT 'd' table version %d unknown\n", d.version); -+ return NULL; - } - -- if (vs >= nouveau_dp_max_voltage_swing(encoder)) { -- vs = nouveau_dp_max_voltage_swing(encoder); -- vs |= 4; -+ table = ROMPTR(bios, d.data[0]); -+ if (!table) { -+ NV_ERROR(dev, "displayport table pointer invalid\n"); -+ return NULL; - } - -- if (pre >= nouveau_dp_max_pre_emphasis(encoder, vs & 3)) { -- pre = nouveau_dp_max_pre_emphasis(encoder, vs & 3); -- pre |= 4; -+ switch (table[0]) { -+ case 0x20: -+ case 0x21: -+ case 0x30: -+ break; -+ default: -+ NV_ERROR(dev, "displayport table 0x%02x unknown\n", table[0]); -+ return NULL; - } - -- /* Update the configuration for all lanes.. */ -- for (i = 0; i < nv_encoder->dp.link_nr; i++) -- config[i] = (pre << 3) | vs; -+ for (i = 0; i < table[3]; i++) { -+ *entry = ROMPTR(bios, table[table[1] + (i * table[2])]); -+ if (*entry && bios_encoder_match(dcb, ROM32((*entry)[0]))) -+ return table; -+ } - -- return true; -+ NV_ERROR(dev, "displayport encoder table not found\n"); -+ return NULL; - } - --static bool --nouveau_dp_link_train_commit(struct drm_encoder *encoder, uint8_t *config) --{ -- struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); -- struct drm_device *dev = encoder->dev; -- struct bit_displayport_encoder_table_entry *dpse; -- struct bit_displayport_encoder_table *dpe; -- int or = nv_encoder->or, link = !(nv_encoder->dcb->sorconf.link & 1); -- int dpe_headerlen, ret, i; -+/****************************************************************************** -+ * link training -+ *****************************************************************************/ -+struct dp_state { -+ struct dcb_entry *dcb; -+ u8 *table; -+ u8 *entry; -+ int auxch; -+ int crtc; -+ int or; -+ int link; -+ u8 *dpcd; -+ int link_nr; -+ u32 link_bw; -+ u8 stat[6]; -+ u8 conf[4]; -+}; - -- NV_DEBUG_KMS(dev, "\t\tconfig 0x%02x 0x%02x 0x%02x 0x%02x\n", -- config[0], config[1], config[2], config[3]); -+static void -+dp_set_link_config(struct drm_device *dev, struct dp_state *dp) -+{ -+ struct drm_nouveau_private *dev_priv = dev->dev_private; -+ int or = dp->or, link = dp->link; -+ u8 *entry, sink[2]; -+ u32 dp_ctrl; -+ u16 script; -+ -+ NV_DEBUG_KMS(dev, "%d lanes at %d KB/s\n", dp->link_nr, dp->link_bw); -+ -+ /* set selected link rate on source */ -+ switch (dp->link_bw) { -+ case 270000: -+ nv_mask(dev, 0x614300 + (or * 0x800), 0x000c0000, 0x00040000); -+ sink[0] = DP_LINK_BW_2_7; -+ break; -+ default: -+ nv_mask(dev, 0x614300 + (or * 0x800), 0x000c0000, 0x00000000); -+ sink[0] = DP_LINK_BW_1_62; -+ break; -+ } - -- dpe = nouveau_bios_dp_table(dev, nv_encoder->dcb, &dpe_headerlen); -- if (!dpe) -- return false; -- dpse = (void *)((char *)dpe + dpe_headerlen); -+ /* offset +0x0a of each dp encoder table entry is a pointer to another -+ * table, that has (among other things) pointers to more scripts that -+ * need to be executed, this time depending on link speed. -+ */ -+ entry = ROMPTR(&dev_priv->vbios, dp->entry[10]); -+ if (entry) { -+ if (dp->table[0] < 0x30) { -+ while (dp->link_bw < (ROM16(entry[0]) * 10)) -+ entry += 4; -+ script = ROM16(entry[2]); -+ } else { -+ while (dp->link_bw < (entry[0] * 27000)) -+ entry += 3; -+ script = ROM16(entry[1]); -+ } - -- for (i = 0; i < dpe->record_nr; i++, dpse++) { -- if (dpse->vs_level == (config[0] & 3) && -- dpse->pre_level == ((config[0] >> 3) & 3)) -- break; -+ nouveau_bios_run_init_table(dev, script, dp->dcb, dp->crtc); - } -- BUG_ON(i == dpe->record_nr); -- -- for (i = 0; i < nv_encoder->dp.link_nr; i++) { -- const int shift[4] = { 16, 8, 0, 24 }; -- uint32_t mask = 0xff << shift[i]; -- uint32_t reg0, reg1, reg2; -- -- reg0 = nv_rd32(dev, NV50_SOR_DP_UNK118(or, link)) & ~mask; -- reg0 |= (dpse->reg0 << shift[i]); -- reg1 = nv_rd32(dev, NV50_SOR_DP_UNK120(or, link)) & ~mask; -- reg1 |= (dpse->reg1 << shift[i]); -- reg2 = nv_rd32(dev, NV50_SOR_DP_UNK130(or, link)) & 0xffff00ff; -- reg2 |= (dpse->reg2 << 8); -- nv_wr32(dev, NV50_SOR_DP_UNK118(or, link), reg0); -- nv_wr32(dev, NV50_SOR_DP_UNK120(or, link), reg1); -- nv_wr32(dev, NV50_SOR_DP_UNK130(or, link), reg2); -+ -+ /* configure lane count on the source */ -+ dp_ctrl = ((1 << dp->link_nr) - 1) << 16; -+ sink[1] = dp->link_nr; -+ if (dp->dpcd[2] & DP_ENHANCED_FRAME_CAP) { -+ dp_ctrl |= 0x00004000; -+ sink[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN; - } - -- ret = auxch_wr(encoder, DP_TRAINING_LANE0_SET, config, 4); -- if (ret) -- return false; -+ nv_mask(dev, NV50_SOR_DP_CTRL(or, link), 0x001f4000, dp_ctrl); - -- return true; -+ /* inform the sink of the new configuration */ -+ auxch_tx(dev, dp->auxch, 8, DP_LINK_BW_SET, sink, 2); - } - --bool --nouveau_dp_link_train(struct drm_encoder *encoder) -+static void -+dp_set_training_pattern(struct drm_device *dev, struct dp_state *dp, u8 tp) - { -- struct drm_device *dev = encoder->dev; -- struct drm_nouveau_private *dev_priv = dev->dev_private; -- struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio; -- struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); -- struct nouveau_connector *nv_connector; -- struct bit_displayport_encoder_table *dpe; -- int dpe_headerlen; -- uint8_t config[4], status[3]; -- bool cr_done, cr_max_vs, eq_done, hpd_state; -- int ret = 0, i, tries, voltage; -+ u8 sink_tp; - -- NV_DEBUG_KMS(dev, "link training!!\n"); -+ NV_DEBUG_KMS(dev, "training pattern %d\n", tp); - -- nv_connector = nouveau_encoder_connector_get(nv_encoder); -- if (!nv_connector) -- return false; -+ nv_mask(dev, NV50_SOR_DP_CTRL(dp->or, dp->link), 0x0f000000, tp << 24); - -- dpe = nouveau_bios_dp_table(dev, nv_encoder->dcb, &dpe_headerlen); -- if (!dpe) { -- NV_ERROR(dev, "SOR-%d: no DP encoder table!\n", nv_encoder->or); -- return false; -- } -+ auxch_tx(dev, dp->auxch, 9, DP_TRAINING_PATTERN_SET, &sink_tp, 1); -+ sink_tp &= ~DP_TRAINING_PATTERN_MASK; -+ sink_tp |= tp; -+ auxch_tx(dev, dp->auxch, 8, DP_TRAINING_PATTERN_SET, &sink_tp, 1); -+} - -- /* disable hotplug detect, this flips around on some panels during -- * link training. -- */ -- hpd_state = pgpio->irq_enable(dev, nv_connector->dcb->gpio_tag, false); -+static const u8 nv50_lane_map[] = { 16, 8, 0, 24 }; -+static const u8 nvaf_lane_map[] = { 24, 16, 8, 0 }; -+ -+static int -+dp_link_train_commit(struct drm_device *dev, struct dp_state *dp) -+{ -+ struct drm_nouveau_private *dev_priv = dev->dev_private; -+ u32 mask = 0, drv = 0, pre = 0, unk = 0; -+ const u8 *shifts; -+ int link = dp->link; -+ int or = dp->or; -+ int i; -+ -+ if (dev_priv->chipset != 0xaf) -+ shifts = nv50_lane_map; -+ else -+ shifts = nvaf_lane_map; -+ -+ for (i = 0; i < dp->link_nr; i++) { -+ u8 *conf = dp->entry + dp->table[4]; -+ u8 lane = (dp->stat[4 + (i >> 1)] >> ((i & 1) * 4)) & 0xf; -+ u8 lpre = (lane & 0x0c) >> 2; -+ u8 lvsw = (lane & 0x03) >> 0; -+ -+ mask |= 0xff << shifts[i]; -+ unk |= 1 << (shifts[i] >> 3); -+ -+ dp->conf[i] = (lpre << 3) | lvsw; -+ if (lvsw == DP_TRAIN_VOLTAGE_SWING_1200) -+ dp->conf[i] |= DP_TRAIN_MAX_SWING_REACHED; -+ if (lpre == DP_TRAIN_PRE_EMPHASIS_9_5) -+ dp->conf[i] |= DP_TRAIN_MAX_PRE_EMPHASIS_REACHED; -+ -+ NV_DEBUG_KMS(dev, "config lane %d %02x\n", i, dp->conf[i]); -+ -+ if (dp->table[0] < 0x30) { -+ u8 *last = conf + (dp->entry[4] * dp->table[5]); -+ while (lvsw != conf[0] || lpre != conf[1]) { -+ conf += dp->table[5]; -+ if (conf >= last) -+ return -EINVAL; -+ } -+ -+ conf += 2; -+ } else { -+ /* no lookup table anymore, set entries for each -+ * combination of voltage swing and pre-emphasis -+ * level allowed by the DP spec. -+ */ -+ switch (lvsw) { -+ case 0: lpre += 0; break; -+ case 1: lpre += 4; break; -+ case 2: lpre += 7; break; -+ case 3: lpre += 9; break; -+ } -+ -+ conf = conf + (lpre * dp->table[5]); -+ conf++; -+ } - -- if (dpe->script0) { -- NV_DEBUG_KMS(dev, "SOR-%d: running DP script 0\n", nv_encoder->or); -- nouveau_bios_run_init_table(dev, le16_to_cpu(dpe->script0), -- nv_encoder->dcb); -+ drv |= conf[0] << shifts[i]; -+ pre |= conf[1] << shifts[i]; -+ unk = (unk & ~0x0000ff00) | (conf[2] << 8); - } - --train: -- cr_done = eq_done = false; -+ nv_mask(dev, NV50_SOR_DP_UNK118(or, link), mask, drv); -+ nv_mask(dev, NV50_SOR_DP_UNK120(or, link), mask, pre); -+ nv_mask(dev, NV50_SOR_DP_UNK130(or, link), 0x0000ff0f, unk); - -- /* set link configuration */ -- NV_DEBUG_KMS(dev, "\tbegin train: bw %d, lanes %d\n", -- nv_encoder->dp.link_bw, nv_encoder->dp.link_nr); -+ return auxch_tx(dev, dp->auxch, 8, DP_TRAINING_LANE0_SET, dp->conf, 4); -+} - -- ret = nouveau_dp_link_bw_set(encoder, nv_encoder->dp.link_bw); -- if (ret) -- return false; -+static int -+dp_link_train_update(struct drm_device *dev, struct dp_state *dp, u32 delay) -+{ -+ int ret; - -- config[0] = nv_encoder->dp.link_nr; -- if (nv_encoder->dp.dpcd_version >= 0x11 && -- nv_encoder->dp.enhanced_frame) -- config[0] |= DP_LANE_COUNT_ENHANCED_FRAME_EN; -+ udelay(delay); - -- ret = nouveau_dp_lane_count_set(encoder, config[0]); -+ ret = auxch_tx(dev, dp->auxch, 9, DP_LANE0_1_STATUS, dp->stat, 6); - if (ret) -- return false; -+ return ret; - -- /* clock recovery */ -- NV_DEBUG_KMS(dev, "\tbegin cr\n"); -- ret = nouveau_dp_link_train_set(encoder, DP_TRAINING_PATTERN_1); -- if (ret) -- goto stop; -+ NV_DEBUG_KMS(dev, "status %02x %02x %02x %02x %02x %02x\n", -+ dp->stat[0], dp->stat[1], dp->stat[2], dp->stat[3], -+ dp->stat[4], dp->stat[5]); -+ return 0; -+} - -- tries = 0; -- voltage = -1; -- memset(config, 0x00, sizeof(config)); -- for (;;) { -- if (!nouveau_dp_link_train_commit(encoder, config)) -- break; -+static int -+dp_link_train_cr(struct drm_device *dev, struct dp_state *dp) -+{ -+ bool cr_done = false, abort = false; -+ int voltage = dp->conf[0] & DP_TRAIN_VOLTAGE_SWING_MASK; -+ int tries = 0, i; - -- udelay(100); -+ dp_set_training_pattern(dev, dp, DP_TRAINING_PATTERN_1); - -- ret = auxch_rd(encoder, DP_LANE0_1_STATUS, status, 2); -- if (ret) -+ do { -+ if (dp_link_train_commit(dev, dp) || -+ dp_link_train_update(dev, dp, 100)) - break; -- NV_DEBUG_KMS(dev, "\t\tstatus: 0x%02x 0x%02x\n", -- status[0], status[1]); - - cr_done = true; -- cr_max_vs = false; -- for (i = 0; i < nv_encoder->dp.link_nr; i++) { -- int lane = (status[i >> 1] >> ((i & 1) * 4)) & 0xf; -- -+ for (i = 0; i < dp->link_nr; i++) { -+ u8 lane = (dp->stat[i >> 1] >> ((i & 1) * 4)) & 0xf; - if (!(lane & DP_LANE_CR_DONE)) { - cr_done = false; -- if (config[i] & DP_TRAIN_MAX_PRE_EMPHASIS_REACHED) -- cr_max_vs = true; -+ if (dp->conf[i] & DP_TRAIN_MAX_SWING_REACHED) -+ abort = true; - break; - } - } - -- if ((config[0] & DP_TRAIN_VOLTAGE_SWING_MASK) != voltage) { -- voltage = config[0] & DP_TRAIN_VOLTAGE_SWING_MASK; -+ if ((dp->conf[0] & DP_TRAIN_VOLTAGE_SWING_MASK) != voltage) { -+ voltage = dp->conf[0] & DP_TRAIN_VOLTAGE_SWING_MASK; - tries = 0; - } -+ } while (!cr_done && !abort && ++tries < 5); - -- if (cr_done || cr_max_vs || (++tries == 5)) -- break; -- -- if (!nouveau_dp_link_train_adjust(encoder, config)) -- break; -- } -- -- if (!cr_done) -- goto stop; -+ return cr_done ? 0 : -1; -+} - -- /* channel equalisation */ -- NV_DEBUG_KMS(dev, "\tbegin eq\n"); -- ret = nouveau_dp_link_train_set(encoder, DP_TRAINING_PATTERN_2); -- if (ret) -- goto stop; -+static int -+dp_link_train_eq(struct drm_device *dev, struct dp_state *dp) -+{ -+ bool eq_done, cr_done = true; -+ int tries = 0, i; - -- for (tries = 0; tries <= 5; tries++) { -- udelay(400); -+ dp_set_training_pattern(dev, dp, DP_TRAINING_PATTERN_2); - -- ret = auxch_rd(encoder, DP_LANE0_1_STATUS, status, 3); -- if (ret) -+ do { -+ if (dp_link_train_update(dev, dp, 400)) - break; -- NV_DEBUG_KMS(dev, "\t\tstatus: 0x%02x 0x%02x\n", -- status[0], status[1]); - -- eq_done = true; -- if (!(status[2] & DP_INTERLANE_ALIGN_DONE)) -- eq_done = false; -- -- for (i = 0; eq_done && i < nv_encoder->dp.link_nr; i++) { -- int lane = (status[i >> 1] >> ((i & 1) * 4)) & 0xf; -- -- if (!(lane & DP_LANE_CR_DONE)) { -+ eq_done = !!(dp->stat[2] & DP_INTERLANE_ALIGN_DONE); -+ for (i = 0; i < dp->link_nr && eq_done; i++) { -+ u8 lane = (dp->stat[i >> 1] >> ((i & 1) * 4)) & 0xf; -+ if (!(lane & DP_LANE_CR_DONE)) - cr_done = false; -- break; -- } -- - if (!(lane & DP_LANE_CHANNEL_EQ_DONE) || -- !(lane & DP_LANE_SYMBOL_LOCKED)) { -+ !(lane & DP_LANE_SYMBOL_LOCKED)) - eq_done = false; -- break; -- } - } - -- if (eq_done || !cr_done) -+ if (dp_link_train_commit(dev, dp)) - break; -+ } while (!eq_done && cr_done && ++tries <= 5); - -- if (!nouveau_dp_link_train_adjust(encoder, config) || -- !nouveau_dp_link_train_commit(encoder, config)) -- break; -- } -+ return eq_done ? 0 : -1; -+} - --stop: -- /* end link training */ -- ret = nouveau_dp_link_train_set(encoder, DP_TRAINING_PATTERN_DISABLE); -- if (ret) -+bool -+nouveau_dp_link_train(struct drm_encoder *encoder, u32 datarate) -+{ -+ struct drm_nouveau_private *dev_priv = encoder->dev->dev_private; -+ struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio; -+ struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); -+ struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc); -+ struct nouveau_connector *nv_connector = -+ nouveau_encoder_connector_get(nv_encoder); -+ struct drm_device *dev = encoder->dev; -+ struct nouveau_i2c_chan *auxch; -+ const u32 bw_list[] = { 270000, 162000, 0 }; -+ const u32 *link_bw = bw_list; -+ struct dp_state dp; -+ -+ auxch = nouveau_i2c_find(dev, nv_encoder->dcb->i2c_index); -+ if (!auxch) - return false; - -- /* retry at a lower setting, if possible */ -- if (!ret && !(eq_done && cr_done)) { -- NV_DEBUG_KMS(dev, "\twe failed\n"); -- if (nv_encoder->dp.link_bw != DP_LINK_BW_1_62) { -- NV_DEBUG_KMS(dev, "retry link training at low rate\n"); -- nv_encoder->dp.link_bw = DP_LINK_BW_1_62; -- goto train; -- } -+ dp.table = nouveau_dp_bios_data(dev, nv_encoder->dcb, &dp.entry); -+ if (!dp.table) -+ return -EINVAL; -+ -+ dp.dcb = nv_encoder->dcb; -+ dp.crtc = nv_crtc->index; -+ dp.auxch = auxch->rd; -+ dp.or = nv_encoder->or; -+ dp.link = !(nv_encoder->dcb->sorconf.link & 1); -+ dp.dpcd = nv_encoder->dp.dpcd; -+ -+ /* some sinks toggle hotplug in response to some of the actions -+ * we take during link training (DP_SET_POWER is one), we need -+ * to ignore them for the moment to avoid races. -+ */ -+ pgpio->irq_enable(dev, nv_connector->dcb->gpio_tag, false); -+ -+ /* enable down-spreading, if possible */ -+ if (dp.table[1] >= 16) { -+ u16 script = ROM16(dp.entry[14]); -+ if (nv_encoder->dp.dpcd[3] & 1) -+ script = ROM16(dp.entry[12]); -+ -+ nouveau_bios_run_init_table(dev, script, dp.dcb, dp.crtc); - } - -- if (dpe->script1) { -- NV_DEBUG_KMS(dev, "SOR-%d: running DP script 1\n", nv_encoder->or); -- nouveau_bios_run_init_table(dev, le16_to_cpu(dpe->script1), -- nv_encoder->dcb); -+ /* execute pre-train script from vbios */ -+ nouveau_bios_run_init_table(dev, ROM16(dp.entry[6]), dp.dcb, dp.crtc); -+ -+ /* start off at highest link rate supported by encoder and display */ -+ while (*link_bw > nv_encoder->dp.link_bw) -+ link_bw++; -+ -+ while (link_bw[0]) { -+ /* find minimum required lane count at this link rate */ -+ dp.link_nr = nv_encoder->dp.link_nr; -+ while ((dp.link_nr >> 1) * link_bw[0] > datarate) -+ dp.link_nr >>= 1; -+ -+ /* drop link rate to minimum with this lane count */ -+ while ((link_bw[1] * dp.link_nr) > datarate) -+ link_bw++; -+ dp.link_bw = link_bw[0]; -+ -+ /* program selected link configuration */ -+ dp_set_link_config(dev, &dp); -+ -+ /* attempt to train the link at this configuration */ -+ memset(dp.stat, 0x00, sizeof(dp.stat)); -+ if (!dp_link_train_cr(dev, &dp) && -+ !dp_link_train_eq(dev, &dp)) -+ break; -+ -+ /* retry at lower rate */ -+ link_bw++; - } - -- /* re-enable hotplug detect */ -- pgpio->irq_enable(dev, nv_connector->dcb->gpio_tag, hpd_state); -+ /* finish link training */ -+ dp_set_training_pattern(dev, &dp, DP_TRAINING_PATTERN_DISABLE); - -- return eq_done; -+ /* execute post-train script from vbios */ -+ nouveau_bios_run_init_table(dev, ROM16(dp.entry[8]), dp.dcb, dp.crtc); -+ -+ /* re-enable hotplug detect */ -+ pgpio->irq_enable(dev, nv_connector->dcb->gpio_tag, true); -+ return true; - } - - bool -@@ -447,31 +648,34 @@ nouveau_dp_detect(struct drm_encoder *encoder) - { - struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); - struct drm_device *dev = encoder->dev; -- uint8_t dpcd[4]; -+ struct nouveau_i2c_chan *auxch; -+ u8 *dpcd = nv_encoder->dp.dpcd; - int ret; - -- ret = auxch_rd(encoder, 0x0000, dpcd, 4); -- if (ret) -+ auxch = nouveau_i2c_find(dev, nv_encoder->dcb->i2c_index); -+ if (!auxch) - return false; - -- NV_DEBUG_KMS(dev, "encoder: link_bw %d, link_nr %d\n" -- "display: link_bw %d, link_nr %d version 0x%02x\n", -- nv_encoder->dcb->dpconf.link_bw, -- nv_encoder->dcb->dpconf.link_nr, -- dpcd[1], dpcd[2] & 0x0f, dpcd[0]); -+ ret = auxch_tx(dev, auxch->rd, 9, DP_DPCD_REV, dpcd, 8); -+ if (ret) -+ return false; - -- nv_encoder->dp.dpcd_version = dpcd[0]; -+ nv_encoder->dp.link_bw = 27000 * dpcd[1]; -+ nv_encoder->dp.link_nr = dpcd[2] & DP_MAX_LANE_COUNT_MASK; - -- nv_encoder->dp.link_bw = dpcd[1]; -- if (nv_encoder->dp.link_bw != DP_LINK_BW_1_62 && -- !nv_encoder->dcb->dpconf.link_bw) -- nv_encoder->dp.link_bw = DP_LINK_BW_1_62; -+ NV_DEBUG_KMS(dev, "display: %dx%d dpcd 0x%02x\n", -+ nv_encoder->dp.link_nr, nv_encoder->dp.link_bw, dpcd[0]); -+ NV_DEBUG_KMS(dev, "encoder: %dx%d\n", -+ nv_encoder->dcb->dpconf.link_nr, -+ nv_encoder->dcb->dpconf.link_bw); - -- nv_encoder->dp.link_nr = dpcd[2] & DP_MAX_LANE_COUNT_MASK; -- if (nv_encoder->dp.link_nr > nv_encoder->dcb->dpconf.link_nr) -+ if (nv_encoder->dcb->dpconf.link_nr < nv_encoder->dp.link_nr) - nv_encoder->dp.link_nr = nv_encoder->dcb->dpconf.link_nr; -+ if (nv_encoder->dcb->dpconf.link_bw < nv_encoder->dp.link_bw) -+ nv_encoder->dp.link_bw = nv_encoder->dcb->dpconf.link_bw; - -- nv_encoder->dp.enhanced_frame = (dpcd[2] & DP_ENHANCED_FRAME_CAP); -+ NV_DEBUG_KMS(dev, "maximum: %dx%d\n", -+ nv_encoder->dp.link_nr, nv_encoder->dp.link_bw); - - return true; - } -@@ -480,105 +684,13 @@ int - nouveau_dp_auxch(struct nouveau_i2c_chan *auxch, int cmd, int addr, - uint8_t *data, int data_nr) - { -- struct drm_device *dev = auxch->dev; -- uint32_t tmp, ctrl, stat = 0, data32[4] = {}; -- int ret = 0, i, index = auxch->rd; -- -- NV_DEBUG_KMS(dev, "ch %d cmd %d addr 0x%x len %d\n", index, cmd, addr, data_nr); -- -- tmp = nv_rd32(dev, NV50_AUXCH_CTRL(auxch->rd)); -- nv_wr32(dev, NV50_AUXCH_CTRL(auxch->rd), tmp | 0x00100000); -- tmp = nv_rd32(dev, NV50_AUXCH_CTRL(auxch->rd)); -- if (!(tmp & 0x01000000)) { -- NV_ERROR(dev, "expected bit 24 == 1, got 0x%08x\n", tmp); -- ret = -EIO; -- goto out; -- } -- -- for (i = 0; i < 3; i++) { -- tmp = nv_rd32(dev, NV50_AUXCH_STAT(auxch->rd)); -- if (tmp & NV50_AUXCH_STAT_STATE_READY) -- break; -- udelay(100); -- } -- -- if (i == 3) { -- ret = -EBUSY; -- goto out; -- } -- -- if (!(cmd & 1)) { -- memcpy(data32, data, data_nr); -- for (i = 0; i < 4; i++) { -- NV_DEBUG_KMS(dev, "wr %d: 0x%08x\n", i, data32[i]); -- nv_wr32(dev, NV50_AUXCH_DATA_OUT(index, i), data32[i]); -- } -- } -- -- nv_wr32(dev, NV50_AUXCH_ADDR(index), addr); -- ctrl = nv_rd32(dev, NV50_AUXCH_CTRL(index)); -- ctrl &= ~(NV50_AUXCH_CTRL_CMD | NV50_AUXCH_CTRL_LEN); -- ctrl |= (cmd << NV50_AUXCH_CTRL_CMD_SHIFT); -- ctrl |= ((data_nr - 1) << NV50_AUXCH_CTRL_LEN_SHIFT); -- -- for (i = 0; i < 16; i++) { -- nv_wr32(dev, NV50_AUXCH_CTRL(index), ctrl | 0x80000000); -- nv_wr32(dev, NV50_AUXCH_CTRL(index), ctrl); -- nv_wr32(dev, NV50_AUXCH_CTRL(index), ctrl | 0x00010000); -- if (!nv_wait(dev, NV50_AUXCH_CTRL(index), -- 0x00010000, 0x00000000)) { -- NV_ERROR(dev, "expected bit 16 == 0, got 0x%08x\n", -- nv_rd32(dev, NV50_AUXCH_CTRL(index))); -- ret = -EBUSY; -- goto out; -- } -- -- udelay(400); -- -- stat = nv_rd32(dev, NV50_AUXCH_STAT(index)); -- if ((stat & NV50_AUXCH_STAT_REPLY_AUX) != -- NV50_AUXCH_STAT_REPLY_AUX_DEFER) -- break; -- } -- -- if (i == 16) { -- NV_ERROR(dev, "auxch DEFER too many times, bailing\n"); -- ret = -EREMOTEIO; -- goto out; -- } -- -- if (cmd & 1) { -- if ((stat & NV50_AUXCH_STAT_COUNT) != data_nr) { -- ret = -EREMOTEIO; -- goto out; -- } -- -- for (i = 0; i < 4; i++) { -- data32[i] = nv_rd32(dev, NV50_AUXCH_DATA_IN(index, i)); -- NV_DEBUG_KMS(dev, "rd %d: 0x%08x\n", i, data32[i]); -- } -- memcpy(data, data32, data_nr); -- } -- --out: -- tmp = nv_rd32(dev, NV50_AUXCH_CTRL(auxch->rd)); -- nv_wr32(dev, NV50_AUXCH_CTRL(auxch->rd), tmp & ~0x00100000); -- tmp = nv_rd32(dev, NV50_AUXCH_CTRL(auxch->rd)); -- if (tmp & 0x01000000) { -- NV_ERROR(dev, "expected bit 24 == 0, got 0x%08x\n", tmp); -- ret = -EIO; -- } -- -- udelay(400); -- -- return ret ? ret : (stat & NV50_AUXCH_STAT_REPLY); -+ return auxch_tx(auxch->dev, auxch->rd, cmd, addr, data, data_nr); - } - - static int - nouveau_dp_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) - { - struct nouveau_i2c_chan *auxch = (struct nouveau_i2c_chan *)adap; -- struct drm_device *dev = auxch->dev; - struct i2c_msg *msg = msgs; - int ret, mcnt = num; - -@@ -602,19 +714,6 @@ nouveau_dp_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) - if (ret < 0) - return ret; - -- switch (ret & NV50_AUXCH_STAT_REPLY_I2C) { -- case NV50_AUXCH_STAT_REPLY_I2C_ACK: -- break; -- case NV50_AUXCH_STAT_REPLY_I2C_NACK: -- return -EREMOTEIO; -- case NV50_AUXCH_STAT_REPLY_I2C_DEFER: -- udelay(100); -- continue; -- default: -- NV_ERROR(dev, "bad auxch reply: 0x%08x\n", ret); -- return -EREMOTEIO; -- } -- - ptr += cnt; - remaining -= cnt; - } -diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.c b/drivers/gpu/drm/nouveau/nouveau_drv.c -index b30ddd8..c1e01f3 100644 ---- a/drivers/gpu/drm/nouveau/nouveau_drv.c -+++ b/drivers/gpu/drm/nouveau/nouveau_drv.c -@@ -41,7 +41,7 @@ int nouveau_agpmode = -1; - module_param_named(agpmode, nouveau_agpmode, int, 0400); - - MODULE_PARM_DESC(modeset, "Enable kernel modesetting"); --static int nouveau_modeset = -1; /* kms */ -+int nouveau_modeset = -1; - module_param_named(modeset, nouveau_modeset, int, 0400); - - MODULE_PARM_DESC(vbios, "Override default VBIOS location"); -diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h -index d7d51de..29837da 100644 ---- a/drivers/gpu/drm/nouveau/nouveau_drv.h -+++ b/drivers/gpu/drm/nouveau/nouveau_drv.h -@@ -414,12 +414,13 @@ struct nouveau_gpio_engine { - }; - - struct nouveau_pm_voltage_level { -- u8 voltage; -- u8 vid; -+ u32 voltage; /* microvolts */ -+ u8 vid; - }; - - struct nouveau_pm_voltage { - bool supported; -+ u8 version; - u8 vid_mask; - - struct nouveau_pm_voltage_level *level; -@@ -428,17 +429,48 @@ struct nouveau_pm_voltage { - - struct nouveau_pm_memtiming { - int id; -- u32 reg_100220; -- u32 reg_100224; -- u32 reg_100228; -- u32 reg_10022c; -- u32 reg_100230; -- u32 reg_100234; -- u32 reg_100238; -- u32 reg_10023c; -- u32 reg_100240; -+ u32 reg_0; /* 0x10f290 on Fermi, 0x100220 for older */ -+ u32 reg_1; -+ u32 reg_2; -+ u32 reg_3; -+ u32 reg_4; -+ u32 reg_5; -+ u32 reg_6; -+ u32 reg_7; -+ u32 reg_8; -+ /* To be written to 0x1002c0 */ -+ u8 CL; -+ u8 WR; - }; - -+struct nouveau_pm_tbl_header{ -+ u8 version; -+ u8 header_len; -+ u8 entry_cnt; -+ u8 entry_len; -+}; -+ -+struct nouveau_pm_tbl_entry{ -+ u8 tWR; -+ u8 tUNK_1; -+ u8 tCL; -+ u8 tRP; /* Byte 3 */ -+ u8 empty_4; -+ u8 tRAS; /* Byte 5 */ -+ u8 empty_6; -+ u8 tRFC; /* Byte 7 */ -+ u8 empty_8; -+ u8 tRC; /* Byte 9 */ -+ u8 tUNK_10, tUNK_11, tUNK_12, tUNK_13, tUNK_14; -+ u8 empty_15,empty_16,empty_17; -+ u8 tUNK_18, tUNK_19, tUNK_20, tUNK_21; -+}; -+ -+/* nouveau_mem.c */ -+void nv30_mem_timing_entry(struct drm_device *dev, struct nouveau_pm_tbl_header *hdr, -+ struct nouveau_pm_tbl_entry *e, uint8_t magic_number, -+ struct nouveau_pm_memtiming *timing); -+ - #define NOUVEAU_PM_MAX_LEVEL 8 - struct nouveau_pm_level { - struct device_attribute dev_attr; -@@ -448,11 +480,19 @@ struct nouveau_pm_level { - u32 core; - u32 memory; - u32 shader; -- u32 unk05; -- u32 unk0a; -- -- u8 voltage; -- u8 fanspeed; -+ u32 rop; -+ u32 copy; -+ u32 daemon; -+ u32 vdec; -+ u32 unk05; /* nv50:nva3, roughly.. */ -+ u32 unka0; /* nva3:nvc0 */ -+ u32 hub01; /* nvc0- */ -+ u32 hub06; /* nvc0- */ -+ u32 hub07; /* nvc0- */ -+ -+ u32 volt_min; /* microvolts */ -+ u32 volt_max; -+ u8 fanspeed; - - u16 memscript; - struct nouveau_pm_memtiming *timing; -@@ -496,6 +536,11 @@ struct nouveau_pm_engine { - void *(*clock_pre)(struct drm_device *, struct nouveau_pm_level *, - u32 id, int khz); - void (*clock_set)(struct drm_device *, void *); -+ -+ int (*clocks_get)(struct drm_device *, struct nouveau_pm_level *); -+ void *(*clocks_pre)(struct drm_device *, struct nouveau_pm_level *); -+ void (*clocks_set)(struct drm_device *, void *); -+ - int (*voltage_get)(struct drm_device *); - int (*voltage_set)(struct drm_device *, int voltage); - int (*fanspeed_get)(struct drm_device *); -@@ -504,7 +549,7 @@ struct nouveau_pm_engine { - }; - - struct nouveau_vram_engine { -- struct nouveau_mm *mm; -+ struct nouveau_mm mm; - - int (*init)(struct drm_device *); - void (*takedown)(struct drm_device *dev); -@@ -623,6 +668,7 @@ enum nouveau_card_type { - NV_40 = 0x40, - NV_50 = 0x50, - NV_C0 = 0xc0, -+ NV_D0 = 0xd0 - }; - - struct drm_nouveau_private { -@@ -633,8 +679,8 @@ struct drm_nouveau_private { - enum nouveau_card_type card_type; - /* exact chipset, derived from NV_PMC_BOOT_0 */ - int chipset; -- int stepping; - int flags; -+ u32 crystal; - - void __iomem *mmio; - -@@ -721,7 +767,6 @@ struct drm_nouveau_private { - uint64_t vram_size; - uint64_t vram_sys_base; - -- uint64_t fb_phys; - uint64_t fb_available_size; - uint64_t fb_mappable_pages; - uint64_t fb_aper_free; -@@ -784,6 +829,7 @@ nouveau_bo_ref(struct nouveau_bo *ref, struct nouveau_bo **pnvbo) - } - - /* nouveau_drv.c */ -+extern int nouveau_modeset; - extern int nouveau_agpmode; - extern int nouveau_duallink; - extern int nouveau_uscript_lvds; -@@ -824,6 +870,8 @@ extern bool nouveau_wait_eq(struct drm_device *, uint64_t timeout, - uint32_t reg, uint32_t mask, uint32_t val); - extern bool nouveau_wait_ne(struct drm_device *, uint64_t timeout, - uint32_t reg, uint32_t mask, uint32_t val); -+extern bool nouveau_wait_cb(struct drm_device *, u64 timeout, -+ bool (*cond)(void *), void *); - extern bool nouveau_wait_for_idle(struct drm_device *); - extern int nouveau_card_init(struct drm_device *); - -@@ -1006,15 +1054,15 @@ static inline int nouveau_acpi_edid(struct drm_device *dev, struct drm_connector - - /* nouveau_backlight.c */ - #ifdef CONFIG_DRM_NOUVEAU_BACKLIGHT --extern int nouveau_backlight_init(struct drm_connector *); --extern void nouveau_backlight_exit(struct drm_connector *); -+extern int nouveau_backlight_init(struct drm_device *); -+extern void nouveau_backlight_exit(struct drm_device *); - #else --static inline int nouveau_backlight_init(struct drm_connector *dev) -+static inline int nouveau_backlight_init(struct drm_device *dev) - { - return 0; - } - --static inline void nouveau_backlight_exit(struct drm_connector *dev) { } -+static inline void nouveau_backlight_exit(struct drm_device *dev) { } - #endif - - /* nouveau_bios.c */ -@@ -1022,7 +1070,8 @@ extern int nouveau_bios_init(struct drm_device *); - extern void nouveau_bios_takedown(struct drm_device *dev); - extern int nouveau_run_vbios_init(struct drm_device *); - extern void nouveau_bios_run_init_table(struct drm_device *, uint16_t table, -- struct dcb_entry *); -+ struct dcb_entry *, int crtc); -+extern void nouveau_bios_init_exec(struct drm_device *, uint16_t table); - extern struct dcb_gpio_entry *nouveau_bios_gpio_entry(struct drm_device *, - enum dcb_gpio_tag); - extern struct dcb_connector_table_entry * -@@ -1030,11 +1079,8 @@ nouveau_bios_connector_entry(struct drm_device *, int index); - extern u32 get_pll_register(struct drm_device *, enum pll_types); - extern int get_pll_limits(struct drm_device *, uint32_t limit_match, - struct pll_lims *); --extern int nouveau_bios_run_display_table(struct drm_device *, -- struct dcb_entry *, -- uint32_t script, int pxclk); --extern void *nouveau_bios_dp_table(struct drm_device *, struct dcb_entry *, -- int *length); -+extern int nouveau_bios_run_display_table(struct drm_device *, u16 id, int clk, -+ struct dcb_entry *, int crtc); - extern bool nouveau_bios_fp_mode(struct drm_device *, struct drm_display_mode *); - extern uint8_t *nouveau_bios_embedded_edid(struct drm_device *); - extern int nouveau_bios_parse_lvds_table(struct drm_device *, int pxclk, -@@ -1043,6 +1089,7 @@ extern int run_tmds_table(struct drm_device *, struct dcb_entry *, - int head, int pxclk); - extern int call_lvds_script(struct drm_device *, struct dcb_entry *, int head, - enum LVDS_script, int pxclk); -+bool bios_encoder_match(struct dcb_entry *, u32 hash); - - /* nouveau_ttm.c */ - int nouveau_ttm_global_init(struct drm_nouveau_private *); -@@ -1053,7 +1100,9 @@ int nouveau_ttm_mmap(struct file *, struct vm_area_struct *); - int nouveau_dp_auxch(struct nouveau_i2c_chan *auxch, int cmd, int addr, - uint8_t *data, int data_nr); - bool nouveau_dp_detect(struct drm_encoder *); --bool nouveau_dp_link_train(struct drm_encoder *); -+bool nouveau_dp_link_train(struct drm_encoder *, u32 datarate); -+void nouveau_dp_tu_update(struct drm_device *, int, int, u32, u32); -+u8 *nouveau_dp_bios_data(struct drm_device *, struct dcb_entry *, u8 **); - - /* nv04_fb.c */ - extern int nv04_fb_init(struct drm_device *); -@@ -1179,8 +1228,8 @@ extern int nva3_copy_create(struct drm_device *dev); - /* nvc0_copy.c */ - extern int nvc0_copy_create(struct drm_device *dev, int engine); - --/* nv40_mpeg.c */ --extern int nv40_mpeg_create(struct drm_device *dev); -+/* nv31_mpeg.c */ -+extern int nv31_mpeg_create(struct drm_device *dev); - - /* nv50_mpeg.c */ - extern int nv50_mpeg_create(struct drm_device *dev); -@@ -1265,6 +1314,11 @@ extern int nv04_display_create(struct drm_device *); - extern int nv04_display_init(struct drm_device *); - extern void nv04_display_destroy(struct drm_device *); - -+/* nvd0_display.c */ -+extern int nvd0_display_create(struct drm_device *); -+extern int nvd0_display_init(struct drm_device *); -+extern void nvd0_display_destroy(struct drm_device *); -+ - /* nv04_crtc.c */ - extern int nv04_crtc_create(struct drm_device *, int index); - -@@ -1374,6 +1428,8 @@ int nv50_gpio_init(struct drm_device *dev); - void nv50_gpio_fini(struct drm_device *dev); - int nv50_gpio_get(struct drm_device *dev, enum dcb_gpio_tag tag); - int nv50_gpio_set(struct drm_device *dev, enum dcb_gpio_tag tag, int state); -+int nvd0_gpio_get(struct drm_device *dev, enum dcb_gpio_tag tag); -+int nvd0_gpio_set(struct drm_device *dev, enum dcb_gpio_tag tag, int state); - int nv50_gpio_irq_register(struct drm_device *, enum dcb_gpio_tag, - void (*)(void *, int), void *); - void nv50_gpio_irq_unregister(struct drm_device *, enum dcb_gpio_tag, -@@ -1448,6 +1504,8 @@ static inline void nv_wr08(struct drm_device *dev, unsigned reg, u8 val) - nouveau_wait_eq(dev, 2000000000ULL, (reg), (mask), (val)) - #define nv_wait_ne(dev, reg, mask, val) \ - nouveau_wait_ne(dev, 2000000000ULL, (reg), (mask), (val)) -+#define nv_wait_cb(dev, func, data) \ -+ nouveau_wait_cb(dev, 2000000000ULL, (func), (data)) - - /* PRAMIN access */ - static inline u32 nv_ri32(struct drm_device *dev, unsigned offset) -@@ -1514,6 +1572,7 @@ enum { - NOUVEAU_REG_DEBUG_RMVIO = 0x80, - NOUVEAU_REG_DEBUG_VGAATTR = 0x100, - NOUVEAU_REG_DEBUG_EVO = 0x200, -+ NOUVEAU_REG_DEBUG_AUXCH = 0x400 - }; - - #define NV_REG_DEBUG(type, dev, fmt, arg...) do { \ -diff --git a/drivers/gpu/drm/nouveau/nouveau_encoder.h b/drivers/gpu/drm/nouveau/nouveau_encoder.h -index ae69b61..e5d6e3f 100644 ---- a/drivers/gpu/drm/nouveau/nouveau_encoder.h -+++ b/drivers/gpu/drm/nouveau/nouveau_encoder.h -@@ -49,17 +49,17 @@ struct nouveau_encoder { - - union { - struct { -- int mc_unknown; -- uint32_t unk0; -- uint32_t unk1; -- int dpcd_version; -+ u8 dpcd[8]; - int link_nr; - int link_bw; -- bool enhanced_frame; -+ u32 datarate; - } dp; - }; - }; - -+struct nouveau_encoder * -+find_encoder(struct drm_connector *connector, int type); -+ - static inline struct nouveau_encoder *nouveau_encoder(struct drm_encoder *enc) - { - struct drm_encoder_slave *slave = to_encoder_slave(enc); -@@ -83,21 +83,4 @@ nouveau_encoder_connector_get(struct nouveau_encoder *encoder); - int nv50_sor_create(struct drm_connector *, struct dcb_entry *); - int nv50_dac_create(struct drm_connector *, struct dcb_entry *); - --struct bit_displayport_encoder_table { -- uint32_t match; -- uint8_t record_nr; -- uint8_t unknown; -- uint16_t script0; -- uint16_t script1; -- uint16_t unknown_table; --} __attribute__ ((packed)); -- --struct bit_displayport_encoder_table_entry { -- uint8_t vs_level; -- uint8_t pre_level; -- uint8_t reg0; -- uint8_t reg1; -- uint8_t reg2; --} __attribute__ ((packed)); -- - #endif /* __NOUVEAU_ENCODER_H__ */ -diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c -index c919cfc..81116cf 100644 ---- a/drivers/gpu/drm/nouveau/nouveau_fence.c -+++ b/drivers/gpu/drm/nouveau/nouveau_fence.c -@@ -519,7 +519,7 @@ nouveau_fence_channel_init(struct nouveau_channel *chan) - if (USE_SEMA(dev) && dev_priv->chipset < 0x84) { - struct ttm_mem_reg *mem = &dev_priv->fence.bo->bo.mem; - -- ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY, -+ ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_FROM_MEMORY, - mem->start << PAGE_SHIFT, - mem->size, NV_MEM_ACCESS_RW, - NV_MEM_TARGET_VRAM, &obj); -diff --git a/drivers/gpu/drm/nouveau/nouveau_i2c.c b/drivers/gpu/drm/nouveau/nouveau_i2c.c -index cb389d0..f6a27fa 100644 ---- a/drivers/gpu/drm/nouveau/nouveau_i2c.c -+++ b/drivers/gpu/drm/nouveau/nouveau_i2c.c -@@ -107,6 +107,13 @@ nv4e_i2c_getsda(void *data) - return !!((nv_rd32(dev, i2c->rd) >> 16) & 8); - } - -+static const uint32_t nv50_i2c_port[] = { -+ 0x00e138, 0x00e150, 0x00e168, 0x00e180, -+ 0x00e254, 0x00e274, 0x00e764, 0x00e780, -+ 0x00e79c, 0x00e7b8 -+}; -+#define NV50_I2C_PORTS ARRAY_SIZE(nv50_i2c_port) -+ - static int - nv50_i2c_getscl(void *data) - { -@@ -130,28 +137,32 @@ static void - nv50_i2c_setscl(void *data, int state) - { - struct nouveau_i2c_chan *i2c = data; -- struct drm_device *dev = i2c->dev; - -- nv_wr32(dev, i2c->wr, 4 | (i2c->data ? 2 : 0) | (state ? 1 : 0)); -+ nv_wr32(i2c->dev, i2c->wr, 4 | (i2c->data ? 2 : 0) | (state ? 1 : 0)); - } - - static void - nv50_i2c_setsda(void *data, int state) - { - struct nouveau_i2c_chan *i2c = data; -- struct drm_device *dev = i2c->dev; - -- nv_wr32(dev, i2c->wr, -- (nv_rd32(dev, i2c->rd) & 1) | 4 | (state ? 2 : 0)); -+ nv_mask(i2c->dev, i2c->wr, 0x00000006, 4 | (state ? 2 : 0)); - i2c->data = state; - } - --static const uint32_t nv50_i2c_port[] = { -- 0x00e138, 0x00e150, 0x00e168, 0x00e180, -- 0x00e254, 0x00e274, 0x00e764, 0x00e780, -- 0x00e79c, 0x00e7b8 --}; --#define NV50_I2C_PORTS ARRAY_SIZE(nv50_i2c_port) -+static int -+nvd0_i2c_getscl(void *data) -+{ -+ struct nouveau_i2c_chan *i2c = data; -+ return !!(nv_rd32(i2c->dev, i2c->rd) & 0x10); -+} -+ -+static int -+nvd0_i2c_getsda(void *data) -+{ -+ struct nouveau_i2c_chan *i2c = data; -+ return !!(nv_rd32(i2c->dev, i2c->rd) & 0x20); -+} - - int - nouveau_i2c_init(struct drm_device *dev, struct dcb_i2c_entry *entry, int index) -@@ -163,7 +174,8 @@ nouveau_i2c_init(struct drm_device *dev, struct dcb_i2c_entry *entry, int index) - if (entry->chan) - return -EEXIST; - -- if (dev_priv->card_type >= NV_50 && entry->read >= NV50_I2C_PORTS) { -+ if (dev_priv->card_type >= NV_50 && -+ dev_priv->card_type <= NV_C0 && entry->read >= NV50_I2C_PORTS) { - NV_ERROR(dev, "unknown i2c port %d\n", entry->read); - return -EINVAL; - } -@@ -192,10 +204,17 @@ nouveau_i2c_init(struct drm_device *dev, struct dcb_i2c_entry *entry, int index) - case 5: - i2c->bit.setsda = nv50_i2c_setsda; - i2c->bit.setscl = nv50_i2c_setscl; -- i2c->bit.getsda = nv50_i2c_getsda; -- i2c->bit.getscl = nv50_i2c_getscl; -- i2c->rd = nv50_i2c_port[entry->read]; -- i2c->wr = i2c->rd; -+ if (dev_priv->card_type < NV_D0) { -+ i2c->bit.getsda = nv50_i2c_getsda; -+ i2c->bit.getscl = nv50_i2c_getscl; -+ i2c->rd = nv50_i2c_port[entry->read]; -+ i2c->wr = i2c->rd; -+ } else { -+ i2c->bit.getsda = nvd0_i2c_getsda; -+ i2c->bit.getscl = nvd0_i2c_getscl; -+ i2c->rd = 0x00d014 + (entry->read * 0x20); -+ i2c->wr = i2c->rd; -+ } - break; - case 6: - i2c->rd = entry->read; -@@ -267,7 +286,10 @@ nouveau_i2c_find(struct drm_device *dev, int index) - val = 0xe001; - } - -- nv_wr32(dev, reg, (nv_rd32(dev, reg) & ~0xf003) | val); -+ /* nfi, but neither auxch or i2c work if it's 1 */ -+ nv_mask(dev, reg + 0x0c, 0x00000001, 0x00000000); -+ /* nfi, but switches auxch vs normal i2c */ -+ nv_mask(dev, reg + 0x00, 0x0000f003, val); - } - - if (!i2c->chan && nouveau_i2c_init(dev, i2c, index)) -diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c -index f9ae2fc..36bec48 100644 ---- a/drivers/gpu/drm/nouveau/nouveau_mem.c -+++ b/drivers/gpu/drm/nouveau/nouveau_mem.c -@@ -408,8 +408,6 @@ nouveau_mem_vram_init(struct drm_device *dev) - if (ret) - return ret; - -- dev_priv->fb_phys = pci_resource_start(dev->pdev, 1); -- - ret = nouveau_ttm_global_init(dev_priv); - if (ret) - return ret; -@@ -504,35 +502,146 @@ nouveau_mem_gart_init(struct drm_device *dev) - return 0; - } - -+/* XXX: For now a dummy. More samples required, possibly even a card -+ * Called from nouveau_perf.c */ -+void nv30_mem_timing_entry(struct drm_device *dev, struct nouveau_pm_tbl_header *hdr, -+ struct nouveau_pm_tbl_entry *e, uint8_t magic_number, -+ struct nouveau_pm_memtiming *timing) { -+ -+ NV_DEBUG(dev,"Timing entry format unknown, please contact nouveau developers"); -+} -+ -+void nv40_mem_timing_entry(struct drm_device *dev, struct nouveau_pm_tbl_header *hdr, -+ struct nouveau_pm_tbl_entry *e, uint8_t magic_number, -+ struct nouveau_pm_memtiming *timing) { -+ -+ timing->reg_0 = (e->tRC << 24 | e->tRFC << 16 | e->tRAS << 8 | e->tRP); -+ -+ /* XXX: I don't trust the -1's and +1's... they must come -+ * from somewhere! */ -+ timing->reg_1 = (e->tWR + 2 + magic_number) << 24 | -+ 1 << 16 | -+ (e->tUNK_1 + 2 + magic_number) << 8 | -+ (e->tCL + 2 - magic_number); -+ timing->reg_2 = (magic_number << 24 | e->tUNK_12 << 16 | e->tUNK_11 << 8 | e->tUNK_10); -+ timing->reg_2 |= 0x20200000; -+ -+ NV_DEBUG(dev, "Entry %d: 220: %08x %08x %08x\n", timing->id, -+ timing->reg_0, timing->reg_1,timing->reg_2); -+} -+ -+void nv50_mem_timing_entry(struct drm_device *dev, struct bit_entry *P, struct nouveau_pm_tbl_header *hdr, -+ struct nouveau_pm_tbl_entry *e, uint8_t magic_number,struct nouveau_pm_memtiming *timing) { -+ struct drm_nouveau_private *dev_priv = dev->dev_private; -+ -+ uint8_t unk18 = 1, -+ unk19 = 1, -+ unk20 = 0, -+ unk21 = 0; -+ -+ switch (min(hdr->entry_len, (u8) 22)) { -+ case 22: -+ unk21 = e->tUNK_21; -+ case 21: -+ unk20 = e->tUNK_20; -+ case 20: -+ unk19 = e->tUNK_19; -+ case 19: -+ unk18 = e->tUNK_18; -+ break; -+ } -+ -+ timing->reg_0 = (e->tRC << 24 | e->tRFC << 16 | e->tRAS << 8 | e->tRP); -+ -+ /* XXX: I don't trust the -1's and +1's... they must come -+ * from somewhere! */ -+ timing->reg_1 = (e->tWR + unk19 + 1 + magic_number) << 24 | -+ max(unk18, (u8) 1) << 16 | -+ (e->tUNK_1 + unk19 + 1 + magic_number) << 8; -+ if (dev_priv->chipset == 0xa8) { -+ timing->reg_1 |= (e->tCL - 1); -+ } else { -+ timing->reg_1 |= (e->tCL + 2 - magic_number); -+ } -+ timing->reg_2 = (e->tUNK_12 << 16 | e->tUNK_11 << 8 | e->tUNK_10); -+ -+ timing->reg_5 = (e->tRAS << 24 | e->tRC); -+ timing->reg_5 += max(e->tUNK_10, e->tUNK_11) << 16; -+ -+ if (P->version == 1) { -+ timing->reg_2 |= magic_number << 24; -+ timing->reg_3 = (0x14 + e->tCL) << 24 | -+ 0x16 << 16 | -+ (e->tCL - 1) << 8 | -+ (e->tCL - 1); -+ timing->reg_4 = (nv_rd32(dev,0x10022c) & 0xffff0000) | e->tUNK_13 << 8 | e->tUNK_13; -+ timing->reg_5 |= (e->tCL + 2) << 8; -+ timing->reg_7 = 0x4000202 | (e->tCL - 1) << 16; -+ } else { -+ timing->reg_2 |= (unk19 - 1) << 24; -+ /* XXX: reg_10022c for recentish cards pretty much unknown*/ -+ timing->reg_3 = e->tCL - 1; -+ timing->reg_4 = (unk20 << 24 | unk21 << 16 | -+ e->tUNK_13 << 8 | e->tUNK_13); -+ /* XXX: +6? */ -+ timing->reg_5 |= (unk19 + 6) << 8; -+ -+ /* XXX: reg_10023c currently unknown -+ * 10023c seen as 06xxxxxx, 0bxxxxxx or 0fxxxxxx */ -+ timing->reg_7 = 0x202; -+ } -+ -+ NV_DEBUG(dev, "Entry %d: 220: %08x %08x %08x %08x\n", timing->id, -+ timing->reg_0, timing->reg_1, -+ timing->reg_2, timing->reg_3); -+ NV_DEBUG(dev, " 230: %08x %08x %08x %08x\n", -+ timing->reg_4, timing->reg_5, -+ timing->reg_6, timing->reg_7); -+ NV_DEBUG(dev, " 240: %08x\n", timing->reg_8); -+} -+ -+void nvc0_mem_timing_entry(struct drm_device *dev, struct nouveau_pm_tbl_header *hdr, -+ struct nouveau_pm_tbl_entry *e, struct nouveau_pm_memtiming *timing) { -+ timing->reg_0 = (e->tRC << 24 | (e->tRFC & 0x7f) << 17 | e->tRAS << 8 | e->tRP); -+ timing->reg_1 = (nv_rd32(dev,0x10f294) & 0xff000000) | (e->tUNK_11&0x0f) << 20 | (e->tUNK_19 << 7) | (e->tCL & 0x0f); -+ timing->reg_2 = (nv_rd32(dev,0x10f298) & 0xff0000ff) | e->tWR << 16 | e->tUNK_1 << 8; -+ timing->reg_3 = e->tUNK_20 << 9 | e->tUNK_13; -+ timing->reg_4 = (nv_rd32(dev,0x10f2a0) & 0xfff000ff) | e->tUNK_12 << 15; -+ NV_DEBUG(dev, "Entry %d: 290: %08x %08x %08x %08x\n", timing->id, -+ timing->reg_0, timing->reg_1, -+ timing->reg_2, timing->reg_3); -+ NV_DEBUG(dev, " 2a0: %08x %08x %08x %08x\n", -+ timing->reg_4, timing->reg_5, -+ timing->reg_6, timing->reg_7); -+} -+ -+/** -+ * Processes the Memory Timing BIOS table, stores generated -+ * register values -+ * @pre init scripts were run, memtiming regs are initialized -+ */ - 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; - struct nvbios *bios = &dev_priv->vbios; - struct bit_entry P; -- u8 tUNK_0, tUNK_1, tUNK_2; -- u8 tRP; /* Byte 3 */ -- u8 tRAS; /* Byte 5 */ -- u8 tRFC; /* Byte 7 */ -- u8 tRC; /* Byte 9 */ -- u8 tUNK_10, tUNK_11, tUNK_12, tUNK_13, tUNK_14; -- u8 tUNK_18, tUNK_19, tUNK_20, tUNK_21; -- u8 magic_number = 0; /* Yeah... sorry*/ -- u8 *mem = NULL, *entry; -- int i, recordlen, entries; -+ struct nouveau_pm_tbl_header *hdr = NULL; -+ uint8_t magic_number; -+ u8 *entry; -+ int i; - - if (bios->type == NVBIOS_BIT) { - if (bit_table(dev, 'P', &P)) - return; - - if (P.version == 1) -- mem = ROMPTR(bios, P.data[4]); -+ hdr = (struct nouveau_pm_tbl_header *) ROMPTR(bios, P.data[4]); - else - if (P.version == 2) -- mem = ROMPTR(bios, P.data[8]); -+ hdr = (struct nouveau_pm_tbl_header *) ROMPTR(bios, P.data[8]); - else { - NV_WARN(dev, "unknown mem for BIT P %d\n", P.version); - } -@@ -541,150 +650,56 @@ nouveau_mem_timing_init(struct drm_device *dev) - return; - } - -- if (!mem) { -+ if (!hdr) { - NV_DEBUG(dev, "memory timing table pointer invalid\n"); - return; - } - -- if (mem[0] != 0x10) { -- NV_WARN(dev, "memory timing table 0x%02x unknown\n", mem[0]); -+ if (hdr->version != 0x10) { -+ NV_WARN(dev, "memory timing table 0x%02x unknown\n", hdr->version); - return; - } - - /* validate record length */ -- entries = mem[2]; -- recordlen = mem[3]; -- if (recordlen < 15) { -- NV_ERROR(dev, "mem timing table length unknown: %d\n", mem[3]); -+ if (hdr->entry_len < 15) { -+ NV_ERROR(dev, "mem timing table length unknown: %d\n", hdr->entry_len); - return; - } - - /* parse vbios entries into common format */ - memtimings->timing = -- kcalloc(entries, sizeof(*memtimings->timing), GFP_KERNEL); -+ kcalloc(hdr->entry_cnt, sizeof(*memtimings->timing), GFP_KERNEL); - if (!memtimings->timing) - return; - - /* Get "some number" from the timing reg for NV_40 and NV_50 -- * Used in calculations later */ -- if (dev_priv->card_type >= NV_40 && dev_priv->chipset < 0x98) { -+ * Used in calculations later... source unknown */ -+ magic_number = 0; -+ if (P.version == 1) { - magic_number = (nv_rd32(dev, 0x100228) & 0x0f000000) >> 24; - } - -- entry = mem + mem[1]; -- for (i = 0; i < entries; i++, entry += recordlen) { -+ entry = (u8*) hdr + hdr->header_len; -+ for (i = 0; i < hdr->entry_cnt; i++, entry += hdr->entry_len) { - struct nouveau_pm_memtiming *timing = &pm->memtimings.timing[i]; - if (entry[0] == 0) - continue; - -- tUNK_18 = 1; -- tUNK_19 = 1; -- tUNK_20 = 0; -- tUNK_21 = 0; -- switch (min(recordlen, 22)) { -- case 22: -- tUNK_21 = entry[21]; -- case 21: -- tUNK_20 = entry[20]; -- case 20: -- tUNK_19 = entry[19]; -- case 19: -- tUNK_18 = entry[18]; -- default: -- tUNK_0 = entry[0]; -- tUNK_1 = entry[1]; -- tUNK_2 = entry[2]; -- tRP = entry[3]; -- tRAS = entry[5]; -- tRFC = entry[7]; -- tRC = entry[9]; -- tUNK_10 = entry[10]; -- tUNK_11 = entry[11]; -- tUNK_12 = entry[12]; -- tUNK_13 = entry[13]; -- tUNK_14 = entry[14]; -- break; -- } -- -- timing->reg_100220 = (tRC << 24 | tRFC << 16 | tRAS << 8 | tRP); -- -- /* XXX: I don't trust the -1's and +1's... they must come -- * from somewhere! */ -- timing->reg_100224 = (tUNK_0 + tUNK_19 + 1 + magic_number) << 24 | -- max(tUNK_18, (u8) 1) << 16 | -- (tUNK_1 + tUNK_19 + 1 + magic_number) << 8; -- if (dev_priv->chipset == 0xa8) { -- timing->reg_100224 |= (tUNK_2 - 1); -- } else { -- timing->reg_100224 |= (tUNK_2 + 2 - magic_number); -- } -- -- timing->reg_100228 = (tUNK_12 << 16 | tUNK_11 << 8 | tUNK_10); -- if (dev_priv->chipset >= 0xa3 && dev_priv->chipset < 0xaa) -- timing->reg_100228 |= (tUNK_19 - 1) << 24; -- else -- timing->reg_100228 |= magic_number << 24; -- -- if (dev_priv->card_type == NV_40) { -- /* NV40: don't know what the rest of the regs are.. -- * And don't need to know either */ -- timing->reg_100228 |= 0x20200000; -- } else if (dev_priv->card_type >= NV_50) { -- if (dev_priv->chipset < 0x98 || -- (dev_priv->chipset == 0x98 && -- dev_priv->stepping <= 0xa1)) { -- timing->reg_10022c = (0x14 + tUNK_2) << 24 | -- 0x16 << 16 | -- (tUNK_2 - 1) << 8 | -- (tUNK_2 - 1); -- } else { -- /* XXX: reg_10022c for recentish cards */ -- timing->reg_10022c = tUNK_2 - 1; -- } -- -- timing->reg_100230 = (tUNK_20 << 24 | tUNK_21 << 16 | -- tUNK_13 << 8 | tUNK_13); -- -- timing->reg_100234 = (tRAS << 24 | tRC); -- timing->reg_100234 += max(tUNK_10, tUNK_11) << 16; -- -- if (dev_priv->chipset < 0x98 || -- (dev_priv->chipset == 0x98 && -- dev_priv->stepping <= 0xa1)) { -- timing->reg_100234 |= (tUNK_2 + 2) << 8; -- } else { -- /* XXX: +6? */ -- timing->reg_100234 |= (tUNK_19 + 6) << 8; -- } -- -- /* XXX; reg_100238 -- * reg_100238: 0x00?????? */ -- timing->reg_10023c = 0x202; -- if (dev_priv->chipset < 0x98 || -- (dev_priv->chipset == 0x98 && -- dev_priv->stepping <= 0xa1)) { -- timing->reg_10023c |= 0x4000000 | (tUNK_2 - 1) << 16; -- } else { -- /* XXX: reg_10023c -- * currently unknown -- * 10023c seen as 06xxxxxx, 0bxxxxxx or 0fxxxxxx */ -- } -- -- /* XXX: reg_100240? */ -- } - timing->id = i; -- -- NV_DEBUG(dev, "Entry %d: 220: %08x %08x %08x %08x\n", i, -- timing->reg_100220, timing->reg_100224, -- timing->reg_100228, timing->reg_10022c); -- NV_DEBUG(dev, " 230: %08x %08x %08x %08x\n", -- timing->reg_100230, timing->reg_100234, -- timing->reg_100238, timing->reg_10023c); -- NV_DEBUG(dev, " 240: %08x\n", timing->reg_100240); -+ timing->WR = entry[0]; -+ timing->CL = entry[2]; -+ -+ if(dev_priv->card_type <= NV_40) { -+ nv40_mem_timing_entry(dev,hdr,(struct nouveau_pm_tbl_entry*) entry,magic_number,&pm->memtimings.timing[i]); -+ } else if(dev_priv->card_type == NV_50){ -+ nv50_mem_timing_entry(dev,&P,hdr,(struct nouveau_pm_tbl_entry*) entry,magic_number,&pm->memtimings.timing[i]); -+ } else if(dev_priv->card_type == NV_C0) { -+ nvc0_mem_timing_entry(dev,hdr,(struct nouveau_pm_tbl_entry*) entry,&pm->memtimings.timing[i]); -+ } - } - -- memtimings->nr_timing = entries; -- memtimings->supported = (dev_priv->chipset <= 0x98); -+ memtimings->nr_timing = hdr->entry_cnt; -+ memtimings->supported = P.version == 1; - } - - void -@@ -693,7 +708,10 @@ nouveau_mem_timing_fini(struct drm_device *dev) - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_pm_memtimings *mem = &dev_priv->engine.pm.memtimings; - -- kfree(mem->timing); -+ if(mem->timing) { -+ kfree(mem->timing); -+ mem->timing = NULL; -+ } - } - - static int -diff --git a/drivers/gpu/drm/nouveau/nouveau_mm.c b/drivers/gpu/drm/nouveau/nouveau_mm.c -index 1640dec..b29ffb3 100644 ---- a/drivers/gpu/drm/nouveau/nouveau_mm.c -+++ b/drivers/gpu/drm/nouveau/nouveau_mm.c -@@ -27,7 +27,7 @@ - #include "nouveau_mm.h" - - static inline void --region_put(struct nouveau_mm *rmm, struct nouveau_mm_node *a) -+region_put(struct nouveau_mm *mm, struct nouveau_mm_node *a) - { - list_del(&a->nl_entry); - list_del(&a->fl_entry); -@@ -35,7 +35,7 @@ region_put(struct nouveau_mm *rmm, struct nouveau_mm_node *a) - } - - static struct nouveau_mm_node * --region_split(struct nouveau_mm *rmm, struct nouveau_mm_node *a, u32 size) -+region_split(struct nouveau_mm *mm, struct nouveau_mm_node *a, u32 size) - { - struct nouveau_mm_node *b; - -@@ -57,33 +57,33 @@ region_split(struct nouveau_mm *rmm, struct nouveau_mm_node *a, u32 size) - return b; - } - --#define node(root, dir) ((root)->nl_entry.dir == &rmm->nodes) ? NULL : \ -+#define node(root, dir) ((root)->nl_entry.dir == &mm->nodes) ? NULL : \ - list_entry((root)->nl_entry.dir, struct nouveau_mm_node, nl_entry) - - void --nouveau_mm_put(struct nouveau_mm *rmm, struct nouveau_mm_node *this) -+nouveau_mm_put(struct nouveau_mm *mm, struct nouveau_mm_node *this) - { - struct nouveau_mm_node *prev = node(this, prev); - struct nouveau_mm_node *next = node(this, next); - -- list_add(&this->fl_entry, &rmm->free); -+ list_add(&this->fl_entry, &mm->free); - this->type = 0; - - if (prev && prev->type == 0) { - prev->length += this->length; -- region_put(rmm, this); -+ region_put(mm, this); - this = prev; - } - - if (next && next->type == 0) { - next->offset = this->offset; - next->length += this->length; -- region_put(rmm, this); -+ region_put(mm, this); - } - } - - int --nouveau_mm_get(struct nouveau_mm *rmm, int type, u32 size, u32 size_nc, -+nouveau_mm_get(struct nouveau_mm *mm, int type, u32 size, u32 size_nc, - u32 align, struct nouveau_mm_node **pnode) - { - struct nouveau_mm_node *prev, *this, *next; -@@ -92,17 +92,17 @@ nouveau_mm_get(struct nouveau_mm *rmm, int type, u32 size, u32 size_nc, - u32 splitoff; - u32 s, e; - -- list_for_each_entry(this, &rmm->free, fl_entry) { -+ list_for_each_entry(this, &mm->free, fl_entry) { - e = this->offset + this->length; - s = this->offset; - - prev = node(this, prev); - if (prev && prev->type != type) -- s = roundup(s, rmm->block_size); -+ s = roundup(s, mm->block_size); - - next = node(this, next); - if (next && next->type != type) -- e = rounddown(e, rmm->block_size); -+ e = rounddown(e, mm->block_size); - - s = (s + align_mask) & ~align_mask; - e &= ~align_mask; -@@ -110,10 +110,10 @@ nouveau_mm_get(struct nouveau_mm *rmm, int type, u32 size, u32 size_nc, - continue; - - splitoff = s - this->offset; -- if (splitoff && !region_split(rmm, this, splitoff)) -+ if (splitoff && !region_split(mm, this, splitoff)) - return -ENOMEM; - -- this = region_split(rmm, this, min(size, e - s)); -+ this = region_split(mm, this, min(size, e - s)); - if (!this) - return -ENOMEM; - -@@ -127,52 +127,49 @@ nouveau_mm_get(struct nouveau_mm *rmm, int type, u32 size, u32 size_nc, - } - - int --nouveau_mm_init(struct nouveau_mm **prmm, u32 offset, u32 length, u32 block) -+nouveau_mm_init(struct nouveau_mm *mm, u32 offset, u32 length, u32 block) - { -- struct nouveau_mm *rmm; -- struct nouveau_mm_node *heap; -+ struct nouveau_mm_node *node; -+ -+ if (block) { -+ mutex_init(&mm->mutex); -+ INIT_LIST_HEAD(&mm->nodes); -+ INIT_LIST_HEAD(&mm->free); -+ mm->block_size = block; -+ mm->heap_nodes = 0; -+ } - -- heap = kzalloc(sizeof(*heap), GFP_KERNEL); -- if (!heap) -+ node = kzalloc(sizeof(*node), GFP_KERNEL); -+ if (!node) - return -ENOMEM; -- heap->offset = roundup(offset, block); -- heap->length = rounddown(offset + length, block) - heap->offset; -+ node->offset = roundup(offset, mm->block_size); -+ node->length = rounddown(offset + length, mm->block_size) - node->offset; - -- rmm = kzalloc(sizeof(*rmm), GFP_KERNEL); -- if (!rmm) { -- kfree(heap); -- return -ENOMEM; -- } -- rmm->block_size = block; -- mutex_init(&rmm->mutex); -- INIT_LIST_HEAD(&rmm->nodes); -- INIT_LIST_HEAD(&rmm->free); -- list_add(&heap->nl_entry, &rmm->nodes); -- list_add(&heap->fl_entry, &rmm->free); -- -- *prmm = rmm; -+ list_add_tail(&node->nl_entry, &mm->nodes); -+ list_add_tail(&node->fl_entry, &mm->free); -+ mm->heap_nodes++; - return 0; - } - - int --nouveau_mm_fini(struct nouveau_mm **prmm) -+nouveau_mm_fini(struct nouveau_mm *mm) - { -- struct nouveau_mm *rmm = *prmm; - struct nouveau_mm_node *node, *heap = -- list_first_entry(&rmm->nodes, struct nouveau_mm_node, nl_entry); -- -- if (!list_is_singular(&rmm->nodes)) { -- printk(KERN_ERR "nouveau_mm not empty at destroy time!\n"); -- list_for_each_entry(node, &rmm->nodes, nl_entry) { -- printk(KERN_ERR "0x%02x: 0x%08x 0x%08x\n", -- node->type, node->offset, node->length); -+ list_first_entry(&mm->nodes, struct nouveau_mm_node, nl_entry); -+ int nodes = 0; -+ -+ list_for_each_entry(node, &mm->nodes, nl_entry) { -+ if (nodes++ == mm->heap_nodes) { -+ printk(KERN_ERR "nouveau_mm in use at destroy time!\n"); -+ list_for_each_entry(node, &mm->nodes, nl_entry) { -+ printk(KERN_ERR "0x%02x: 0x%08x 0x%08x\n", -+ node->type, node->offset, node->length); -+ } -+ WARN_ON(1); -+ return -EBUSY; - } -- WARN_ON(1); -- return -EBUSY; - } - - kfree(heap); -- kfree(rmm); -- *prmm = NULL; - return 0; - } -diff --git a/drivers/gpu/drm/nouveau/nouveau_mm.h b/drivers/gpu/drm/nouveau/nouveau_mm.h -index b9c016d..57a600c 100644 ---- a/drivers/gpu/drm/nouveau/nouveau_mm.h -+++ b/drivers/gpu/drm/nouveau/nouveau_mm.h -@@ -42,10 +42,11 @@ struct nouveau_mm { - struct mutex mutex; - - u32 block_size; -+ int heap_nodes; - }; - --int nouveau_mm_init(struct nouveau_mm **, u32 offset, u32 length, u32 block); --int nouveau_mm_fini(struct nouveau_mm **); -+int nouveau_mm_init(struct nouveau_mm *, u32 offset, u32 length, u32 block); -+int nouveau_mm_fini(struct nouveau_mm *); - int nouveau_mm_pre(struct nouveau_mm *); - int nouveau_mm_get(struct nouveau_mm *, int type, u32 size, u32 size_nc, - u32 align, struct nouveau_mm_node **); -diff --git a/drivers/gpu/drm/nouveau/nouveau_object.c b/drivers/gpu/drm/nouveau/nouveau_object.c -index 159b7c4..02222c5 100644 ---- a/drivers/gpu/drm/nouveau/nouveau_object.c -+++ b/drivers/gpu/drm/nouveau/nouveau_object.c -@@ -693,6 +693,7 @@ nouveau_gpuobj_channel_init_pramin(struct nouveau_channel *chan) - static int - nvc0_gpuobj_channel_init(struct nouveau_channel *chan, struct nouveau_vm *vm) - { -+ struct drm_nouveau_private *dev_priv = chan->dev->dev_private; - struct drm_device *dev = chan->dev; - struct nouveau_gpuobj *pgd = NULL; - struct nouveau_vm_pgd *vpgd; -@@ -722,6 +723,9 @@ nvc0_gpuobj_channel_init(struct nouveau_channel *chan, struct nouveau_vm *vm) - nv_wo32(chan->ramin, 0x020c, 0x000000ff); - - /* map display semaphore buffers into channel's vm */ -+ if (dev_priv->card_type >= NV_D0) -+ return 0; -+ - for (i = 0; i < 2; i++) { - struct nv50_display_crtc *dispc = &nv50_display(dev)->crtc[i]; - -@@ -746,7 +750,7 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan, - int ret, i; - - NV_DEBUG(dev, "ch%d vram=0x%08x tt=0x%08x\n", chan->id, vram_h, tt_h); -- if (dev_priv->card_type == NV_C0) -+ if (dev_priv->card_type >= NV_C0) - return nvc0_gpuobj_channel_init(chan, vm); - - /* Allocate a chunk of memory for per-channel object storage */ -@@ -793,7 +797,7 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan, - return ret; - - /* dma objects for display sync channel semaphore blocks */ -- for (i = 0; i < 2; i++) { -+ for (i = 0; i < dev->mode_config.num_crtc; i++) { - struct nouveau_gpuobj *sem = NULL; - struct nv50_display_crtc *dispc = - &nv50_display(dev)->crtc[i]; -@@ -875,18 +879,18 @@ nouveau_gpuobj_channel_takedown(struct nouveau_channel *chan) - - NV_DEBUG(dev, "ch%d\n", chan->id); - -- if (dev_priv->card_type >= NV_50) { -+ if (dev_priv->card_type >= NV_50 && dev_priv->card_type <= NV_C0) { - struct nv50_display *disp = nv50_display(dev); - -- for (i = 0; i < 2; i++) { -+ for (i = 0; i < dev->mode_config.num_crtc; i++) { - struct nv50_display_crtc *dispc = &disp->crtc[i]; - nouveau_bo_vma_del(dispc->sem.bo, &chan->dispc_vma[i]); - } -- -- nouveau_vm_ref(NULL, &chan->vm, chan->vm_pd); -- nouveau_gpuobj_ref(NULL, &chan->vm_pd); - } - -+ nouveau_vm_ref(NULL, &chan->vm, chan->vm_pd); -+ nouveau_gpuobj_ref(NULL, &chan->vm_pd); -+ - if (drm_mm_initialized(&chan->ramin_heap)) - drm_mm_takedown(&chan->ramin_heap); - nouveau_gpuobj_ref(NULL, &chan->ramin); -diff --git a/drivers/gpu/drm/nouveau/nouveau_perf.c b/drivers/gpu/drm/nouveau/nouveau_perf.c -index ef9dec0..9f178aa 100644 ---- a/drivers/gpu/drm/nouveau/nouveau_perf.c -+++ b/drivers/gpu/drm/nouveau/nouveau_perf.c -@@ -127,13 +127,57 @@ nouveau_perf_timing(struct drm_device *dev, struct bit_entry *P, - - entry += ramcfg * recordlen; - if (entry[1] >= pm->memtimings.nr_timing) { -- NV_WARN(dev, "timingset %d does not exist\n", entry[1]); -+ if (entry[1] != 0xff) -+ NV_WARN(dev, "timingset %d does not exist\n", entry[1]); - return NULL; - } - - return &pm->memtimings.timing[entry[1]]; - } - -+static void -+nouveau_perf_voltage(struct drm_device *dev, struct bit_entry *P, -+ struct nouveau_pm_level *perflvl) -+{ -+ struct drm_nouveau_private *dev_priv = dev->dev_private; -+ struct nvbios *bios = &dev_priv->vbios; -+ u8 *vmap; -+ int id; -+ -+ id = perflvl->volt_min; -+ perflvl->volt_min = 0; -+ -+ /* boards using voltage table version <0x40 store the voltage -+ * level directly in the perflvl entry as a multiple of 10mV -+ */ -+ if (dev_priv->engine.pm.voltage.version < 0x40) { -+ perflvl->volt_min = id * 10000; -+ perflvl->volt_max = perflvl->volt_min; -+ return; -+ } -+ -+ /* on newer ones, the perflvl stores an index into yet another -+ * vbios table containing a min/max voltage value for the perflvl -+ */ -+ if (P->version != 2 || P->length < 34) { -+ NV_DEBUG(dev, "where's our volt map table ptr? %d %d\n", -+ P->version, P->length); -+ return; -+ } -+ -+ vmap = ROMPTR(bios, P->data[32]); -+ if (!vmap) { -+ NV_DEBUG(dev, "volt map table pointer invalid\n"); -+ return; -+ } -+ -+ if (id < vmap[3]) { -+ vmap += vmap[1] + (vmap[2] * id); -+ perflvl->volt_min = ROM32(vmap[0]); -+ perflvl->volt_max = ROM32(vmap[4]); -+ } -+} -+ - void - nouveau_perf_init(struct drm_device *dev) - { -@@ -141,6 +185,8 @@ nouveau_perf_init(struct drm_device *dev) - struct nouveau_pm_engine *pm = &dev_priv->engine.pm; - struct nvbios *bios = &dev_priv->vbios; - struct bit_entry P; -+ struct nouveau_pm_memtimings *memtimings = &pm->memtimings; -+ struct nouveau_pm_tbl_header mt_hdr; - u8 version, headerlen, recordlen, entries; - u8 *perf, *entry; - int vid, i; -@@ -188,6 +234,22 @@ nouveau_perf_init(struct drm_device *dev) - } - - entry = perf + headerlen; -+ -+ /* For version 0x15, initialize memtiming table */ -+ if(version == 0x15) { -+ memtimings->timing = -+ kcalloc(entries, sizeof(*memtimings->timing), GFP_KERNEL); -+ if(!memtimings) { -+ NV_WARN(dev,"Could not allocate memtiming table\n"); -+ return; -+ } -+ -+ mt_hdr.entry_cnt = entries; -+ mt_hdr.entry_len = 14; -+ mt_hdr.version = version; -+ mt_hdr.header_len = 4; -+ } -+ - for (i = 0; i < entries; i++) { - struct nouveau_pm_level *perflvl = &pm->perflvl[pm->nr_perflvl]; - -@@ -203,7 +265,8 @@ nouveau_perf_init(struct drm_device *dev) - case 0x13: - case 0x15: - perflvl->fanspeed = entry[55]; -- perflvl->voltage = (recordlen > 56) ? entry[56] : 0; -+ if (recordlen > 56) -+ perflvl->volt_min = entry[56]; - perflvl->core = ROM32(entry[1]) * 10; - perflvl->memory = ROM32(entry[5]) * 20; - break; -@@ -211,9 +274,10 @@ nouveau_perf_init(struct drm_device *dev) - case 0x23: - case 0x24: - perflvl->fanspeed = entry[4]; -- perflvl->voltage = entry[5]; -- perflvl->core = ROM16(entry[6]) * 1000; -- -+ perflvl->volt_min = entry[5]; -+ perflvl->shader = ROM16(entry[6]) * 1000; -+ perflvl->core = perflvl->shader; -+ perflvl->core += (signed char)entry[8] * 1000; - if (dev_priv->chipset == 0x49 || - dev_priv->chipset == 0x4b) - perflvl->memory = ROM16(entry[11]) * 1000; -@@ -223,7 +287,7 @@ nouveau_perf_init(struct drm_device *dev) - break; - case 0x25: - perflvl->fanspeed = entry[4]; -- perflvl->voltage = entry[5]; -+ perflvl->volt_min = entry[5]; - perflvl->core = ROM16(entry[6]) * 1000; - perflvl->shader = ROM16(entry[10]) * 1000; - perflvl->memory = ROM16(entry[12]) * 1000; -@@ -232,7 +296,7 @@ nouveau_perf_init(struct drm_device *dev) - perflvl->memscript = ROM16(entry[2]); - case 0x35: - perflvl->fanspeed = entry[6]; -- perflvl->voltage = entry[7]; -+ perflvl->volt_min = entry[7]; - perflvl->core = ROM16(entry[8]) * 1000; - perflvl->shader = ROM16(entry[10]) * 1000; - perflvl->memory = ROM16(entry[12]) * 1000; -@@ -240,30 +304,34 @@ nouveau_perf_init(struct drm_device *dev) - perflvl->unk05 = ROM16(entry[16]) * 1000; - break; - case 0x40: --#define subent(n) entry[perf[2] + ((n) * perf[3])] -+#define subent(n) (ROM16(entry[perf[2] + ((n) * perf[3])]) & 0xfff) * 1000 - perflvl->fanspeed = 0; /*XXX*/ -- perflvl->voltage = entry[2]; -+ perflvl->volt_min = entry[2]; - if (dev_priv->card_type == NV_50) { -- perflvl->core = ROM16(subent(0)) & 0xfff; -- perflvl->shader = ROM16(subent(1)) & 0xfff; -- perflvl->memory = ROM16(subent(2)) & 0xfff; -+ perflvl->core = subent(0); -+ perflvl->shader = subent(1); -+ perflvl->memory = subent(2); -+ perflvl->vdec = subent(3); -+ perflvl->unka0 = subent(4); - } else { -- perflvl->shader = ROM16(subent(3)) & 0xfff; -+ perflvl->hub06 = subent(0); -+ perflvl->hub01 = subent(1); -+ perflvl->copy = subent(2); -+ perflvl->shader = subent(3); -+ perflvl->rop = subent(4); -+ perflvl->memory = subent(5); -+ perflvl->vdec = subent(6); -+ perflvl->daemon = subent(10); -+ perflvl->hub07 = subent(11); - perflvl->core = perflvl->shader / 2; -- perflvl->unk0a = ROM16(subent(4)) & 0xfff; -- perflvl->memory = ROM16(subent(5)) & 0xfff; - } -- -- perflvl->core *= 1000; -- perflvl->shader *= 1000; -- perflvl->memory *= 1000; -- perflvl->unk0a *= 1000; - break; - } - - /* make sure vid is valid */ -- if (pm->voltage.supported && perflvl->voltage) { -- vid = nouveau_volt_vid_lookup(dev, perflvl->voltage); -+ nouveau_perf_voltage(dev, &P, perflvl); -+ if (pm->voltage.supported && perflvl->volt_min) { -+ vid = nouveau_volt_vid_lookup(dev, perflvl->volt_min); - if (vid < 0) { - NV_DEBUG(dev, "drop perflvl %d, bad vid\n", i); - entry += recordlen; -@@ -272,7 +340,11 @@ nouveau_perf_init(struct drm_device *dev) - } - - /* get the corresponding memory timings */ -- if (version > 0x15) { -+ if (version == 0x15) { -+ memtimings->timing[i].id = i; -+ nv30_mem_timing_entry(dev,&mt_hdr,(struct nouveau_pm_tbl_entry*) &entry[41],0,&memtimings->timing[i]); -+ perflvl->timing = &memtimings->timing[i]; -+ } else if (version > 0x15) { - /* last 3 args are for < 0x40, ignored for >= 0x40 */ - perflvl->timing = - nouveau_perf_timing(dev, &P, -diff --git a/drivers/gpu/drm/nouveau/nouveau_pm.c b/drivers/gpu/drm/nouveau/nouveau_pm.c -index da8d994..a539fd2 100644 ---- a/drivers/gpu/drm/nouveau/nouveau_pm.c -+++ b/drivers/gpu/drm/nouveau/nouveau_pm.c -@@ -64,18 +64,26 @@ nouveau_pm_perflvl_set(struct drm_device *dev, struct nouveau_pm_level *perflvl) - if (perflvl == pm->cur) - return 0; - -- if (pm->voltage.supported && pm->voltage_set && perflvl->voltage) { -- ret = pm->voltage_set(dev, perflvl->voltage); -+ if (pm->voltage.supported && pm->voltage_set && perflvl->volt_min) { -+ ret = pm->voltage_set(dev, perflvl->volt_min); - if (ret) { - NV_ERROR(dev, "voltage_set %d failed: %d\n", -- perflvl->voltage, ret); -+ perflvl->volt_min, ret); - } - } - -- nouveau_pm_clock_set(dev, perflvl, PLL_CORE, perflvl->core); -- nouveau_pm_clock_set(dev, perflvl, PLL_SHADER, perflvl->shader); -- nouveau_pm_clock_set(dev, perflvl, PLL_MEMORY, perflvl->memory); -- nouveau_pm_clock_set(dev, perflvl, PLL_UNK05, perflvl->unk05); -+ if (pm->clocks_pre) { -+ void *state = pm->clocks_pre(dev, perflvl); -+ if (IS_ERR(state)) -+ return PTR_ERR(state); -+ pm->clocks_set(dev, state); -+ } else -+ if (pm->clock_set) { -+ nouveau_pm_clock_set(dev, perflvl, PLL_CORE, perflvl->core); -+ nouveau_pm_clock_set(dev, perflvl, PLL_SHADER, perflvl->shader); -+ nouveau_pm_clock_set(dev, perflvl, PLL_MEMORY, perflvl->memory); -+ nouveau_pm_clock_set(dev, perflvl, PLL_UNK05, perflvl->unk05); -+ } - - pm->cur = perflvl; - return 0; -@@ -92,9 +100,6 @@ nouveau_pm_profile_set(struct drm_device *dev, const char *profile) - if (nouveau_perflvl_wr != 7777) - return -EPERM; - -- if (!pm->clock_set) -- return -EINVAL; -- - if (!strncmp(profile, "boot", 4)) - perflvl = &pm->boot; - else { -@@ -123,31 +128,37 @@ nouveau_pm_perflvl_get(struct drm_device *dev, struct nouveau_pm_level *perflvl) - struct nouveau_pm_engine *pm = &dev_priv->engine.pm; - int ret; - -- if (!pm->clock_get) -- return -EINVAL; -- - memset(perflvl, 0, sizeof(*perflvl)); - -- ret = pm->clock_get(dev, PLL_CORE); -- if (ret > 0) -- perflvl->core = ret; -+ if (pm->clocks_get) { -+ ret = pm->clocks_get(dev, perflvl); -+ if (ret) -+ return ret; -+ } else -+ if (pm->clock_get) { -+ ret = pm->clock_get(dev, PLL_CORE); -+ if (ret > 0) -+ perflvl->core = ret; - -- ret = pm->clock_get(dev, PLL_MEMORY); -- if (ret > 0) -- perflvl->memory = ret; -+ ret = pm->clock_get(dev, PLL_MEMORY); -+ if (ret > 0) -+ perflvl->memory = ret; - -- ret = pm->clock_get(dev, PLL_SHADER); -- if (ret > 0) -- perflvl->shader = ret; -+ ret = pm->clock_get(dev, PLL_SHADER); -+ if (ret > 0) -+ perflvl->shader = ret; - -- ret = pm->clock_get(dev, PLL_UNK05); -- if (ret > 0) -- perflvl->unk05 = ret; -+ ret = pm->clock_get(dev, PLL_UNK05); -+ if (ret > 0) -+ perflvl->unk05 = ret; -+ } - - if (pm->voltage.supported && pm->voltage_get) { - ret = pm->voltage_get(dev); -- if (ret > 0) -- perflvl->voltage = ret; -+ if (ret > 0) { -+ perflvl->volt_min = ret; -+ perflvl->volt_max = ret; -+ } - } - - return 0; -@@ -156,7 +167,7 @@ nouveau_pm_perflvl_get(struct drm_device *dev, struct nouveau_pm_level *perflvl) - static void - nouveau_pm_perflvl_info(struct nouveau_pm_level *perflvl, char *ptr, int len) - { -- char c[16], s[16], v[16], f[16], t[16]; -+ char c[16], s[16], v[32], f[16], t[16], m[16]; - - c[0] = '\0'; - if (perflvl->core) -@@ -166,9 +177,19 @@ nouveau_pm_perflvl_info(struct nouveau_pm_level *perflvl, char *ptr, int len) - if (perflvl->shader) - snprintf(s, sizeof(s), " shader %dMHz", perflvl->shader / 1000); - -+ m[0] = '\0'; -+ if (perflvl->memory) -+ snprintf(m, sizeof(m), " memory %dMHz", perflvl->memory / 1000); -+ - v[0] = '\0'; -- if (perflvl->voltage) -- snprintf(v, sizeof(v), " voltage %dmV", perflvl->voltage * 10); -+ if (perflvl->volt_min && perflvl->volt_min != perflvl->volt_max) { -+ snprintf(v, sizeof(v), " voltage %dmV-%dmV", -+ perflvl->volt_min / 1000, perflvl->volt_max / 1000); -+ } else -+ if (perflvl->volt_min) { -+ snprintf(v, sizeof(v), " voltage %dmV", -+ perflvl->volt_min / 1000); -+ } - - f[0] = '\0'; - if (perflvl->fanspeed) -@@ -178,8 +199,7 @@ nouveau_pm_perflvl_info(struct nouveau_pm_level *perflvl, char *ptr, int len) - if (perflvl->timing) - snprintf(t, sizeof(t), " timing %d", perflvl->timing->id); - -- snprintf(ptr, len, "memory %dMHz%s%s%s%s%s\n", perflvl->memory / 1000, -- c, s, v, f, t); -+ snprintf(ptr, len, "%s%s%s%s%s%s\n", c, s, m, t, v, f); - } - - static ssize_t -@@ -190,7 +210,7 @@ nouveau_pm_get_perflvl_info(struct device *d, - char *ptr = buf; - int len = PAGE_SIZE; - -- snprintf(ptr, len, "%d: ", perflvl->id); -+ snprintf(ptr, len, "%d:", perflvl->id); - ptr += strlen(buf); - len -= strlen(buf); - -@@ -211,9 +231,9 @@ nouveau_pm_get_perflvl(struct device *d, struct device_attribute *a, char *buf) - if (!pm->cur) - snprintf(ptr, len, "setting: boot\n"); - else if (pm->cur == &pm->boot) -- snprintf(ptr, len, "setting: boot\nc: "); -+ snprintf(ptr, len, "setting: boot\nc:"); - else -- snprintf(ptr, len, "setting: static %d\nc: ", pm->cur->id); -+ snprintf(ptr, len, "setting: static %d\nc:", pm->cur->id); - ptr += strlen(buf); - len -= strlen(buf); - -@@ -292,7 +312,7 @@ nouveau_sysfs_fini(struct drm_device *dev) - } - } - --#ifdef CONFIG_HWMON -+#if defined(CONFIG_HWMON) || (defined(MODULE) && defined(CONFIG_HWMON_MODULE)) - static ssize_t - nouveau_hwmon_show_temp(struct device *d, struct device_attribute *a, char *buf) - { -@@ -409,7 +429,7 @@ static const struct attribute_group hwmon_attrgroup = { - static int - nouveau_hwmon_init(struct drm_device *dev) - { --#ifdef CONFIG_HWMON -+#if defined(CONFIG_HWMON) || (defined(MODULE) && defined(CONFIG_HWMON_MODULE)) - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_pm_engine *pm = &dev_priv->engine.pm; - struct device *hwmon_dev; -@@ -442,7 +462,7 @@ nouveau_hwmon_init(struct drm_device *dev) - static void - nouveau_hwmon_fini(struct drm_device *dev) - { --#ifdef CONFIG_HWMON -+#if defined(CONFIG_HWMON) || (defined(MODULE) && defined(CONFIG_HWMON_MODULE)) - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_pm_engine *pm = &dev_priv->engine.pm; - -@@ -488,7 +508,7 @@ nouveau_pm_init(struct drm_device *dev) - NV_INFO(dev, "%d available performance level(s)\n", pm->nr_perflvl); - for (i = 0; i < pm->nr_perflvl; i++) { - nouveau_pm_perflvl_info(&pm->perflvl[i], info, sizeof(info)); -- NV_INFO(dev, "%d: %s", pm->perflvl[i].id, info); -+ NV_INFO(dev, "%d:%s", pm->perflvl[i].id, info); - } - - /* determine current ("boot") performance level */ -@@ -498,7 +518,7 @@ nouveau_pm_init(struct drm_device *dev) - pm->cur = &pm->boot; - - nouveau_pm_perflvl_info(&pm->boot, info, sizeof(info)); -- NV_INFO(dev, "c: %s", info); -+ NV_INFO(dev, "c:%s", info); - } - - /* switch performance levels now if requested */ -diff --git a/drivers/gpu/drm/nouveau/nouveau_pm.h b/drivers/gpu/drm/nouveau/nouveau_pm.h -index 4a9838dd..8ac02cd 100644 ---- a/drivers/gpu/drm/nouveau/nouveau_pm.h -+++ b/drivers/gpu/drm/nouveau/nouveau_pm.h -@@ -52,6 +52,11 @@ void *nv04_pm_clock_pre(struct drm_device *, struct nouveau_pm_level *, - u32 id, int khz); - void nv04_pm_clock_set(struct drm_device *, void *); - -+/* nv40_pm.c */ -+int nv40_pm_clocks_get(struct drm_device *, struct nouveau_pm_level *); -+void *nv40_pm_clocks_pre(struct drm_device *, struct nouveau_pm_level *); -+void nv40_pm_clocks_set(struct drm_device *, void *); -+ - /* nv50_pm.c */ - int nv50_pm_clock_get(struct drm_device *, u32 id); - void *nv50_pm_clock_pre(struct drm_device *, struct nouveau_pm_level *, -@@ -59,10 +64,12 @@ void *nv50_pm_clock_pre(struct drm_device *, struct nouveau_pm_level *, - void nv50_pm_clock_set(struct drm_device *, void *); - - /* nva3_pm.c */ --int nva3_pm_clock_get(struct drm_device *, u32 id); --void *nva3_pm_clock_pre(struct drm_device *, struct nouveau_pm_level *, -- u32 id, int khz); --void nva3_pm_clock_set(struct drm_device *, void *); -+int nva3_pm_clocks_get(struct drm_device *, struct nouveau_pm_level *); -+void *nva3_pm_clocks_pre(struct drm_device *, struct nouveau_pm_level *); -+void nva3_pm_clocks_set(struct drm_device *, void *); -+ -+/* nvc0_pm.c */ -+int nvc0_pm_clocks_get(struct drm_device *, struct nouveau_pm_level *); - - /* nouveau_temp.c */ - void nouveau_temp_init(struct drm_device *dev); -diff --git a/drivers/gpu/drm/nouveau/nouveau_reg.h b/drivers/gpu/drm/nouveau/nouveau_reg.h -index f18cdfc..43a96b9 100644 ---- a/drivers/gpu/drm/nouveau/nouveau_reg.h -+++ b/drivers/gpu/drm/nouveau/nouveau_reg.h -@@ -826,9 +826,12 @@ - #define NV50_PDISPLAY_SOR_DPMS_STATE_ACTIVE 0x00030000 - #define NV50_PDISPLAY_SOR_DPMS_STATE_BLANKED 0x00080000 - #define NV50_PDISPLAY_SOR_DPMS_STATE_WAIT 0x10000000 --#define NV50_PDISPLAY_SOR_BACKLIGHT 0x0061c084 --#define NV50_PDISPLAY_SOR_BACKLIGHT_ENABLE 0x80000000 --#define NV50_PDISPLAY_SOR_BACKLIGHT_LEVEL 0x00000fff -+#define NV50_PDISP_SOR_PWM_DIV(i) (0x0061c080 + (i) * 0x800) -+#define NV50_PDISP_SOR_PWM_CTL(i) (0x0061c084 + (i) * 0x800) -+#define NV50_PDISP_SOR_PWM_CTL_NEW 0x80000000 -+#define NVA3_PDISP_SOR_PWM_CTL_UNK 0x40000000 -+#define NV50_PDISP_SOR_PWM_CTL_VAL 0x000007ff -+#define NVA3_PDISP_SOR_PWM_CTL_VAL 0x00ffffff - #define NV50_SOR_DP_CTRL(i, l) (0x0061c10c + (i) * 0x800 + (l) * 0x80) - #define NV50_SOR_DP_CTRL_ENABLED 0x00000001 - #define NV50_SOR_DP_CTRL_ENHANCED_FRAME_ENABLED 0x00004000 -@@ -843,7 +846,7 @@ - #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_UNK120(i, l) (0x0061c120 + (i) * 0x800 + (l) * 0x80) --#define NV50_SOR_DP_UNK128(i, l) (0x0061c128 + (i) * 0x800 + (l) * 0x80) -+#define NV50_SOR_DP_SCFG(i, l) (0x0061c128 + (i) * 0x800 + (l) * 0x80) - #define NV50_SOR_DP_UNK130(i, l) (0x0061c130 + (i) * 0x800 + (l) * 0x80) - - #define NV50_PDISPLAY_USER(i) ((i) * 0x1000 + 0x00640000) -diff --git a/drivers/gpu/drm/nouveau/nouveau_sgdma.c b/drivers/gpu/drm/nouveau/nouveau_sgdma.c -index 2706cb3..b75258a 100644 ---- a/drivers/gpu/drm/nouveau/nouveau_sgdma.c -+++ b/drivers/gpu/drm/nouveau/nouveau_sgdma.c -@@ -12,8 +12,8 @@ struct nouveau_sgdma_be { - struct drm_device *dev; - - dma_addr_t *pages; -- bool *ttm_alloced; - unsigned nr_pages; -+ bool unmap_pages; - - u64 offset; - bool bound; -@@ -26,43 +26,28 @@ nouveau_sgdma_populate(struct ttm_backend *be, unsigned long num_pages, - { - struct nouveau_sgdma_be *nvbe = (struct nouveau_sgdma_be *)be; - struct drm_device *dev = nvbe->dev; -+ int i; - - NV_DEBUG(nvbe->dev, "num_pages = %ld\n", num_pages); - -- if (nvbe->pages) -- return -EINVAL; -- -- nvbe->pages = kmalloc(sizeof(dma_addr_t) * num_pages, GFP_KERNEL); -- if (!nvbe->pages) -- return -ENOMEM; -+ nvbe->pages = dma_addrs; -+ nvbe->nr_pages = num_pages; -+ nvbe->unmap_pages = true; - -- nvbe->ttm_alloced = kmalloc(sizeof(bool) * num_pages, GFP_KERNEL); -- if (!nvbe->ttm_alloced) { -- kfree(nvbe->pages); -- nvbe->pages = NULL; -- return -ENOMEM; -+ /* this code path isn't called and is incorrect anyways */ -+ if (0) { /* dma_addrs[0] != DMA_ERROR_CODE) { */ -+ nvbe->unmap_pages = false; -+ return 0; - } - -- nvbe->nr_pages = 0; -- while (num_pages--) { -- /* this code path isn't called and is incorrect anyways */ -- if (0) { /*dma_addrs[nvbe->nr_pages] != DMA_ERROR_CODE)*/ -- nvbe->pages[nvbe->nr_pages] = -- dma_addrs[nvbe->nr_pages]; -- nvbe->ttm_alloced[nvbe->nr_pages] = true; -- } else { -- nvbe->pages[nvbe->nr_pages] = -- pci_map_page(dev->pdev, pages[nvbe->nr_pages], 0, -- PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); -- if (pci_dma_mapping_error(dev->pdev, -- nvbe->pages[nvbe->nr_pages])) { -- be->func->clear(be); -- return -EFAULT; -- } -- nvbe->ttm_alloced[nvbe->nr_pages] = false; -+ for (i = 0; i < num_pages; i++) { -+ nvbe->pages[i] = pci_map_page(dev->pdev, pages[i], 0, -+ PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); -+ if (pci_dma_mapping_error(dev->pdev, nvbe->pages[i])) { -+ nvbe->nr_pages = --i; -+ be->func->clear(be); -+ return -EFAULT; - } -- -- nvbe->nr_pages++; - } - - return 0; -@@ -72,25 +57,16 @@ static void - nouveau_sgdma_clear(struct ttm_backend *be) - { - struct nouveau_sgdma_be *nvbe = (struct nouveau_sgdma_be *)be; -- struct drm_device *dev; -- -- if (nvbe && nvbe->pages) { -- dev = nvbe->dev; -- NV_DEBUG(dev, "\n"); -+ struct drm_device *dev = nvbe->dev; - -- if (nvbe->bound) -- be->func->unbind(be); -+ if (nvbe->bound) -+ be->func->unbind(be); - -+ if (nvbe->unmap_pages) { - while (nvbe->nr_pages--) { -- if (!nvbe->ttm_alloced[nvbe->nr_pages]) -- pci_unmap_page(dev->pdev, nvbe->pages[nvbe->nr_pages], -+ pci_unmap_page(dev->pdev, nvbe->pages[nvbe->nr_pages], - PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); - } -- kfree(nvbe->pages); -- kfree(nvbe->ttm_alloced); -- nvbe->pages = NULL; -- nvbe->ttm_alloced = NULL; -- nvbe->nr_pages = 0; - } - } - -diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c -index 10656e4..82478e0 100644 ---- a/drivers/gpu/drm/nouveau/nouveau_state.c -+++ b/drivers/gpu/drm/nouveau/nouveau_state.c -@@ -286,9 +286,9 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) - engine->gpio.get = nv10_gpio_get; - engine->gpio.set = nv10_gpio_set; - engine->gpio.irq_enable = NULL; -- engine->pm.clock_get = nv04_pm_clock_get; -- engine->pm.clock_pre = nv04_pm_clock_pre; -- engine->pm.clock_set = nv04_pm_clock_set; -+ engine->pm.clocks_get = nv40_pm_clocks_get; -+ engine->pm.clocks_pre = nv40_pm_clocks_pre; -+ engine->pm.clocks_set = nv40_pm_clocks_set; - engine->pm.voltage_get = nouveau_voltage_gpio_get; - engine->pm.voltage_set = nouveau_voltage_gpio_set; - engine->pm.temp_get = nv40_temp_get; -@@ -299,7 +299,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) - case 0x50: - case 0x80: /* gotta love NVIDIA's consistency.. */ - case 0x90: -- case 0xA0: -+ case 0xa0: - engine->instmem.init = nv50_instmem_init; - engine->instmem.takedown = nv50_instmem_takedown; - engine->instmem.suspend = nv50_instmem_suspend; -@@ -359,9 +359,9 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) - engine->pm.clock_set = nv50_pm_clock_set; - break; - default: -- engine->pm.clock_get = nva3_pm_clock_get; -- engine->pm.clock_pre = nva3_pm_clock_pre; -- engine->pm.clock_set = nva3_pm_clock_set; -+ engine->pm.clocks_get = nva3_pm_clocks_get; -+ engine->pm.clocks_pre = nva3_pm_clocks_pre; -+ engine->pm.clocks_set = nva3_pm_clocks_set; - break; - } - engine->pm.voltage_get = nouveau_voltage_gpio_get; -@@ -376,7 +376,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) - engine->vram.put = nv50_vram_del; - engine->vram.flags_valid = nv50_vram_flags_valid; - break; -- case 0xC0: -+ case 0xc0: - engine->instmem.init = nvc0_instmem_init; - engine->instmem.takedown = nvc0_instmem_takedown; - engine->instmem.suspend = nvc0_instmem_suspend; -@@ -422,12 +422,73 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) - engine->vram.put = nv50_vram_del; - engine->vram.flags_valid = nvc0_vram_flags_valid; - engine->pm.temp_get = nv84_temp_get; -+ engine->pm.clocks_get = nvc0_pm_clocks_get; -+ engine->pm.voltage_get = nouveau_voltage_gpio_get; -+ engine->pm.voltage_set = nouveau_voltage_gpio_set; -+ break; -+ case 0xd0: -+ 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.get = nv50_instmem_get; -+ engine->instmem.put = nv50_instmem_put; -+ engine->instmem.map = nv50_instmem_map; -+ engine->instmem.unmap = nv50_instmem_unmap; -+ engine->instmem.flush = nv84_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->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 = nouveau_stub_init; -+ engine->display.late_takedown = nouveau_stub_takedown; -+ engine->display.create = nvd0_display_create; -+ engine->display.init = nvd0_display_init; -+ engine->display.destroy = nvd0_display_destroy; -+ engine->gpio.init = nv50_gpio_init; -+ engine->gpio.takedown = nouveau_stub_takedown; -+ engine->gpio.get = nvd0_gpio_get; -+ engine->gpio.set = nvd0_gpio_set; -+ engine->gpio.irq_register = nv50_gpio_irq_register; -+ engine->gpio.irq_unregister = nv50_gpio_irq_unregister; -+ engine->gpio.irq_enable = nv50_gpio_irq_enable; -+ engine->vram.init = nvc0_vram_init; -+ engine->vram.takedown = nv50_vram_fini; -+ engine->vram.get = nvc0_vram_new; -+ engine->vram.put = nv50_vram_del; -+ engine->vram.flags_valid = nvc0_vram_flags_valid; -+ engine->pm.clocks_get = nvc0_pm_clocks_get; -+ engine->pm.voltage_get = nouveau_voltage_gpio_get; -+ engine->pm.voltage_set = nouveau_voltage_gpio_set; - break; - default: - NV_ERROR(dev, "NV%02x unsupported\n", dev_priv->chipset); - return 1; - } - -+ /* headless mode */ -+ if (nouveau_modeset == 2) { -+ engine->display.early_init = nouveau_stub_init; -+ engine->display.late_takedown = nouveau_stub_takedown; -+ engine->display.create = nouveau_stub_init; -+ engine->display.init = nouveau_stub_init; -+ engine->display.destroy = nouveau_stub_takedown; -+ } -+ - return 0; - } - -@@ -449,21 +510,6 @@ nouveau_vga_set_decode(void *priv, bool state) - return VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM; - } - --static int --nouveau_card_init_channel(struct drm_device *dev) --{ -- struct drm_nouveau_private *dev_priv = dev->dev_private; -- int ret; -- -- ret = nouveau_channel_alloc(dev, &dev_priv->channel, NULL, -- NvDmaFB, NvDmaTT); -- if (ret) -- return ret; -- -- mutex_unlock(&dev_priv->channel->mutex); -- return 0; --} -- - static void nouveau_switcheroo_set_state(struct pci_dev *pdev, - enum vga_switcheroo_state state) - { -@@ -630,8 +676,11 @@ nouveau_card_init(struct drm_device *dev) - break; - } - -- if (dev_priv->card_type == NV_40) -- nv40_mpeg_create(dev); -+ if (dev_priv->card_type == NV_40 || -+ dev_priv->chipset == 0x31 || -+ dev_priv->chipset == 0x34 || -+ dev_priv->chipset == 0x36) -+ nv31_mpeg_create(dev); - else - if (dev_priv->card_type == NV_50 && - (dev_priv->chipset < 0x98 || dev_priv->chipset == 0xa0)) -@@ -651,41 +700,69 @@ nouveau_card_init(struct drm_device *dev) - goto out_engine; - } - -- ret = engine->display.create(dev); -+ ret = nouveau_irq_init(dev); - if (ret) - goto out_fifo; - -- ret = drm_vblank_init(dev, nv_two_heads(dev) ? 2 : 1); -- if (ret) -- goto out_vblank; -+ /* initialise general modesetting */ -+ drm_mode_config_init(dev); -+ drm_mode_create_scaling_mode_property(dev); -+ drm_mode_create_dithering_property(dev); -+ dev->mode_config.funcs = (void *)&nouveau_mode_config_funcs; -+ dev->mode_config.fb_base = pci_resource_start(dev->pdev, 1); -+ dev->mode_config.min_width = 0; -+ dev->mode_config.min_height = 0; -+ if (dev_priv->card_type < NV_10) { -+ dev->mode_config.max_width = 2048; -+ dev->mode_config.max_height = 2048; -+ } else -+ if (dev_priv->card_type < NV_50) { -+ dev->mode_config.max_width = 4096; -+ dev->mode_config.max_height = 4096; -+ } else { -+ dev->mode_config.max_width = 8192; -+ dev->mode_config.max_height = 8192; -+ } - -- ret = nouveau_irq_init(dev); -+ ret = engine->display.create(dev); - if (ret) -- goto out_vblank; -+ goto out_irq; - -- /* what about PVIDEO/PCRTC/PRAMDAC etc? */ -+ nouveau_backlight_init(dev); - - if (dev_priv->eng[NVOBJ_ENGINE_GR]) { - ret = nouveau_fence_init(dev); - if (ret) -- goto out_irq; -+ goto out_disp; - -- ret = nouveau_card_init_channel(dev); -+ ret = nouveau_channel_alloc(dev, &dev_priv->channel, NULL, -+ NvDmaFB, NvDmaTT); - if (ret) - goto out_fence; -+ -+ mutex_unlock(&dev_priv->channel->mutex); -+ } -+ -+ if (dev->mode_config.num_crtc) { -+ ret = drm_vblank_init(dev, dev->mode_config.num_crtc); -+ if (ret) -+ goto out_chan; -+ -+ nouveau_fbcon_init(dev); -+ drm_kms_helper_poll_init(dev); - } - -- nouveau_fbcon_init(dev); -- drm_kms_helper_poll_init(dev); - return 0; - -+out_chan: -+ nouveau_channel_put_unlocked(&dev_priv->channel); - out_fence: - nouveau_fence_fini(dev); -+out_disp: -+ nouveau_backlight_exit(dev); -+ engine->display.destroy(dev); - out_irq: - nouveau_irq_fini(dev); --out_vblank: -- drm_vblank_cleanup(dev); -- engine->display.destroy(dev); - out_fifo: - if (!dev_priv->noaccel) - engine->fifo.takedown(dev); -@@ -732,15 +809,20 @@ static void nouveau_card_takedown(struct drm_device *dev) - struct nouveau_engine *engine = &dev_priv->engine; - int e; - -- drm_kms_helper_poll_fini(dev); -- nouveau_fbcon_fini(dev); -+ if (dev->mode_config.num_crtc) { -+ drm_kms_helper_poll_fini(dev); -+ nouveau_fbcon_fini(dev); -+ drm_vblank_cleanup(dev); -+ } - - if (dev_priv->channel) { - nouveau_channel_put_unlocked(&dev_priv->channel); - nouveau_fence_fini(dev); - } - -+ nouveau_backlight_exit(dev); - engine->display.destroy(dev); -+ drm_mode_config_cleanup(dev); - - if (!dev_priv->noaccel) { - engine->fifo.takedown(dev); -@@ -774,7 +856,6 @@ static void nouveau_card_takedown(struct drm_device *dev) - engine->vram.takedown(dev); - - nouveau_irq_fini(dev); -- drm_vblank_cleanup(dev); - - nouveau_pm_fini(dev); - nouveau_bios_takedown(dev); -@@ -907,7 +988,7 @@ static int nouveau_remove_conflicting_drivers(struct drm_device *dev) - int nouveau_load(struct drm_device *dev, unsigned long flags) - { - struct drm_nouveau_private *dev_priv; -- uint32_t reg0; -+ uint32_t reg0, strap; - resource_size_t mmio_start_offs; - int ret; - -@@ -951,13 +1032,11 @@ int nouveau_load(struct drm_device *dev, unsigned long flags) - - /* Time to determine the card architecture */ - reg0 = nv_rd32(dev, NV03_PMC_BOOT_0); -- dev_priv->stepping = 0; /* XXX: add stepping for pre-NV10? */ - - /* We're dealing with >=NV10 */ - if ((reg0 & 0x0f000000) > 0) { - /* Bit 27-20 contain the architecture in hex */ - dev_priv->chipset = (reg0 & 0xff00000) >> 20; -- dev_priv->stepping = (reg0 & 0xff); - /* NV04 or NV05 */ - } else if ((reg0 & 0xff00fff0) == 0x20004000) { - if (reg0 & 0x00f00000) -@@ -987,6 +1066,9 @@ int nouveau_load(struct drm_device *dev, unsigned long flags) - case 0xc0: - dev_priv->card_type = NV_C0; - break; -+ case 0xd0: -+ dev_priv->card_type = NV_D0; -+ break; - default: - NV_INFO(dev, "Unsupported chipset 0x%08x\n", reg0); - ret = -EINVAL; -@@ -996,6 +1078,23 @@ int nouveau_load(struct drm_device *dev, unsigned long flags) - NV_INFO(dev, "Detected an NV%2x generation card (0x%08x)\n", - dev_priv->card_type, reg0); - -+ /* determine frequency of timing crystal */ -+ strap = nv_rd32(dev, 0x101000); -+ if ( dev_priv->chipset < 0x17 || -+ (dev_priv->chipset >= 0x20 && dev_priv->chipset <= 0x25)) -+ strap &= 0x00000040; -+ else -+ strap &= 0x00400040; -+ -+ switch (strap) { -+ case 0x00000000: dev_priv->crystal = 13500; break; -+ case 0x00000040: dev_priv->crystal = 14318; break; -+ case 0x00400000: dev_priv->crystal = 27000; break; -+ case 0x00400040: dev_priv->crystal = 25000; break; -+ } -+ -+ NV_DEBUG(dev, "crystal freq: %dKHz\n", dev_priv->crystal); -+ - /* Determine whether we'll attempt acceleration or not, some - * cards are disabled by default here due to them being known - * non-functional, or never been tested due to lack of hw. -@@ -1030,7 +1129,7 @@ int nouveau_load(struct drm_device *dev, unsigned long flags) - ioremap(pci_resource_start(dev->pdev, ramin_bar), - dev_priv->ramin_size); - if (!dev_priv->ramin) { -- NV_ERROR(dev, "Failed to PRAMIN BAR"); -+ NV_ERROR(dev, "Failed to map PRAMIN BAR\n"); - ret = -ENOMEM; - goto err_mmio; - } -@@ -1130,7 +1229,7 @@ int nouveau_ioctl_getparam(struct drm_device *dev, void *data, - getparam->value = 1; - break; - case NOUVEAU_GETPARAM_HAS_PAGEFLIP: -- getparam->value = 1; -+ getparam->value = dev_priv->card_type < NV_D0; - break; - case NOUVEAU_GETPARAM_GRAPH_UNITS: - /* NV40 and NV50 versions are quite different, but register -@@ -1198,6 +1297,23 @@ nouveau_wait_ne(struct drm_device *dev, uint64_t timeout, - return false; - } - -+/* Wait until cond(data) == true, up until timeout has hit */ -+bool -+nouveau_wait_cb(struct drm_device *dev, u64 timeout, -+ bool (*cond)(void *), void *data) -+{ -+ struct drm_nouveau_private *dev_priv = dev->dev_private; -+ struct nouveau_timer_engine *ptimer = &dev_priv->engine.timer; -+ u64 start = ptimer->read(dev); -+ -+ do { -+ if (cond(data) == true) -+ return true; -+ } while (ptimer->read(dev) - start < timeout); -+ -+ return false; -+} -+ - /* Waits for PGRAPH to go completely idle */ - bool nouveau_wait_for_idle(struct drm_device *dev) - { -diff --git a/drivers/gpu/drm/nouveau/nouveau_vm.c b/drivers/gpu/drm/nouveau/nouveau_vm.c -index 244fd38..ef0832b 100644 ---- a/drivers/gpu/drm/nouveau/nouveau_vm.c -+++ b/drivers/gpu/drm/nouveau/nouveau_vm.c -@@ -172,9 +172,9 @@ nouveau_vm_unmap_pgt(struct nouveau_vm *vm, int big, u32 fpde, u32 lpde) - vm->map_pgt(vpgd->obj, pde, vpgt->obj); - } - -- mutex_unlock(&vm->mm->mutex); -+ mutex_unlock(&vm->mm.mutex); - nouveau_gpuobj_ref(NULL, &pgt); -- mutex_lock(&vm->mm->mutex); -+ mutex_lock(&vm->mm.mutex); - } - } - -@@ -191,18 +191,18 @@ nouveau_vm_map_pgt(struct nouveau_vm *vm, u32 pde, u32 type) - pgt_size = (1 << (vm->pgt_bits + 12)) >> type; - pgt_size *= 8; - -- mutex_unlock(&vm->mm->mutex); -+ mutex_unlock(&vm->mm.mutex); - ret = nouveau_gpuobj_new(vm->dev, NULL, pgt_size, 0x1000, - NVOBJ_FLAG_ZERO_ALLOC, &pgt); -- mutex_lock(&vm->mm->mutex); -+ mutex_lock(&vm->mm.mutex); - if (unlikely(ret)) - return ret; - - /* someone beat us to filling the PDE while we didn't have the lock */ - if (unlikely(vpgt->refcount[big]++)) { -- mutex_unlock(&vm->mm->mutex); -+ mutex_unlock(&vm->mm.mutex); - nouveau_gpuobj_ref(NULL, &pgt); -- mutex_lock(&vm->mm->mutex); -+ mutex_lock(&vm->mm.mutex); - return 0; - } - -@@ -223,10 +223,10 @@ nouveau_vm_get(struct nouveau_vm *vm, u64 size, u32 page_shift, - u32 fpde, lpde, pde; - int ret; - -- mutex_lock(&vm->mm->mutex); -- ret = nouveau_mm_get(vm->mm, page_shift, msize, 0, align, &vma->node); -+ mutex_lock(&vm->mm.mutex); -+ ret = nouveau_mm_get(&vm->mm, page_shift, msize, 0, align, &vma->node); - if (unlikely(ret != 0)) { -- mutex_unlock(&vm->mm->mutex); -+ mutex_unlock(&vm->mm.mutex); - return ret; - } - -@@ -245,13 +245,13 @@ nouveau_vm_get(struct nouveau_vm *vm, u64 size, u32 page_shift, - if (ret) { - if (pde != fpde) - nouveau_vm_unmap_pgt(vm, big, fpde, pde - 1); -- nouveau_mm_put(vm->mm, vma->node); -- mutex_unlock(&vm->mm->mutex); -+ nouveau_mm_put(&vm->mm, vma->node); -+ mutex_unlock(&vm->mm.mutex); - vma->node = NULL; - return ret; - } - } -- mutex_unlock(&vm->mm->mutex); -+ mutex_unlock(&vm->mm.mutex); - - vma->vm = vm; - vma->offset = (u64)vma->node->offset << 12; -@@ -270,11 +270,11 @@ nouveau_vm_put(struct nouveau_vma *vma) - fpde = (vma->node->offset >> vm->pgt_bits); - lpde = (vma->node->offset + vma->node->length - 1) >> vm->pgt_bits; - -- mutex_lock(&vm->mm->mutex); -+ mutex_lock(&vm->mm.mutex); - nouveau_vm_unmap_pgt(vm, vma->node->type != vm->spg_shift, fpde, lpde); -- nouveau_mm_put(vm->mm, vma->node); -+ nouveau_mm_put(&vm->mm, vma->node); - vma->node = NULL; -- mutex_unlock(&vm->mm->mutex); -+ mutex_unlock(&vm->mm.mutex); - } - - int -@@ -306,7 +306,7 @@ nouveau_vm_new(struct drm_device *dev, u64 offset, u64 length, u64 mm_offset, - block = length; - - } else -- if (dev_priv->card_type == NV_C0) { -+ if (dev_priv->card_type >= NV_C0) { - vm->map_pgt = nvc0_vm_map_pgt; - vm->map = nvc0_vm_map; - vm->map_sg = nvc0_vm_map_sg; -@@ -360,11 +360,11 @@ nouveau_vm_link(struct nouveau_vm *vm, struct nouveau_gpuobj *pgd) - - nouveau_gpuobj_ref(pgd, &vpgd->obj); - -- mutex_lock(&vm->mm->mutex); -+ mutex_lock(&vm->mm.mutex); - for (i = vm->fpde; i <= vm->lpde; i++) - vm->map_pgt(pgd, i, vm->pgt[i - vm->fpde].obj); - list_add(&vpgd->head, &vm->pgd_list); -- mutex_unlock(&vm->mm->mutex); -+ mutex_unlock(&vm->mm.mutex); - return 0; - } - -@@ -377,7 +377,7 @@ nouveau_vm_unlink(struct nouveau_vm *vm, struct nouveau_gpuobj *mpgd) - if (!mpgd) - return; - -- mutex_lock(&vm->mm->mutex); -+ mutex_lock(&vm->mm.mutex); - list_for_each_entry_safe(vpgd, tmp, &vm->pgd_list, head) { - if (vpgd->obj == mpgd) { - pgd = vpgd->obj; -@@ -386,7 +386,7 @@ nouveau_vm_unlink(struct nouveau_vm *vm, struct nouveau_gpuobj *mpgd) - break; - } - } -- mutex_unlock(&vm->mm->mutex); -+ mutex_unlock(&vm->mm.mutex); - - nouveau_gpuobj_ref(NULL, &pgd); - } -diff --git a/drivers/gpu/drm/nouveau/nouveau_vm.h b/drivers/gpu/drm/nouveau/nouveau_vm.h -index 579ca8c..6ce995f 100644 ---- a/drivers/gpu/drm/nouveau/nouveau_vm.h -+++ b/drivers/gpu/drm/nouveau/nouveau_vm.h -@@ -51,7 +51,7 @@ struct nouveau_vma { - - struct nouveau_vm { - struct drm_device *dev; -- struct nouveau_mm *mm; -+ struct nouveau_mm mm; - int refcount; - - struct list_head pgd_list; -diff --git a/drivers/gpu/drm/nouveau/nouveau_volt.c b/drivers/gpu/drm/nouveau/nouveau_volt.c -index 75e87274..86d03e1 100644 ---- a/drivers/gpu/drm/nouveau/nouveau_volt.c -+++ b/drivers/gpu/drm/nouveau/nouveau_volt.c -@@ -27,7 +27,7 @@ - #include "nouveau_drv.h" - #include "nouveau_pm.h" - --static const enum dcb_gpio_tag vidtag[] = { 0x04, 0x05, 0x06, 0x1a }; -+static const enum dcb_gpio_tag vidtag[] = { 0x04, 0x05, 0x06, 0x1a, 0x73 }; - static int nr_vidtag = sizeof(vidtag) / sizeof(vidtag[0]); - - int -@@ -170,6 +170,13 @@ nouveau_volt_init(struct drm_device *dev) - */ - vidshift = 2; - break; -+ case 0x40: -+ headerlen = volt[1]; -+ recordlen = volt[2]; -+ entries = volt[3]; /* not a clue what the entries are for.. */ -+ vidmask = volt[11]; /* guess.. */ -+ vidshift = 0; -+ break; - default: - NV_WARN(dev, "voltage table 0x%02x unknown\n", volt[0]); - return; -@@ -197,16 +204,37 @@ nouveau_volt_init(struct drm_device *dev) - } - - /* parse vbios entries into common format */ -- voltage->level = kcalloc(entries, sizeof(*voltage->level), GFP_KERNEL); -- if (!voltage->level) -- return; -+ voltage->version = volt[0]; -+ if (voltage->version < 0x40) { -+ voltage->nr_level = entries; -+ voltage->level = -+ kcalloc(entries, sizeof(*voltage->level), GFP_KERNEL); -+ if (!voltage->level) -+ return; - -- entry = volt + headerlen; -- for (i = 0; i < entries; i++, entry += recordlen) { -- voltage->level[i].voltage = entry[0]; -- voltage->level[i].vid = entry[1] >> vidshift; -+ entry = volt + headerlen; -+ for (i = 0; i < entries; i++, entry += recordlen) { -+ voltage->level[i].voltage = entry[0] * 10000; -+ voltage->level[i].vid = entry[1] >> vidshift; -+ } -+ } else { -+ u32 volt_uv = ROM32(volt[4]); -+ s16 step_uv = ROM16(volt[8]); -+ u8 vid; -+ -+ voltage->nr_level = voltage->vid_mask + 1; -+ voltage->level = kcalloc(voltage->nr_level, -+ sizeof(*voltage->level), GFP_KERNEL); -+ if (!voltage->level) -+ return; -+ -+ for (vid = 0; vid <= voltage->vid_mask; vid++) { -+ voltage->level[vid].voltage = volt_uv; -+ voltage->level[vid].vid = vid; -+ volt_uv += step_uv; -+ } - } -- voltage->nr_level = entries; -+ - voltage->supported = true; - } - -diff --git a/drivers/gpu/drm/nouveau/nv04_display.c b/drivers/gpu/drm/nouveau/nv04_display.c -index 1715e14..6bd8518 100644 ---- a/drivers/gpu/drm/nouveau/nv04_display.c -+++ b/drivers/gpu/drm/nouveau/nv04_display.c -@@ -126,27 +126,6 @@ nv04_display_create(struct drm_device *dev) - - nouveau_hw_save_vga_fonts(dev, 1); - -- drm_mode_config_init(dev); -- drm_mode_create_scaling_mode_property(dev); -- drm_mode_create_dithering_property(dev); -- -- dev->mode_config.funcs = (void *)&nouveau_mode_config_funcs; -- -- dev->mode_config.min_width = 0; -- dev->mode_config.min_height = 0; -- switch (dev_priv->card_type) { -- case NV_04: -- dev->mode_config.max_width = 2048; -- dev->mode_config.max_height = 2048; -- break; -- default: -- dev->mode_config.max_width = 4096; -- dev->mode_config.max_height = 4096; -- break; -- } -- -- dev->mode_config.fb_base = dev_priv->fb_phys; -- - nv04_crtc_create(dev, 0); - if (nv_two_heads(dev)) - nv04_crtc_create(dev, 1); -@@ -235,8 +214,6 @@ nv04_display_destroy(struct drm_device *dev) - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) - crtc->funcs->restore(crtc); - -- drm_mode_config_cleanup(dev); -- - nouveau_hw_save_vga_fonts(dev, 0); - } - -diff --git a/drivers/gpu/drm/nouveau/nv04_pm.c b/drivers/gpu/drm/nouveau/nv04_pm.c -index eb1c70d..9ae92a8 100644 ---- a/drivers/gpu/drm/nouveau/nv04_pm.c -+++ b/drivers/gpu/drm/nouveau/nv04_pm.c -@@ -68,6 +68,7 @@ void - nv04_pm_clock_set(struct drm_device *dev, void *pre_state) - { - struct drm_nouveau_private *dev_priv = dev->dev_private; -+ struct nouveau_timer_engine *ptimer = &dev_priv->engine.timer; - struct nv04_pm_state *state = pre_state; - u32 reg = state->pll.reg; - -@@ -85,6 +86,9 @@ nv04_pm_clock_set(struct drm_device *dev, void *pre_state) - nv_mask(dev, 0x1002c0, 0, 1 << 8); - } - -+ if (reg == NV_PRAMDAC_NVPLL_COEFF) -+ ptimer->init(dev); -+ - kfree(state); - } - -diff --git a/drivers/gpu/drm/nouveau/nv04_timer.c b/drivers/gpu/drm/nouveau/nv04_timer.c -index 1d09ddd..263301b 100644 ---- a/drivers/gpu/drm/nouveau/nv04_timer.c -+++ b/drivers/gpu/drm/nouveau/nv04_timer.c -@@ -6,43 +6,75 @@ - int - nv04_timer_init(struct drm_device *dev) - { -+ struct drm_nouveau_private *dev_priv = dev->dev_private; -+ u32 m, n, d; -+ - nv_wr32(dev, NV04_PTIMER_INTR_EN_0, 0x00000000); - nv_wr32(dev, NV04_PTIMER_INTR_0, 0xFFFFFFFF); - -- /* Just use the pre-existing values when possible for now; these regs -- * are not written in nv (driver writer missed a /4 on the address), and -- * writing 8 and 3 to the correct regs breaks the timings on the LVDS -- * hardware sequencing microcode. -- * A correct solution (involving calculations with the GPU PLL) can -- * be done when kernel modesetting lands -- */ -- if (!nv_rd32(dev, NV04_PTIMER_NUMERATOR) || -- !nv_rd32(dev, NV04_PTIMER_DENOMINATOR)) { -- nv_wr32(dev, NV04_PTIMER_NUMERATOR, 0x00000008); -- nv_wr32(dev, NV04_PTIMER_DENOMINATOR, 0x00000003); -+ /* aim for 31.25MHz, which gives us nanosecond timestamps */ -+ d = 1000000 / 32; -+ -+ /* determine base clock for timer source */ -+ if (dev_priv->chipset < 0x40) { -+ n = dev_priv->engine.pm.clock_get(dev, PLL_CORE); -+ } else -+ if (dev_priv->chipset == 0x40) { -+ /*XXX: figure this out */ -+ n = 0; -+ } else { -+ n = dev_priv->crystal; -+ m = 1; -+ while (n < (d * 2)) { -+ n += (n / m); -+ m++; -+ } -+ -+ nv_wr32(dev, 0x009220, m - 1); -+ } -+ -+ if (!n) { -+ NV_WARN(dev, "PTIMER: unknown input clock freq\n"); -+ if (!nv_rd32(dev, NV04_PTIMER_NUMERATOR) || -+ !nv_rd32(dev, NV04_PTIMER_DENOMINATOR)) { -+ nv_wr32(dev, NV04_PTIMER_NUMERATOR, 1); -+ nv_wr32(dev, NV04_PTIMER_DENOMINATOR, 1); -+ } -+ return 0; -+ } -+ -+ /* reduce ratio to acceptable values */ -+ while (((n % 5) == 0) && ((d % 5) == 0)) { -+ n /= 5; -+ d /= 5; - } - -+ while (((n % 2) == 0) && ((d % 2) == 0)) { -+ n /= 2; -+ d /= 2; -+ } -+ -+ while (n > 0xffff || d > 0xffff) { -+ n >>= 1; -+ d >>= 1; -+ } -+ -+ nv_wr32(dev, NV04_PTIMER_NUMERATOR, n); -+ nv_wr32(dev, NV04_PTIMER_DENOMINATOR, d); - return 0; - } - --uint64_t -+u64 - nv04_timer_read(struct drm_device *dev) - { -- uint32_t low; -- /* From kmmio dumps on nv28 this looks like how the blob does this. -- * It reads the high dword twice, before and after. -- * The only explanation seems to be that the 64-bit timer counter -- * advances between high and low dword reads and may corrupt the -- * result. Not confirmed. -- */ -- uint32_t high2 = nv_rd32(dev, NV04_PTIMER_TIME_1); -- uint32_t high1; -+ u32 hi, lo; -+ - do { -- high1 = high2; -- low = nv_rd32(dev, NV04_PTIMER_TIME_0); -- high2 = nv_rd32(dev, NV04_PTIMER_TIME_1); -- } while (high1 != high2); -- return (((uint64_t)high2) << 32) | (uint64_t)low; -+ hi = nv_rd32(dev, NV04_PTIMER_TIME_1); -+ lo = nv_rd32(dev, NV04_PTIMER_TIME_0); -+ } while (hi != nv_rd32(dev, NV04_PTIMER_TIME_1)); -+ -+ return ((u64)hi << 32 | lo); - } - - void -diff --git a/drivers/gpu/drm/nouveau/nv31_mpeg.c b/drivers/gpu/drm/nouveau/nv31_mpeg.c -new file mode 100644 -index 0000000..6f06a07 ---- /dev/null -+++ b/drivers/gpu/drm/nouveau/nv31_mpeg.c -@@ -0,0 +1,344 @@ -+/* -+ * Copyright 2011 Red Hat Inc. -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a -+ * copy of this software and associated documentation files (the "Software"), -+ * to deal in the Software without restriction, including without limitation -+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, -+ * and/or sell copies of the Software, and to permit persons to whom the -+ * Software is furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR -+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -+ * OTHER DEALINGS IN THE SOFTWARE. -+ * -+ * Authors: Ben Skeggs -+ */ -+ -+#include "drmP.h" -+#include "nouveau_drv.h" -+#include "nouveau_ramht.h" -+ -+struct nv31_mpeg_engine { -+ struct nouveau_exec_engine base; -+ atomic_t refcount; -+}; -+ -+ -+static int -+nv31_mpeg_context_new(struct nouveau_channel *chan, int engine) -+{ -+ struct nv31_mpeg_engine *pmpeg = nv_engine(chan->dev, engine); -+ -+ if (!atomic_add_unless(&pmpeg->refcount, 1, 1)) -+ return -EBUSY; -+ -+ chan->engctx[engine] = (void *)0xdeadcafe; -+ return 0; -+} -+ -+static void -+nv31_mpeg_context_del(struct nouveau_channel *chan, int engine) -+{ -+ struct nv31_mpeg_engine *pmpeg = nv_engine(chan->dev, engine); -+ atomic_dec(&pmpeg->refcount); -+ chan->engctx[engine] = NULL; -+} -+ -+static int -+nv40_mpeg_context_new(struct nouveau_channel *chan, int engine) -+{ -+ struct drm_device *dev = chan->dev; -+ struct drm_nouveau_private *dev_priv = dev->dev_private; -+ struct nouveau_gpuobj *ctx = NULL; -+ unsigned long flags; -+ int ret; -+ -+ NV_DEBUG(dev, "ch%d\n", chan->id); -+ -+ ret = nouveau_gpuobj_new(dev, NULL, 264 * 4, 16, NVOBJ_FLAG_ZERO_ALLOC | -+ NVOBJ_FLAG_ZERO_FREE, &ctx); -+ if (ret) -+ return ret; -+ -+ nv_wo32(ctx, 0x78, 0x02001ec1); -+ -+ spin_lock_irqsave(&dev_priv->context_switch_lock, flags); -+ nv_mask(dev, 0x002500, 0x00000001, 0x00000000); -+ if ((nv_rd32(dev, 0x003204) & 0x1f) == chan->id) -+ nv_wr32(dev, 0x00330c, ctx->pinst >> 4); -+ nv_wo32(chan->ramfc, 0x54, ctx->pinst >> 4); -+ nv_mask(dev, 0x002500, 0x00000001, 0x00000001); -+ spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); -+ -+ chan->engctx[engine] = ctx; -+ return 0; -+} -+ -+static void -+nv40_mpeg_context_del(struct nouveau_channel *chan, int engine) -+{ -+ struct drm_nouveau_private *dev_priv = chan->dev->dev_private; -+ struct nouveau_gpuobj *ctx = chan->engctx[engine]; -+ struct drm_device *dev = chan->dev; -+ unsigned long flags; -+ u32 inst = 0x80000000 | (ctx->pinst >> 4); -+ -+ spin_lock_irqsave(&dev_priv->context_switch_lock, flags); -+ nv_mask(dev, 0x00b32c, 0x00000001, 0x00000000); -+ if (nv_rd32(dev, 0x00b318) == inst) -+ nv_mask(dev, 0x00b318, 0x80000000, 0x00000000); -+ nv_mask(dev, 0x00b32c, 0x00000001, 0x00000001); -+ spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); -+ -+ nouveau_gpuobj_ref(NULL, &ctx); -+ chan->engctx[engine] = NULL; -+} -+ -+static int -+nv31_mpeg_object_new(struct nouveau_channel *chan, int engine, -+ u32 handle, u16 class) -+{ -+ struct drm_device *dev = chan->dev; -+ struct nouveau_gpuobj *obj = NULL; -+ int ret; -+ -+ ret = nouveau_gpuobj_new(dev, chan, 20, 16, NVOBJ_FLAG_ZERO_ALLOC | -+ NVOBJ_FLAG_ZERO_FREE, &obj); -+ if (ret) -+ return ret; -+ obj->engine = 2; -+ obj->class = class; -+ -+ nv_wo32(obj, 0x00, class); -+ -+ ret = nouveau_ramht_insert(chan, handle, obj); -+ nouveau_gpuobj_ref(NULL, &obj); -+ return ret; -+} -+ -+static int -+nv31_mpeg_init(struct drm_device *dev, int engine) -+{ -+ struct drm_nouveau_private *dev_priv = dev->dev_private; -+ struct nv31_mpeg_engine *pmpeg = nv_engine(dev, engine); -+ int i; -+ -+ /* VPE init */ -+ nv_mask(dev, 0x000200, 0x00000002, 0x00000000); -+ nv_mask(dev, 0x000200, 0x00000002, 0x00000002); -+ nv_wr32(dev, 0x00b0e0, 0x00000020); /* nvidia: rd 0x01, wr 0x20 */ -+ nv_wr32(dev, 0x00b0e8, 0x00000020); /* nvidia: rd 0x01, wr 0x20 */ -+ -+ for (i = 0; i < dev_priv->engine.fb.num_tiles; i++) -+ pmpeg->base.set_tile_region(dev, i); -+ -+ /* PMPEG init */ -+ nv_wr32(dev, 0x00b32c, 0x00000000); -+ nv_wr32(dev, 0x00b314, 0x00000100); -+ nv_wr32(dev, 0x00b220, nv44_graph_class(dev) ? 0x00000044 : 0x00000031); -+ nv_wr32(dev, 0x00b300, 0x02001ec1); -+ nv_mask(dev, 0x00b32c, 0x00000001, 0x00000001); -+ -+ nv_wr32(dev, 0x00b100, 0xffffffff); -+ nv_wr32(dev, 0x00b140, 0xffffffff); -+ -+ if (!nv_wait(dev, 0x00b200, 0x00000001, 0x00000000)) { -+ NV_ERROR(dev, "PMPEG init: 0x%08x\n", nv_rd32(dev, 0x00b200)); -+ return -EBUSY; -+ } -+ -+ return 0; -+} -+ -+static int -+nv31_mpeg_fini(struct drm_device *dev, int engine, bool suspend) -+{ -+ /*XXX: context save? */ -+ nv_mask(dev, 0x00b32c, 0x00000001, 0x00000000); -+ nv_wr32(dev, 0x00b140, 0x00000000); -+ return 0; -+} -+ -+static int -+nv31_mpeg_mthd_dma(struct nouveau_channel *chan, u32 class, u32 mthd, u32 data) -+{ -+ struct drm_device *dev = chan->dev; -+ u32 inst = data << 4; -+ u32 dma0 = nv_ri32(dev, inst + 0); -+ u32 dma1 = nv_ri32(dev, inst + 4); -+ u32 dma2 = nv_ri32(dev, inst + 8); -+ u32 base = (dma2 & 0xfffff000) | (dma0 >> 20); -+ u32 size = dma1 + 1; -+ -+ /* only allow linear DMA objects */ -+ if (!(dma0 & 0x00002000)) -+ return -EINVAL; -+ -+ if (mthd == 0x0190) { -+ /* DMA_CMD */ -+ nv_mask(dev, 0x00b300, 0x00030000, (dma0 & 0x00030000)); -+ nv_wr32(dev, 0x00b334, base); -+ nv_wr32(dev, 0x00b324, size); -+ } else -+ if (mthd == 0x01a0) { -+ /* DMA_DATA */ -+ nv_mask(dev, 0x00b300, 0x000c0000, (dma0 & 0x00030000) << 2); -+ nv_wr32(dev, 0x00b360, base); -+ nv_wr32(dev, 0x00b364, size); -+ } else { -+ /* DMA_IMAGE, VRAM only */ -+ if (dma0 & 0x000c0000) -+ return -EINVAL; -+ -+ nv_wr32(dev, 0x00b370, base); -+ nv_wr32(dev, 0x00b374, size); -+ } -+ -+ return 0; -+} -+ -+static int -+nv31_mpeg_isr_chid(struct drm_device *dev, u32 inst) -+{ -+ struct drm_nouveau_private *dev_priv = dev->dev_private; -+ struct nouveau_gpuobj *ctx; -+ unsigned long flags; -+ int i; -+ -+ /* hardcode drm channel id on nv3x, so swmthd lookup works */ -+ if (dev_priv->card_type < NV_40) -+ return 0; -+ -+ spin_lock_irqsave(&dev_priv->channels.lock, flags); -+ for (i = 0; i < dev_priv->engine.fifo.channels; i++) { -+ if (!dev_priv->channels.ptr[i]) -+ continue; -+ -+ ctx = dev_priv->channels.ptr[i]->engctx[NVOBJ_ENGINE_MPEG]; -+ if (ctx && ctx->pinst == inst) -+ break; -+ } -+ spin_unlock_irqrestore(&dev_priv->channels.lock, flags); -+ return i; -+} -+ -+static void -+nv31_vpe_set_tile_region(struct drm_device *dev, int i) -+{ -+ struct drm_nouveau_private *dev_priv = dev->dev_private; -+ struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i]; -+ -+ nv_wr32(dev, 0x00b008 + (i * 0x10), tile->pitch); -+ nv_wr32(dev, 0x00b004 + (i * 0x10), tile->limit); -+ nv_wr32(dev, 0x00b000 + (i * 0x10), tile->addr); -+} -+ -+static void -+nv31_mpeg_isr(struct drm_device *dev) -+{ -+ u32 inst = (nv_rd32(dev, 0x00b318) & 0x000fffff) << 4; -+ u32 chid = nv31_mpeg_isr_chid(dev, inst); -+ u32 stat = nv_rd32(dev, 0x00b100); -+ u32 type = nv_rd32(dev, 0x00b230); -+ u32 mthd = nv_rd32(dev, 0x00b234); -+ u32 data = nv_rd32(dev, 0x00b238); -+ u32 show = stat; -+ -+ if (stat & 0x01000000) { -+ /* happens on initial binding of the object */ -+ if (type == 0x00000020 && mthd == 0x0000) { -+ nv_mask(dev, 0x00b308, 0x00000000, 0x00000000); -+ show &= ~0x01000000; -+ } -+ -+ if (type == 0x00000010) { -+ if (!nouveau_gpuobj_mthd_call2(dev, chid, 0x3174, mthd, data)) -+ show &= ~0x01000000; -+ } -+ } -+ -+ nv_wr32(dev, 0x00b100, stat); -+ nv_wr32(dev, 0x00b230, 0x00000001); -+ -+ if (show && nouveau_ratelimit()) { -+ NV_INFO(dev, "PMPEG: Ch %d [0x%08x] 0x%08x 0x%08x 0x%08x 0x%08x\n", -+ chid, inst, stat, type, mthd, data); -+ } -+} -+ -+static void -+nv31_vpe_isr(struct drm_device *dev) -+{ -+ if (nv_rd32(dev, 0x00b100)) -+ nv31_mpeg_isr(dev); -+ -+ if (nv_rd32(dev, 0x00b800)) { -+ u32 stat = nv_rd32(dev, 0x00b800); -+ NV_INFO(dev, "PMSRCH: 0x%08x\n", stat); -+ nv_wr32(dev, 0xb800, stat); -+ } -+} -+ -+static void -+nv31_mpeg_destroy(struct drm_device *dev, int engine) -+{ -+ struct nv31_mpeg_engine *pmpeg = nv_engine(dev, engine); -+ -+ nouveau_irq_unregister(dev, 0); -+ -+ NVOBJ_ENGINE_DEL(dev, MPEG); -+ kfree(pmpeg); -+} -+ -+int -+nv31_mpeg_create(struct drm_device *dev) -+{ -+ struct drm_nouveau_private *dev_priv = dev->dev_private; -+ struct nv31_mpeg_engine *pmpeg; -+ -+ pmpeg = kzalloc(sizeof(*pmpeg), GFP_KERNEL); -+ if (!pmpeg) -+ return -ENOMEM; -+ atomic_set(&pmpeg->refcount, 0); -+ -+ pmpeg->base.destroy = nv31_mpeg_destroy; -+ pmpeg->base.init = nv31_mpeg_init; -+ pmpeg->base.fini = nv31_mpeg_fini; -+ if (dev_priv->card_type < NV_40) { -+ pmpeg->base.context_new = nv31_mpeg_context_new; -+ pmpeg->base.context_del = nv31_mpeg_context_del; -+ } else { -+ pmpeg->base.context_new = nv40_mpeg_context_new; -+ pmpeg->base.context_del = nv40_mpeg_context_del; -+ } -+ pmpeg->base.object_new = nv31_mpeg_object_new; -+ -+ /* ISR vector, PMC_ENABLE bit, and TILE regs are shared between -+ * all VPE engines, for this driver's purposes the PMPEG engine -+ * will be treated as the "master" and handle the global VPE -+ * bits too -+ */ -+ pmpeg->base.set_tile_region = nv31_vpe_set_tile_region; -+ nouveau_irq_register(dev, 0, nv31_vpe_isr); -+ -+ NVOBJ_ENGINE_ADD(dev, MPEG, &pmpeg->base); -+ NVOBJ_CLASS(dev, 0x3174, MPEG); -+ NVOBJ_MTHD (dev, 0x3174, 0x0190, nv31_mpeg_mthd_dma); -+ NVOBJ_MTHD (dev, 0x3174, 0x01a0, nv31_mpeg_mthd_dma); -+ NVOBJ_MTHD (dev, 0x3174, 0x01b0, nv31_mpeg_mthd_dma); -+ -+#if 0 -+ NVOBJ_ENGINE_ADD(dev, ME, &pme->base); -+ NVOBJ_CLASS(dev, 0x4075, ME); -+#endif -+ return 0; -+ -+} -diff --git a/drivers/gpu/drm/nouveau/nv40_mpeg.c b/drivers/gpu/drm/nouveau/nv40_mpeg.c -deleted file mode 100644 -index ad03a0e..0000000 ---- a/drivers/gpu/drm/nouveau/nv40_mpeg.c -+++ /dev/null -@@ -1,311 +0,0 @@ --/* -- * Copyright 2011 Red Hat Inc. -- * -- * Permission is hereby granted, free of charge, to any person obtaining a -- * copy of this software and associated documentation files (the "Software"), -- * to deal in the Software without restriction, including without limitation -- * the rights to use, copy, modify, merge, publish, distribute, sublicense, -- * and/or sell copies of the Software, and to permit persons to whom the -- * Software is furnished to do so, subject to the following conditions: -- * -- * The above copyright notice and this permission notice shall be included in -- * all copies or substantial portions of the Software. -- * -- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR -- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -- * OTHER DEALINGS IN THE SOFTWARE. -- * -- * Authors: Ben Skeggs -- */ -- --#include "drmP.h" --#include "nouveau_drv.h" --#include "nouveau_ramht.h" -- --struct nv40_mpeg_engine { -- struct nouveau_exec_engine base; --}; -- --static int --nv40_mpeg_context_new(struct nouveau_channel *chan, int engine) --{ -- struct drm_device *dev = chan->dev; -- struct drm_nouveau_private *dev_priv = dev->dev_private; -- struct nouveau_gpuobj *ctx = NULL; -- unsigned long flags; -- int ret; -- -- NV_DEBUG(dev, "ch%d\n", chan->id); -- -- ret = nouveau_gpuobj_new(dev, NULL, 264 * 4, 16, NVOBJ_FLAG_ZERO_ALLOC | -- NVOBJ_FLAG_ZERO_FREE, &ctx); -- if (ret) -- return ret; -- -- nv_wo32(ctx, 0x78, 0x02001ec1); -- -- spin_lock_irqsave(&dev_priv->context_switch_lock, flags); -- nv_mask(dev, 0x002500, 0x00000001, 0x00000000); -- if ((nv_rd32(dev, 0x003204) & 0x1f) == chan->id) -- nv_wr32(dev, 0x00330c, ctx->pinst >> 4); -- nv_wo32(chan->ramfc, 0x54, ctx->pinst >> 4); -- nv_mask(dev, 0x002500, 0x00000001, 0x00000001); -- spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); -- -- chan->engctx[engine] = ctx; -- return 0; --} -- --static void --nv40_mpeg_context_del(struct nouveau_channel *chan, int engine) --{ -- struct drm_nouveau_private *dev_priv = chan->dev->dev_private; -- struct nouveau_gpuobj *ctx = chan->engctx[engine]; -- struct drm_device *dev = chan->dev; -- unsigned long flags; -- u32 inst = 0x80000000 | (ctx->pinst >> 4); -- -- spin_lock_irqsave(&dev_priv->context_switch_lock, flags); -- nv_mask(dev, 0x00b32c, 0x00000001, 0x00000000); -- if (nv_rd32(dev, 0x00b318) == inst) -- nv_mask(dev, 0x00b318, 0x80000000, 0x00000000); -- nv_mask(dev, 0x00b32c, 0x00000001, 0x00000001); -- spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); -- -- nouveau_gpuobj_ref(NULL, &ctx); -- chan->engctx[engine] = NULL; --} -- --static int --nv40_mpeg_object_new(struct nouveau_channel *chan, int engine, -- u32 handle, u16 class) --{ -- struct drm_device *dev = chan->dev; -- struct nouveau_gpuobj *obj = NULL; -- int ret; -- -- ret = nouveau_gpuobj_new(dev, chan, 20, 16, NVOBJ_FLAG_ZERO_ALLOC | -- NVOBJ_FLAG_ZERO_FREE, &obj); -- if (ret) -- return ret; -- obj->engine = 2; -- obj->class = class; -- -- nv_wo32(obj, 0x00, class); -- -- ret = nouveau_ramht_insert(chan, handle, obj); -- nouveau_gpuobj_ref(NULL, &obj); -- return ret; --} -- --static int --nv40_mpeg_init(struct drm_device *dev, int engine) --{ -- struct drm_nouveau_private *dev_priv = dev->dev_private; -- struct nv40_mpeg_engine *pmpeg = nv_engine(dev, engine); -- int i; -- -- /* VPE init */ -- nv_mask(dev, 0x000200, 0x00000002, 0x00000000); -- nv_mask(dev, 0x000200, 0x00000002, 0x00000002); -- nv_wr32(dev, 0x00b0e0, 0x00000020); /* nvidia: rd 0x01, wr 0x20 */ -- nv_wr32(dev, 0x00b0e8, 0x00000020); /* nvidia: rd 0x01, wr 0x20 */ -- -- for (i = 0; i < dev_priv->engine.fb.num_tiles; i++) -- pmpeg->base.set_tile_region(dev, i); -- -- /* PMPEG init */ -- nv_wr32(dev, 0x00b32c, 0x00000000); -- nv_wr32(dev, 0x00b314, 0x00000100); -- nv_wr32(dev, 0x00b220, 0x00000044); -- nv_wr32(dev, 0x00b300, 0x02001ec1); -- nv_mask(dev, 0x00b32c, 0x00000001, 0x00000001); -- -- nv_wr32(dev, 0x00b100, 0xffffffff); -- nv_wr32(dev, 0x00b140, 0xffffffff); -- -- if (!nv_wait(dev, 0x00b200, 0x00000001, 0x00000000)) { -- NV_ERROR(dev, "PMPEG init: 0x%08x\n", nv_rd32(dev, 0x00b200)); -- return -EBUSY; -- } -- -- return 0; --} -- --static int --nv40_mpeg_fini(struct drm_device *dev, int engine, bool suspend) --{ -- /*XXX: context save? */ -- nv_mask(dev, 0x00b32c, 0x00000001, 0x00000000); -- nv_wr32(dev, 0x00b140, 0x00000000); -- return 0; --} -- --static int --nv40_mpeg_mthd_dma(struct nouveau_channel *chan, u32 class, u32 mthd, u32 data) --{ -- struct drm_device *dev = chan->dev; -- u32 inst = data << 4; -- u32 dma0 = nv_ri32(dev, inst + 0); -- u32 dma1 = nv_ri32(dev, inst + 4); -- u32 dma2 = nv_ri32(dev, inst + 8); -- u32 base = (dma2 & 0xfffff000) | (dma0 >> 20); -- u32 size = dma1 + 1; -- -- /* only allow linear DMA objects */ -- if (!(dma0 & 0x00002000)) -- return -EINVAL; -- -- if (mthd == 0x0190) { -- /* DMA_CMD */ -- nv_mask(dev, 0x00b300, 0x00030000, (dma0 & 0x00030000)); -- nv_wr32(dev, 0x00b334, base); -- nv_wr32(dev, 0x00b324, size); -- } else -- if (mthd == 0x01a0) { -- /* DMA_DATA */ -- nv_mask(dev, 0x00b300, 0x000c0000, (dma0 & 0x00030000) << 2); -- nv_wr32(dev, 0x00b360, base); -- nv_wr32(dev, 0x00b364, size); -- } else { -- /* DMA_IMAGE, VRAM only */ -- if (dma0 & 0x000c0000) -- return -EINVAL; -- -- nv_wr32(dev, 0x00b370, base); -- nv_wr32(dev, 0x00b374, size); -- } -- -- return 0; --} -- --static int --nv40_mpeg_isr_chid(struct drm_device *dev, u32 inst) --{ -- struct drm_nouveau_private *dev_priv = dev->dev_private; -- struct nouveau_gpuobj *ctx; -- unsigned long flags; -- int i; -- -- spin_lock_irqsave(&dev_priv->channels.lock, flags); -- for (i = 0; i < dev_priv->engine.fifo.channels; i++) { -- if (!dev_priv->channels.ptr[i]) -- continue; -- -- ctx = dev_priv->channels.ptr[i]->engctx[NVOBJ_ENGINE_MPEG]; -- if (ctx && ctx->pinst == inst) -- break; -- } -- spin_unlock_irqrestore(&dev_priv->channels.lock, flags); -- return i; --} -- --static void --nv40_vpe_set_tile_region(struct drm_device *dev, int i) --{ -- struct drm_nouveau_private *dev_priv = dev->dev_private; -- struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i]; -- -- nv_wr32(dev, 0x00b008 + (i * 0x10), tile->pitch); -- nv_wr32(dev, 0x00b004 + (i * 0x10), tile->limit); -- nv_wr32(dev, 0x00b000 + (i * 0x10), tile->addr); --} -- --static void --nv40_mpeg_isr(struct drm_device *dev) --{ -- u32 inst = (nv_rd32(dev, 0x00b318) & 0x000fffff) << 4; -- u32 chid = nv40_mpeg_isr_chid(dev, inst); -- u32 stat = nv_rd32(dev, 0x00b100); -- u32 type = nv_rd32(dev, 0x00b230); -- u32 mthd = nv_rd32(dev, 0x00b234); -- u32 data = nv_rd32(dev, 0x00b238); -- u32 show = stat; -- -- if (stat & 0x01000000) { -- /* happens on initial binding of the object */ -- if (type == 0x00000020 && mthd == 0x0000) { -- nv_mask(dev, 0x00b308, 0x00000000, 0x00000000); -- show &= ~0x01000000; -- } -- -- if (type == 0x00000010) { -- if (!nouveau_gpuobj_mthd_call2(dev, chid, 0x3174, mthd, data)) -- show &= ~0x01000000; -- } -- } -- -- nv_wr32(dev, 0x00b100, stat); -- nv_wr32(dev, 0x00b230, 0x00000001); -- -- if (show && nouveau_ratelimit()) { -- NV_INFO(dev, "PMPEG: Ch %d [0x%08x] 0x%08x 0x%08x 0x%08x 0x%08x\n", -- chid, inst, stat, type, mthd, data); -- } --} -- --static void --nv40_vpe_isr(struct drm_device *dev) --{ -- if (nv_rd32(dev, 0x00b100)) -- nv40_mpeg_isr(dev); -- -- if (nv_rd32(dev, 0x00b800)) { -- u32 stat = nv_rd32(dev, 0x00b800); -- NV_INFO(dev, "PMSRCH: 0x%08x\n", stat); -- nv_wr32(dev, 0xb800, stat); -- } --} -- --static void --nv40_mpeg_destroy(struct drm_device *dev, int engine) --{ -- struct nv40_mpeg_engine *pmpeg = nv_engine(dev, engine); -- -- nouveau_irq_unregister(dev, 0); -- -- NVOBJ_ENGINE_DEL(dev, MPEG); -- kfree(pmpeg); --} -- --int --nv40_mpeg_create(struct drm_device *dev) --{ -- struct nv40_mpeg_engine *pmpeg; -- -- pmpeg = kzalloc(sizeof(*pmpeg), GFP_KERNEL); -- if (!pmpeg) -- return -ENOMEM; -- -- pmpeg->base.destroy = nv40_mpeg_destroy; -- pmpeg->base.init = nv40_mpeg_init; -- pmpeg->base.fini = nv40_mpeg_fini; -- pmpeg->base.context_new = nv40_mpeg_context_new; -- pmpeg->base.context_del = nv40_mpeg_context_del; -- pmpeg->base.object_new = nv40_mpeg_object_new; -- -- /* ISR vector, PMC_ENABLE bit, and TILE regs are shared between -- * all VPE engines, for this driver's purposes the PMPEG engine -- * will be treated as the "master" and handle the global VPE -- * bits too -- */ -- pmpeg->base.set_tile_region = nv40_vpe_set_tile_region; -- nouveau_irq_register(dev, 0, nv40_vpe_isr); -- -- NVOBJ_ENGINE_ADD(dev, MPEG, &pmpeg->base); -- NVOBJ_CLASS(dev, 0x3174, MPEG); -- NVOBJ_MTHD (dev, 0x3174, 0x0190, nv40_mpeg_mthd_dma); -- NVOBJ_MTHD (dev, 0x3174, 0x01a0, nv40_mpeg_mthd_dma); -- NVOBJ_MTHD (dev, 0x3174, 0x01b0, nv40_mpeg_mthd_dma); -- --#if 0 -- NVOBJ_ENGINE_ADD(dev, ME, &pme->base); -- NVOBJ_CLASS(dev, 0x4075, ME); --#endif -- return 0; -- --} -diff --git a/drivers/gpu/drm/nouveau/nv40_pm.c b/drivers/gpu/drm/nouveau/nv40_pm.c -new file mode 100644 -index 0000000..e676b0d ---- /dev/null -+++ b/drivers/gpu/drm/nouveau/nv40_pm.c -@@ -0,0 +1,348 @@ -+/* -+ * Copyright 2011 Red Hat Inc. -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a -+ * copy of this software and associated documentation files (the "Software"), -+ * to deal in the Software without restriction, including without limitation -+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, -+ * and/or sell copies of the Software, and to permit persons to whom the -+ * Software is furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR -+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -+ * OTHER DEALINGS IN THE SOFTWARE. -+ * -+ * Authors: Ben Skeggs -+ */ -+ -+#include "drmP.h" -+#include "nouveau_drv.h" -+#include "nouveau_bios.h" -+#include "nouveau_pm.h" -+#include "nouveau_hw.h" -+ -+#define min2(a,b) ((a) < (b) ? (a) : (b)) -+ -+static u32 -+read_pll_1(struct drm_device *dev, u32 reg) -+{ -+ u32 ctrl = nv_rd32(dev, reg + 0x00); -+ int P = (ctrl & 0x00070000) >> 16; -+ int N = (ctrl & 0x0000ff00) >> 8; -+ int M = (ctrl & 0x000000ff) >> 0; -+ u32 ref = 27000, clk = 0; -+ -+ if (ctrl & 0x80000000) -+ clk = ref * N / M; -+ -+ return clk >> P; -+} -+ -+static u32 -+read_pll_2(struct drm_device *dev, u32 reg) -+{ -+ u32 ctrl = nv_rd32(dev, reg + 0x00); -+ u32 coef = nv_rd32(dev, reg + 0x04); -+ int N2 = (coef & 0xff000000) >> 24; -+ int M2 = (coef & 0x00ff0000) >> 16; -+ int N1 = (coef & 0x0000ff00) >> 8; -+ int M1 = (coef & 0x000000ff) >> 0; -+ int P = (ctrl & 0x00070000) >> 16; -+ u32 ref = 27000, clk = 0; -+ -+ if ((ctrl & 0x80000000) && M1) { -+ clk = ref * N1 / M1; -+ if ((ctrl & 0x40000100) == 0x40000000) { -+ if (M2) -+ clk = clk * N2 / M2; -+ else -+ clk = 0; -+ } -+ } -+ -+ return clk >> P; -+} -+ -+static u32 -+read_clk(struct drm_device *dev, u32 src) -+{ -+ switch (src) { -+ case 3: -+ return read_pll_2(dev, 0x004000); -+ case 2: -+ return read_pll_1(dev, 0x004008); -+ default: -+ break; -+ } -+ -+ return 0; -+} -+ -+int -+nv40_pm_clocks_get(struct drm_device *dev, struct nouveau_pm_level *perflvl) -+{ -+ u32 ctrl = nv_rd32(dev, 0x00c040); -+ -+ perflvl->core = read_clk(dev, (ctrl & 0x00000003) >> 0); -+ perflvl->shader = read_clk(dev, (ctrl & 0x00000030) >> 4); -+ perflvl->memory = read_pll_2(dev, 0x4020); -+ return 0; -+} -+ -+struct nv40_pm_state { -+ u32 ctrl; -+ u32 npll_ctrl; -+ u32 npll_coef; -+ u32 spll; -+ u32 mpll_ctrl; -+ u32 mpll_coef; -+}; -+ -+static int -+nv40_calc_pll(struct drm_device *dev, u32 reg, struct pll_lims *pll, -+ u32 clk, int *N1, int *M1, int *N2, int *M2, int *log2P) -+{ -+ struct nouveau_pll_vals coef; -+ int ret; -+ -+ ret = get_pll_limits(dev, reg, pll); -+ if (ret) -+ return ret; -+ -+ if (clk < pll->vco1.maxfreq) -+ pll->vco2.maxfreq = 0; -+ -+ ret = nouveau_calc_pll_mnp(dev, pll, clk, &coef); -+ if (ret == 0) -+ return -ERANGE; -+ -+ *N1 = coef.N1; -+ *M1 = coef.M1; -+ if (N2 && M2) { -+ if (pll->vco2.maxfreq) { -+ *N2 = coef.N2; -+ *M2 = coef.M2; -+ } else { -+ *N2 = 1; -+ *M2 = 1; -+ } -+ } -+ *log2P = coef.log2P; -+ return 0; -+} -+ -+void * -+nv40_pm_clocks_pre(struct drm_device *dev, struct nouveau_pm_level *perflvl) -+{ -+ struct nv40_pm_state *info; -+ struct pll_lims pll; -+ int N1, N2, M1, M2, log2P; -+ int ret; -+ -+ info = kmalloc(sizeof(*info), GFP_KERNEL); -+ if (!info) -+ return ERR_PTR(-ENOMEM); -+ -+ /* core/geometric clock */ -+ ret = nv40_calc_pll(dev, 0x004000, &pll, perflvl->core, -+ &N1, &M1, &N2, &M2, &log2P); -+ if (ret < 0) -+ goto out; -+ -+ if (N2 == M2) { -+ info->npll_ctrl = 0x80000100 | (log2P << 16); -+ info->npll_coef = (N1 << 8) | M1; -+ } else { -+ info->npll_ctrl = 0xc0000000 | (log2P << 16); -+ info->npll_coef = (N2 << 24) | (M2 << 16) | (N1 << 8) | M1; -+ } -+ -+ /* use the second PLL for shader/rop clock, if it differs from core */ -+ if (perflvl->shader && perflvl->shader != perflvl->core) { -+ ret = nv40_calc_pll(dev, 0x004008, &pll, perflvl->shader, -+ &N1, &M1, NULL, NULL, &log2P); -+ if (ret < 0) -+ goto out; -+ -+ info->spll = 0xc0000000 | (log2P << 16) | (N1 << 8) | M1; -+ info->ctrl = 0x00000223; -+ } else { -+ info->spll = 0x00000000; -+ info->ctrl = 0x00000333; -+ } -+ -+ /* memory clock */ -+ if (!perflvl->memory) { -+ info->mpll_ctrl = 0x00000000; -+ goto out; -+ } -+ -+ ret = nv40_calc_pll(dev, 0x004020, &pll, perflvl->memory, -+ &N1, &M1, &N2, &M2, &log2P); -+ if (ret < 0) -+ goto out; -+ -+ info->mpll_ctrl = 0x80000000 | (log2P << 16); -+ info->mpll_ctrl |= min2(pll.log2p_bias + log2P, pll.max_log2p) << 20; -+ if (N2 == M2) { -+ info->mpll_ctrl |= 0x00000100; -+ info->mpll_coef = (N1 << 8) | M1; -+ } else { -+ info->mpll_ctrl |= 0x40000000; -+ info->mpll_coef = (N2 << 24) | (M2 << 16) | (N1 << 8) | M1; -+ } -+ -+out: -+ if (ret < 0) { -+ kfree(info); -+ info = ERR_PTR(ret); -+ } -+ return info; -+} -+ -+static bool -+nv40_pm_gr_idle(void *data) -+{ -+ struct drm_device *dev = data; -+ -+ if ((nv_rd32(dev, 0x400760) & 0x000000f0) >> 4 != -+ (nv_rd32(dev, 0x400760) & 0x0000000f)) -+ return false; -+ -+ if (nv_rd32(dev, 0x400700)) -+ return false; -+ -+ return true; -+} -+ -+void -+nv40_pm_clocks_set(struct drm_device *dev, void *pre_state) -+{ -+ struct drm_nouveau_private *dev_priv = dev->dev_private; -+ struct nv40_pm_state *info = pre_state; -+ unsigned long flags; -+ struct bit_entry M; -+ u32 crtc_mask = 0; -+ u8 sr1[2]; -+ int i; -+ -+ /* determine which CRTCs are active, fetch VGA_SR1 for each */ -+ for (i = 0; i < 2; i++) { -+ u32 vbl = nv_rd32(dev, 0x600808 + (i * 0x2000)); -+ u32 cnt = 0; -+ do { -+ if (vbl != nv_rd32(dev, 0x600808 + (i * 0x2000))) { -+ nv_wr08(dev, 0x0c03c4 + (i * 0x2000), 0x01); -+ sr1[i] = nv_rd08(dev, 0x0c03c5 + (i * 0x2000)); -+ if (!(sr1[i] & 0x20)) -+ crtc_mask |= (1 << i); -+ break; -+ } -+ udelay(1); -+ } while (cnt++ < 32); -+ } -+ -+ /* halt and idle engines */ -+ spin_lock_irqsave(&dev_priv->context_switch_lock, flags); -+ nv_mask(dev, 0x002500, 0x00000001, 0x00000000); -+ if (!nv_wait(dev, 0x002500, 0x00000010, 0x00000000)) -+ goto resume; -+ nv_mask(dev, 0x003220, 0x00000001, 0x00000000); -+ if (!nv_wait(dev, 0x003220, 0x00000010, 0x00000000)) -+ goto resume; -+ nv_mask(dev, 0x003200, 0x00000001, 0x00000000); -+ nv04_fifo_cache_pull(dev, false); -+ -+ if (!nv_wait_cb(dev, nv40_pm_gr_idle, dev)) -+ goto resume; -+ -+ /* set engine clocks */ -+ nv_mask(dev, 0x00c040, 0x00000333, 0x00000000); -+ nv_wr32(dev, 0x004004, info->npll_coef); -+ nv_mask(dev, 0x004000, 0xc0070100, info->npll_ctrl); -+ nv_mask(dev, 0x004008, 0xc007ffff, info->spll); -+ mdelay(5); -+ nv_mask(dev, 0x00c040, 0x00000333, info->ctrl); -+ -+ if (!info->mpll_ctrl) -+ goto resume; -+ -+ /* wait for vblank start on active crtcs, disable memory access */ -+ for (i = 0; i < 2; i++) { -+ if (!(crtc_mask & (1 << i))) -+ continue; -+ nv_wait(dev, 0x600808 + (i * 0x2000), 0x00010000, 0x00000000); -+ nv_wait(dev, 0x600808 + (i * 0x2000), 0x00010000, 0x00010000); -+ nv_wr08(dev, 0x0c03c4 + (i * 0x2000), 0x01); -+ nv_wr08(dev, 0x0c03c5 + (i * 0x2000), sr1[i] | 0x20); -+ } -+ -+ /* prepare ram for reclocking */ -+ nv_wr32(dev, 0x1002d4, 0x00000001); /* precharge */ -+ nv_wr32(dev, 0x1002d0, 0x00000001); /* refresh */ -+ nv_wr32(dev, 0x1002d0, 0x00000001); /* refresh */ -+ nv_mask(dev, 0x100210, 0x80000000, 0x00000000); /* no auto refresh */ -+ nv_wr32(dev, 0x1002dc, 0x00000001); /* enable self-refresh */ -+ -+ /* change the PLL of each memory partition */ -+ nv_mask(dev, 0x00c040, 0x0000c000, 0x00000000); -+ switch (dev_priv->chipset) { -+ case 0x40: -+ case 0x45: -+ case 0x41: -+ case 0x42: -+ case 0x47: -+ nv_mask(dev, 0x004044, 0xc0771100, info->mpll_ctrl); -+ nv_mask(dev, 0x00402c, 0xc0771100, info->mpll_ctrl); -+ nv_wr32(dev, 0x004048, info->mpll_coef); -+ nv_wr32(dev, 0x004030, info->mpll_coef); -+ case 0x43: -+ case 0x49: -+ case 0x4b: -+ nv_mask(dev, 0x004038, 0xc0771100, info->mpll_ctrl); -+ nv_wr32(dev, 0x00403c, info->mpll_coef); -+ default: -+ nv_mask(dev, 0x004020, 0xc0771100, info->mpll_ctrl); -+ nv_wr32(dev, 0x004024, info->mpll_coef); -+ break; -+ } -+ udelay(100); -+ nv_mask(dev, 0x00c040, 0x0000c000, 0x0000c000); -+ -+ /* re-enable normal operation of memory controller */ -+ nv_wr32(dev, 0x1002dc, 0x00000000); -+ nv_mask(dev, 0x100210, 0x80000000, 0x80000000); -+ udelay(100); -+ -+ /* execute memory reset script from vbios */ -+ if (!bit_table(dev, 'M', &M)) -+ nouveau_bios_init_exec(dev, ROM16(M.data[0])); -+ -+ /* make sure we're in vblank (hopefully the same one as before), and -+ * then re-enable crtc memory access -+ */ -+ for (i = 0; i < 2; i++) { -+ if (!(crtc_mask & (1 << i))) -+ continue; -+ nv_wait(dev, 0x600808 + (i * 0x2000), 0x00010000, 0x00010000); -+ nv_wr08(dev, 0x0c03c4 + (i * 0x2000), 0x01); -+ nv_wr08(dev, 0x0c03c5 + (i * 0x2000), sr1[i]); -+ } -+ -+ /* resume engines */ -+resume: -+ nv_wr32(dev, 0x003250, 0x00000001); -+ nv_mask(dev, 0x003220, 0x00000001, 0x00000001); -+ nv_wr32(dev, 0x003200, 0x00000001); -+ nv_wr32(dev, 0x002500, 0x00000001); -+ spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); -+ -+ kfree(info); -+} -diff --git a/drivers/gpu/drm/nouveau/nv50_crtc.c b/drivers/gpu/drm/nouveau/nv50_crtc.c -index 5d98907..882080e 100644 ---- a/drivers/gpu/drm/nouveau/nv50_crtc.c -+++ b/drivers/gpu/drm/nouveau/nv50_crtc.c -@@ -329,8 +329,6 @@ nv50_crtc_destroy(struct drm_crtc *crtc) - - drm_crtc_cleanup(&nv_crtc->base); - -- nv50_cursor_fini(nv_crtc); -- - nouveau_bo_unmap(nv_crtc->lut.nvbo); - nouveau_bo_ref(NULL, &nv_crtc->lut.nvbo); - nouveau_bo_unmap(nv_crtc->cursor.nvbo); -diff --git a/drivers/gpu/drm/nouveau/nv50_cursor.c b/drivers/gpu/drm/nouveau/nv50_cursor.c -index 9752c35..adfc9b6 100644 ---- a/drivers/gpu/drm/nouveau/nv50_cursor.c -+++ b/drivers/gpu/drm/nouveau/nv50_cursor.c -@@ -137,21 +137,3 @@ nv50_cursor_init(struct nouveau_crtc *nv_crtc) - nv_crtc->cursor.show = nv50_cursor_show; - return 0; - } -- --void --nv50_cursor_fini(struct nouveau_crtc *nv_crtc) --{ -- struct drm_device *dev = nv_crtc->base.dev; -- int idx = nv_crtc->index; -- -- NV_DEBUG_KMS(dev, "\n"); -- -- nv_wr32(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(idx), 0); -- if (!nv_wait(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(idx), -- NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS, 0)) { -- NV_ERROR(dev, "timeout: CURSOR_CTRL2_STATUS == 0\n"); -- NV_ERROR(dev, "CURSOR_CTRL2 = 0x%08x\n", -- nv_rd32(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(idx))); -- } --} -- -diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c -index db1a5f4..d23ca00 100644 ---- a/drivers/gpu/drm/nouveau/nv50_display.c -+++ b/drivers/gpu/drm/nouveau/nv50_display.c -@@ -247,6 +247,16 @@ static int nv50_display_disable(struct drm_device *dev) - } - } - -+ for (i = 0; i < 2; i++) { -+ nv_wr32(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i), 0); -+ if (!nv_wait(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i), -+ NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS, 0)) { -+ NV_ERROR(dev, "timeout: CURSOR_CTRL2_STATUS == 0\n"); -+ NV_ERROR(dev, "CURSOR_CTRL2 = 0x%08x\n", -+ nv_rd32(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i))); -+ } -+ } -+ - nv50_evo_fini(dev); - - for (i = 0; i < 3; i++) { -@@ -286,23 +296,6 @@ int nv50_display_create(struct drm_device *dev) - return -ENOMEM; - dev_priv->engine.display.priv = priv; - -- /* init basic kernel modesetting */ -- drm_mode_config_init(dev); -- -- /* Initialise some optional connector properties. */ -- drm_mode_create_scaling_mode_property(dev); -- drm_mode_create_dithering_property(dev); -- -- dev->mode_config.min_width = 0; -- dev->mode_config.min_height = 0; -- -- dev->mode_config.funcs = (void *)&nouveau_mode_config_funcs; -- -- dev->mode_config.max_width = 8192; -- dev->mode_config.max_height = 8192; -- -- dev->mode_config.fb_base = dev_priv->fb_phys; -- - /* Create CRTC objects */ - for (i = 0; i < 2; i++) - nv50_crtc_create(dev, i); -@@ -364,8 +357,6 @@ nv50_display_destroy(struct drm_device *dev) - - NV_DEBUG_KMS(dev, "\n"); - -- drm_mode_config_cleanup(dev); -- - nv50_display_disable(dev); - nouveau_irq_unregister(dev, 26); - kfree(disp); -@@ -698,7 +689,7 @@ nv50_display_unk10_handler(struct drm_device *dev) - struct dcb_entry *dcb = &dev_priv->vbios.dcb.entry[i]; - - if (dcb->type == type && (dcb->or & (1 << or))) { -- nouveau_bios_run_display_table(dev, dcb, 0, -1); -+ nouveau_bios_run_display_table(dev, 0, -1, dcb, -1); - disp->irq.dcb = dcb; - goto ack; - } -@@ -711,37 +702,6 @@ ack: - } - - 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 - nv50_display_unk20_handler(struct drm_device *dev) - { - struct drm_nouveau_private *dev_priv = dev->dev_private; -@@ -753,7 +713,7 @@ nv50_display_unk20_handler(struct drm_device *dev) - NV_DEBUG_KMS(dev, "0x610030: 0x%08x\n", unk30); - dcb = disp->irq.dcb; - if (dcb) { -- nouveau_bios_run_display_table(dev, dcb, 0, -2); -+ nouveau_bios_run_display_table(dev, 0, -2, dcb, -1); - disp->irq.dcb = NULL; - } - -@@ -837,9 +797,15 @@ nv50_display_unk20_handler(struct drm_device *dev) - } - - script = nv50_display_script_select(dev, dcb, mc, pclk); -- nouveau_bios_run_display_table(dev, dcb, script, pclk); -+ nouveau_bios_run_display_table(dev, script, pclk, dcb, -1); - -- nv50_display_unk20_dp_hack(dev, dcb); -+ if (type == OUTPUT_DP) { -+ int link = !(dcb->dpconf.sor.link & 1); -+ if ((mc & 0x000f0000) == 0x00020000) -+ nouveau_dp_tu_update(dev, or, link, pclk, 18); -+ else -+ nouveau_dp_tu_update(dev, or, link, pclk, 24); -+ } - - if (dcb->type != OUTPUT_ANALOG) { - tmp = nv_rd32(dev, NV50_PDISPLAY_SOR_CLK_CTRL2(or)); -@@ -904,7 +870,7 @@ nv50_display_unk40_handler(struct drm_device *dev) - if (!dcb) - goto ack; - -- nouveau_bios_run_display_table(dev, dcb, script, -pclk); -+ nouveau_bios_run_display_table(dev, script, -pclk, dcb, -1); - nv50_display_unk40_dp_set_tmds(dev, dcb); - - ack: -diff --git a/drivers/gpu/drm/nouveau/nv50_gpio.c b/drivers/gpu/drm/nouveau/nv50_gpio.c -index d4f4206..793a5cc 100644 ---- a/drivers/gpu/drm/nouveau/nv50_gpio.c -+++ b/drivers/gpu/drm/nouveau/nv50_gpio.c -@@ -98,6 +98,37 @@ nv50_gpio_set(struct drm_device *dev, enum dcb_gpio_tag tag, int state) - } - - int -+nvd0_gpio_get(struct drm_device *dev, enum dcb_gpio_tag tag) -+{ -+ struct dcb_gpio_entry *gpio; -+ u32 v; -+ -+ gpio = nouveau_bios_gpio_entry(dev, tag); -+ if (!gpio) -+ return -ENOENT; -+ -+ v = nv_rd32(dev, 0x00d610 + (gpio->line * 4)); -+ v &= 0x00004000; -+ return (!!v == (gpio->state[1] & 1)); -+} -+ -+int -+nvd0_gpio_set(struct drm_device *dev, enum dcb_gpio_tag tag, int state) -+{ -+ struct dcb_gpio_entry *gpio; -+ u32 v; -+ -+ gpio = nouveau_bios_gpio_entry(dev, tag); -+ if (!gpio) -+ return -ENOENT; -+ -+ v = gpio->state[state] ^ 2; -+ -+ nv_mask(dev, 0x00d610 + (gpio->line * 4), 0x00003000, v << 12); -+ return 0; -+} -+ -+int - nv50_gpio_irq_register(struct drm_device *dev, enum dcb_gpio_tag tag, - void (*handler)(void *, int), void *data) - { -diff --git a/drivers/gpu/drm/nouveau/nv50_graph.c b/drivers/gpu/drm/nouveau/nv50_graph.c -index d43c46c..8c979b3 100644 ---- a/drivers/gpu/drm/nouveau/nv50_graph.c -+++ b/drivers/gpu/drm/nouveau/nv50_graph.c -@@ -120,70 +120,62 @@ nv50_graph_unload_context(struct drm_device *dev) - return 0; - } - --static void --nv50_graph_init_reset(struct drm_device *dev) --{ -- uint32_t pmc_e = NV_PMC_ENABLE_PGRAPH | (1 << 21); -- NV_DEBUG(dev, "\n"); -- -- nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) & ~pmc_e); -- nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) | pmc_e); --} -- --static void --nv50_graph_init_intr(struct drm_device *dev) --{ -- NV_DEBUG(dev, "\n"); -- -- nv_wr32(dev, NV03_PGRAPH_INTR, 0xffffffff); -- nv_wr32(dev, 0x400138, 0xffffffff); -- nv_wr32(dev, NV40_PGRAPH_INTR_EN, 0xffffffff); --} -- --static void --nv50_graph_init_regs__nv(struct drm_device *dev) -+static int -+nv50_graph_init(struct drm_device *dev, int engine) - { - struct drm_nouveau_private *dev_priv = dev->dev_private; -- uint32_t units = nv_rd32(dev, 0x1540); -+ struct nv50_graph_engine *pgraph = nv_engine(dev, engine); -+ u32 units = nv_rd32(dev, 0x001540); - int i; - - NV_DEBUG(dev, "\n"); - -+ /* master reset */ -+ nv_mask(dev, 0x000200, 0x00200100, 0x00000000); -+ nv_mask(dev, 0x000200, 0x00200100, 0x00200100); -+ nv_wr32(dev, 0x40008c, 0x00000004); /* HW_CTX_SWITCH_ENABLED */ -+ -+ /* reset/enable traps and interrupts */ - nv_wr32(dev, 0x400804, 0xc0000000); - nv_wr32(dev, 0x406800, 0xc0000000); - nv_wr32(dev, 0x400c04, 0xc0000000); - nv_wr32(dev, 0x401800, 0xc0000000); - nv_wr32(dev, 0x405018, 0xc0000000); - nv_wr32(dev, 0x402000, 0xc0000000); -- - for (i = 0; i < 16; i++) { -- if (units & 1 << i) { -- if (dev_priv->chipset < 0xa0) { -- nv_wr32(dev, 0x408900 + (i << 12), 0xc0000000); -- nv_wr32(dev, 0x408e08 + (i << 12), 0xc0000000); -- nv_wr32(dev, 0x408314 + (i << 12), 0xc0000000); -- } else { -- nv_wr32(dev, 0x408600 + (i << 11), 0xc0000000); -- nv_wr32(dev, 0x408708 + (i << 11), 0xc0000000); -- nv_wr32(dev, 0x40831c + (i << 11), 0xc0000000); -- } -+ if (!(units & (1 << i))) -+ continue; -+ -+ if (dev_priv->chipset < 0xa0) { -+ nv_wr32(dev, 0x408900 + (i << 12), 0xc0000000); -+ nv_wr32(dev, 0x408e08 + (i << 12), 0xc0000000); -+ nv_wr32(dev, 0x408314 + (i << 12), 0xc0000000); -+ } else { -+ nv_wr32(dev, 0x408600 + (i << 11), 0xc0000000); -+ nv_wr32(dev, 0x408708 + (i << 11), 0xc0000000); -+ nv_wr32(dev, 0x40831c + (i << 11), 0xc0000000); - } - } - - nv_wr32(dev, 0x400108, 0xffffffff); -- -- nv_wr32(dev, 0x400824, 0x00004000); -+ nv_wr32(dev, 0x400138, 0xffffffff); -+ nv_wr32(dev, 0x400100, 0xffffffff); -+ nv_wr32(dev, 0x40013c, 0xffffffff); - nv_wr32(dev, 0x400500, 0x00010001); --} -- --static void --nv50_graph_init_zcull(struct drm_device *dev) --{ -- struct drm_nouveau_private *dev_priv = dev->dev_private; -- int i; -- -- NV_DEBUG(dev, "\n"); - -+ /* upload context program, initialise ctxctl defaults */ -+ nv_wr32(dev, 0x400324, 0x00000000); -+ for (i = 0; i < pgraph->ctxprog_size; i++) -+ nv_wr32(dev, 0x400328, pgraph->ctxprog[i]); -+ nv_wr32(dev, 0x400824, 0x00000000); -+ nv_wr32(dev, 0x400828, 0x00000000); -+ nv_wr32(dev, 0x40082c, 0x00000000); -+ nv_wr32(dev, 0x400830, 0x00000000); -+ nv_wr32(dev, 0x400724, 0x00000000); -+ nv_wr32(dev, 0x40032c, 0x00000000); -+ nv_wr32(dev, 0x400320, 4); /* CTXCTL_CMD = NEWCTXDMA */ -+ -+ /* some unknown zcull magic */ - switch (dev_priv->chipset & 0xf0) { - case 0x50: - case 0x80: -@@ -212,43 +204,7 @@ nv50_graph_init_zcull(struct drm_device *dev) - nv_wr32(dev, 0x402c28 + (i * 8), 0x00000000); - nv_wr32(dev, 0x402c2c + (i * 8), 0x00000000); - } --} -- --static int --nv50_graph_init_ctxctl(struct drm_device *dev) --{ -- struct nv50_graph_engine *pgraph = nv_engine(dev, NVOBJ_ENGINE_GR); -- int i; -- -- NV_DEBUG(dev, "\n"); -- -- nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_INDEX, 0); -- for (i = 0; i < pgraph->ctxprog_size; i++) -- nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_DATA, pgraph->ctxprog[i]); -- -- nv_wr32(dev, 0x40008c, 0x00000004); /* HW_CTX_SWITCH_ENABLED */ -- nv_wr32(dev, 0x400320, 4); -- nv_wr32(dev, NV40_PGRAPH_CTXCTL_CUR, 0); -- nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_POINTER, 0); -- return 0; --} -- --static int --nv50_graph_init(struct drm_device *dev, int engine) --{ -- int ret; -- -- NV_DEBUG(dev, "\n"); -- -- nv50_graph_init_reset(dev); -- nv50_graph_init_regs__nv(dev); -- nv50_graph_init_zcull(dev); -- -- ret = nv50_graph_init_ctxctl(dev); -- if (ret) -- return ret; - -- nv50_graph_init_intr(dev); - return 0; - } - -diff --git a/drivers/gpu/drm/nouveau/nv50_grctx.c b/drivers/gpu/drm/nouveau/nv50_grctx.c -index de9abff..d05c2c3 100644 ---- a/drivers/gpu/drm/nouveau/nv50_grctx.c -+++ b/drivers/gpu/drm/nouveau/nv50_grctx.c -@@ -40,6 +40,12 @@ - #define CP_FLAG_UNK0B ((0 * 32) + 0xb) - #define CP_FLAG_UNK0B_CLEAR 0 - #define CP_FLAG_UNK0B_SET 1 -+#define CP_FLAG_XFER_SWITCH ((0 * 32) + 0xe) -+#define CP_FLAG_XFER_SWITCH_DISABLE 0 -+#define CP_FLAG_XFER_SWITCH_ENABLE 1 -+#define CP_FLAG_STATE ((0 * 32) + 0x1c) -+#define CP_FLAG_STATE_STOPPED 0 -+#define CP_FLAG_STATE_RUNNING 1 - #define CP_FLAG_UNK1D ((0 * 32) + 0x1d) - #define CP_FLAG_UNK1D_CLEAR 0 - #define CP_FLAG_UNK1D_SET 1 -@@ -194,6 +200,9 @@ nv50_grctx_init(struct nouveau_grctx *ctx) - "the devs.\n"); - return -ENOSYS; - } -+ -+ cp_set (ctx, STATE, RUNNING); -+ cp_set (ctx, XFER_SWITCH, ENABLE); - /* decide whether we're loading/unloading the context */ - cp_bra (ctx, AUTO_SAVE, PENDING, cp_setup_save); - cp_bra (ctx, USER_SAVE, PENDING, cp_setup_save); -@@ -260,6 +269,8 @@ nv50_grctx_init(struct nouveau_grctx *ctx) - cp_name(ctx, cp_exit); - cp_set (ctx, USER_SAVE, NOT_PENDING); - cp_set (ctx, USER_LOAD, NOT_PENDING); -+ cp_set (ctx, XFER_SWITCH, DISABLE); -+ cp_set (ctx, STATE, STOPPED); - cp_out (ctx, CP_END); - ctx->ctxvals_pos += 0x400; /* padding... no idea why you need it */ - -diff --git a/drivers/gpu/drm/nouveau/nv50_pm.c b/drivers/gpu/drm/nouveau/nv50_pm.c -index 8a28100..3d5a86b 100644 ---- a/drivers/gpu/drm/nouveau/nv50_pm.c -+++ b/drivers/gpu/drm/nouveau/nv50_pm.c -@@ -115,15 +115,15 @@ nv50_pm_clock_set(struct drm_device *dev, void *pre_state) - BIT_M.version == 1 && BIT_M.length >= 0x0b) { - script = ROM16(BIT_M.data[0x05]); - if (script) -- nouveau_bios_run_init_table(dev, script, NULL); -+ nouveau_bios_run_init_table(dev, script, NULL, -1); - script = ROM16(BIT_M.data[0x07]); - if (script) -- nouveau_bios_run_init_table(dev, script, NULL); -+ nouveau_bios_run_init_table(dev, script, NULL, -1); - script = ROM16(BIT_M.data[0x09]); - if (script) -- nouveau_bios_run_init_table(dev, script, NULL); -+ nouveau_bios_run_init_table(dev, script, NULL, -1); - -- nouveau_bios_run_init_table(dev, perflvl->memscript, NULL); -+ nouveau_bios_run_init_table(dev, perflvl->memscript, NULL, -1); - } - - if (state->type == PLL_MEMORY) { -diff --git a/drivers/gpu/drm/nouveau/nv50_sor.c b/drivers/gpu/drm/nouveau/nv50_sor.c -index ffe8b48..2633aa8 100644 ---- a/drivers/gpu/drm/nouveau/nv50_sor.c -+++ b/drivers/gpu/drm/nouveau/nv50_sor.c -@@ -124,7 +124,7 @@ nv50_sor_dpms(struct drm_encoder *encoder, int mode) - if (mode == DRM_MODE_DPMS_ON) { - u8 status = DP_SET_POWER_D0; - nouveau_dp_auxch(auxch, 8, DP_SET_POWER, &status, 1); -- nouveau_dp_link_train(encoder); -+ nouveau_dp_link_train(encoder, nv_encoder->dp.datarate); - } else { - u8 status = DP_SET_POWER_D3; - nouveau_dp_auxch(auxch, 8, DP_SET_POWER, &status, 1); -@@ -187,14 +187,13 @@ nv50_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, - struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); - struct drm_device *dev = encoder->dev; - struct nouveau_crtc *crtc = nouveau_crtc(encoder->crtc); -+ struct nouveau_connector *nv_connector; - uint32_t mode_ctl = 0; - int ret; - - NV_DEBUG_KMS(dev, "or %d type %d -> crtc %d\n", - nv_encoder->or, nv_encoder->dcb->type, crtc->index); - -- nv50_sor_dpms(encoder, DRM_MODE_DPMS_ON); -- - switch (nv_encoder->dcb->type) { - case OUTPUT_TMDS: - if (nv_encoder->dcb->sorconf.link & 1) { -@@ -206,7 +205,15 @@ nv50_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, - mode_ctl = 0x0200; - break; - case OUTPUT_DP: -- mode_ctl |= (nv_encoder->dp.mc_unknown << 16); -+ nv_connector = nouveau_encoder_connector_get(nv_encoder); -+ if (nv_connector && nv_connector->base.display_info.bpc == 6) { -+ nv_encoder->dp.datarate = crtc->mode->clock * 18 / 8; -+ mode_ctl |= 0x00020000; -+ } else { -+ nv_encoder->dp.datarate = crtc->mode->clock * 24 / 8; -+ mode_ctl |= 0x00050000; -+ } -+ - if (nv_encoder->dcb->sorconf.link & 1) - mode_ctl |= 0x00000800; - else -@@ -227,6 +234,8 @@ nv50_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, - if (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC) - mode_ctl |= NV50_EVO_SOR_MODE_CTRL_NVSYNC; - -+ nv50_sor_dpms(encoder, DRM_MODE_DPMS_ON); -+ - ret = RING_SPACE(evo, 2); - if (ret) { - NV_ERROR(dev, "no space while connecting SOR\n"); -@@ -313,31 +322,6 @@ nv50_sor_create(struct drm_connector *connector, struct dcb_entry *entry) - encoder->possible_crtcs = entry->heads; - encoder->possible_clones = 0; - -- if (nv_encoder->dcb->type == OUTPUT_DP) { -- int or = nv_encoder->or, link = !(entry->dpconf.sor.link & 1); -- uint32_t tmp; -- -- tmp = nv_rd32(dev, 0x61c700 + (or * 0x800)); -- if (!tmp) -- tmp = nv_rd32(dev, 0x610798 + (or * 8)); -- -- switch ((tmp & 0x00000f00) >> 8) { -- case 8: -- case 9: -- 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; -- default: -- break; -- } -- -- if (!nv_encoder->dp.mc_unknown) -- nv_encoder->dp.mc_unknown = 5; -- } -- - drm_mode_connector_attach_encoder(connector, encoder); - return 0; - } -diff --git a/drivers/gpu/drm/nouveau/nv50_vram.c b/drivers/gpu/drm/nouveau/nv50_vram.c -index af32dae..9da2383 100644 ---- a/drivers/gpu/drm/nouveau/nv50_vram.c -+++ b/drivers/gpu/drm/nouveau/nv50_vram.c -@@ -51,7 +51,7 @@ void - nv50_vram_del(struct drm_device *dev, struct nouveau_mem **pmem) - { - struct drm_nouveau_private *dev_priv = dev->dev_private; -- struct nouveau_mm *mm = dev_priv->engine.vram.mm; -+ struct nouveau_mm *mm = &dev_priv->engine.vram.mm; - struct nouveau_mm_node *this; - struct nouveau_mem *mem; - -@@ -82,7 +82,7 @@ nv50_vram_new(struct drm_device *dev, u64 size, u32 align, u32 size_nc, - u32 memtype, struct nouveau_mem **pmem) - { - struct drm_nouveau_private *dev_priv = dev->dev_private; -- struct nouveau_mm *mm = dev_priv->engine.vram.mm; -+ struct nouveau_mm *mm = &dev_priv->engine.vram.mm; - struct nouveau_mm_node *r; - struct nouveau_mem *mem; - int comp = (memtype & 0x300) >> 8; -diff --git a/drivers/gpu/drm/nouveau/nva3_pm.c b/drivers/gpu/drm/nouveau/nva3_pm.c -index e4b2b9e..618c144 100644 ---- a/drivers/gpu/drm/nouveau/nva3_pm.c -+++ b/drivers/gpu/drm/nouveau/nva3_pm.c -@@ -27,178 +27,316 @@ - #include "nouveau_bios.h" - #include "nouveau_pm.h" - --/* This is actually a lot more complex than it appears here, but hopefully -- * this should be able to deal with what the VBIOS leaves for us.. -- * -- * If not, well, I'll jump off that bridge when I come to it. -- */ -+static u32 read_clk(struct drm_device *, int, bool); -+static u32 read_pll(struct drm_device *, int, u32); - --struct nva3_pm_state { -- enum pll_types type; -- u32 src0; -- u32 src1; -- u32 ctrl; -- u32 coef; -- u32 old_pnm; -- u32 new_pnm; -- u32 new_div; --}; -+static u32 -+read_vco(struct drm_device *dev, int clk) -+{ -+ u32 sctl = nv_rd32(dev, 0x4120 + (clk * 4)); -+ if ((sctl & 0x00000030) != 0x00000030) -+ return read_pll(dev, 0x41, 0x00e820); -+ return read_pll(dev, 0x42, 0x00e8a0); -+} - --static int --nva3_pm_pll_offset(u32 id) -+static u32 -+read_clk(struct drm_device *dev, int clk, bool ignore_en) - { -- static const u32 pll_map[] = { -- 0x00, PLL_CORE, -- 0x01, PLL_SHADER, -- 0x02, PLL_MEMORY, -- 0x00, 0x00 -- }; -- const u32 *map = pll_map; -- -- while (map[1]) { -- if (id == map[1]) -- return map[0]; -- map += 2; -+ struct drm_nouveau_private *dev_priv = dev->dev_private; -+ u32 sctl, sdiv, sclk; -+ -+ /* refclk for the 0xe8xx plls is a fixed frequency */ -+ if (clk >= 0x40) { -+ if (dev_priv->chipset == 0xaf) { -+ /* no joke.. seriously.. sigh.. */ -+ return nv_rd32(dev, 0x00471c) * 1000; -+ } -+ -+ return dev_priv->crystal; - } - -- return -ENOENT; -+ sctl = nv_rd32(dev, 0x4120 + (clk * 4)); -+ if (!ignore_en && !(sctl & 0x00000100)) -+ return 0; -+ -+ switch (sctl & 0x00003000) { -+ case 0x00000000: -+ return dev_priv->crystal; -+ case 0x00002000: -+ if (sctl & 0x00000040) -+ return 108000; -+ return 100000; -+ case 0x00003000: -+ sclk = read_vco(dev, clk); -+ sdiv = ((sctl & 0x003f0000) >> 16) + 2; -+ return (sclk * 2) / sdiv; -+ default: -+ return 0; -+ } - } - --int --nva3_pm_clock_get(struct drm_device *dev, u32 id) -+static u32 -+read_pll(struct drm_device *dev, int clk, u32 pll) -+{ -+ u32 ctrl = nv_rd32(dev, pll + 0); -+ u32 sclk = 0, P = 1, N = 1, M = 1; -+ -+ if (!(ctrl & 0x00000008)) { -+ if (ctrl & 0x00000001) { -+ u32 coef = nv_rd32(dev, pll + 4); -+ M = (coef & 0x000000ff) >> 0; -+ N = (coef & 0x0000ff00) >> 8; -+ P = (coef & 0x003f0000) >> 16; -+ -+ /* no post-divider on these.. */ -+ if ((pll & 0x00ff00) == 0x00e800) -+ P = 1; -+ -+ sclk = read_clk(dev, 0x00 + clk, false); -+ } -+ } else { -+ sclk = read_clk(dev, 0x10 + clk, false); -+ } -+ -+ return sclk * N / (M * P); -+} -+ -+struct creg { -+ u32 clk; -+ u32 pll; -+}; -+ -+static int -+calc_clk(struct drm_device *dev, int clk, u32 pll, u32 khz, struct creg *reg) - { -- u32 src0, src1, ctrl, coef; -- struct pll_lims pll; -- int ret, off; -- int P, N, M; -+ struct pll_lims limits; -+ u32 oclk, sclk, sdiv; -+ int P, N, M, diff; -+ int ret; -+ -+ reg->pll = 0; -+ reg->clk = 0; -+ if (!khz) { -+ NV_DEBUG(dev, "no clock for 0x%04x/0x%02x\n", pll, clk); -+ return 0; -+ } - -- ret = get_pll_limits(dev, id, &pll); -+ switch (khz) { -+ case 27000: -+ reg->clk = 0x00000100; -+ return khz; -+ case 100000: -+ reg->clk = 0x00002100; -+ return khz; -+ case 108000: -+ reg->clk = 0x00002140; -+ return khz; -+ default: -+ sclk = read_vco(dev, clk); -+ sdiv = min((sclk * 2) / (khz - 2999), (u32)65); -+ /* if the clock has a PLL attached, and we can get a within -+ * [-2, 3) MHz of a divider, we'll disable the PLL and use -+ * the divider instead. -+ * -+ * divider can go as low as 2, limited here because NVIDIA -+ * and the VBIOS on my NVA8 seem to prefer using the PLL -+ * for 810MHz - is there a good reason? -+ */ -+ if (sdiv > 4) { -+ oclk = (sclk * 2) / sdiv; -+ diff = khz - oclk; -+ if (!pll || (diff >= -2000 && diff < 3000)) { -+ reg->clk = (((sdiv - 2) << 16) | 0x00003100); -+ return oclk; -+ } -+ } -+ -+ if (!pll) { -+ NV_ERROR(dev, "bad freq %02x: %d %d\n", clk, khz, sclk); -+ return -ERANGE; -+ } -+ -+ break; -+ } -+ -+ ret = get_pll_limits(dev, pll, &limits); - if (ret) - return ret; - -- off = nva3_pm_pll_offset(id); -- if (off < 0) -- return off; -+ limits.refclk = read_clk(dev, clk - 0x10, true); -+ if (!limits.refclk) -+ return -EINVAL; -+ -+ ret = nva3_calc_pll(dev, &limits, khz, &N, NULL, &M, &P); -+ if (ret >= 0) { -+ reg->clk = nv_rd32(dev, 0x4120 + (clk * 4)); -+ reg->pll = (P << 16) | (N << 8) | M; -+ } -+ return ret; -+} -+ -+static void -+prog_pll(struct drm_device *dev, int clk, u32 pll, struct creg *reg) -+{ -+ const u32 src0 = 0x004120 + (clk * 4); -+ const u32 src1 = 0x004160 + (clk * 4); -+ const u32 ctrl = pll + 0; -+ const u32 coef = pll + 4; -+ u32 cntl; -+ -+ if (!reg->clk && !reg->pll) { -+ NV_DEBUG(dev, "no clock for %02x\n", clk); -+ return; -+ } - -- src0 = nv_rd32(dev, 0x4120 + (off * 4)); -- src1 = nv_rd32(dev, 0x4160 + (off * 4)); -- ctrl = nv_rd32(dev, pll.reg + 0); -- coef = nv_rd32(dev, pll.reg + 4); -- NV_DEBUG(dev, "PLL %02x: 0x%08x 0x%08x 0x%08x 0x%08x\n", -- id, src0, src1, ctrl, coef); -+ cntl = nv_rd32(dev, ctrl) & 0xfffffff2; -+ if (reg->pll) { -+ nv_mask(dev, src0, 0x00000101, 0x00000101); -+ nv_wr32(dev, coef, reg->pll); -+ nv_wr32(dev, ctrl, cntl | 0x00000015); -+ nv_mask(dev, src1, 0x00000100, 0x00000000); -+ nv_mask(dev, src1, 0x00000001, 0x00000000); -+ } else { -+ nv_mask(dev, src1, 0x003f3141, 0x00000101 | reg->clk); -+ nv_wr32(dev, ctrl, cntl | 0x0000001d); -+ nv_mask(dev, ctrl, 0x00000001, 0x00000000); -+ nv_mask(dev, src0, 0x00000100, 0x00000000); -+ nv_mask(dev, src0, 0x00000001, 0x00000000); -+ } -+} - -- if (ctrl & 0x00000008) { -- u32 div = ((src1 & 0x003c0000) >> 18) + 1; -- return (pll.refclk * 2) / div; -+static void -+prog_clk(struct drm_device *dev, int clk, struct creg *reg) -+{ -+ if (!reg->clk) { -+ NV_DEBUG(dev, "no clock for %02x\n", clk); -+ return; - } - -- P = (coef & 0x003f0000) >> 16; -- N = (coef & 0x0000ff00) >> 8; -- M = (coef & 0x000000ff); -- return pll.refclk * N / M / P; -+ nv_mask(dev, 0x004120 + (clk * 4), 0x003f3141, 0x00000101 | reg->clk); -+} -+ -+int -+nva3_pm_clocks_get(struct drm_device *dev, struct nouveau_pm_level *perflvl) -+{ -+ perflvl->core = read_pll(dev, 0x00, 0x4200); -+ perflvl->shader = read_pll(dev, 0x01, 0x4220); -+ perflvl->memory = read_pll(dev, 0x02, 0x4000); -+ perflvl->unka0 = read_clk(dev, 0x20, false); -+ perflvl->vdec = read_clk(dev, 0x21, false); -+ perflvl->daemon = read_clk(dev, 0x25, false); -+ perflvl->copy = perflvl->core; -+ return 0; - } - -+struct nva3_pm_state { -+ struct creg nclk; -+ struct creg sclk; -+ struct creg mclk; -+ struct creg vdec; -+ struct creg unka0; -+}; -+ - void * --nva3_pm_clock_pre(struct drm_device *dev, struct nouveau_pm_level *perflvl, -- u32 id, int khz) -+nva3_pm_clocks_pre(struct drm_device *dev, struct nouveau_pm_level *perflvl) - { -- struct nva3_pm_state *pll; -- struct pll_lims limits; -- int N, M, P, diff; -- int ret, off; -+ struct nva3_pm_state *info; -+ int ret; - -- ret = get_pll_limits(dev, id, &limits); -+ info = kzalloc(sizeof(*info), GFP_KERNEL); -+ if (!info) -+ return ERR_PTR(-ENOMEM); -+ -+ ret = calc_clk(dev, 0x10, 0x4200, perflvl->core, &info->nclk); - if (ret < 0) -- return (ret == -ENOENT) ? NULL : ERR_PTR(ret); -+ goto out; - -- off = nva3_pm_pll_offset(id); -- if (id < 0) -- return ERR_PTR(-EINVAL); -+ ret = calc_clk(dev, 0x11, 0x4220, perflvl->shader, &info->sclk); -+ if (ret < 0) -+ goto out; - -+ ret = calc_clk(dev, 0x12, 0x4000, perflvl->memory, &info->mclk); -+ if (ret < 0) -+ goto out; - -- pll = kzalloc(sizeof(*pll), GFP_KERNEL); -- if (!pll) -- return ERR_PTR(-ENOMEM); -- pll->type = id; -- pll->src0 = 0x004120 + (off * 4); -- pll->src1 = 0x004160 + (off * 4); -- pll->ctrl = limits.reg + 0; -- pll->coef = limits.reg + 4; -- -- /* If target clock is within [-2, 3) MHz of a divisor, we'll -- * use that instead of calculating MNP values -- */ -- pll->new_div = min((limits.refclk * 2) / (khz - 2999), 16); -- if (pll->new_div) { -- diff = khz - ((limits.refclk * 2) / pll->new_div); -- if (diff < -2000 || diff >= 3000) -- pll->new_div = 0; -- } -+ ret = calc_clk(dev, 0x20, 0x0000, perflvl->unka0, &info->unka0); -+ if (ret < 0) -+ goto out; - -- if (!pll->new_div) { -- ret = nva3_calc_pll(dev, &limits, khz, &N, NULL, &M, &P); -- if (ret < 0) -- return ERR_PTR(ret); -+ ret = calc_clk(dev, 0x21, 0x0000, perflvl->vdec, &info->vdec); -+ if (ret < 0) -+ goto out; - -- pll->new_pnm = (P << 16) | (N << 8) | M; -- pll->new_div = 2 - 1; -- } else { -- pll->new_pnm = 0; -- pll->new_div--; -+out: -+ if (ret < 0) { -+ kfree(info); -+ info = ERR_PTR(ret); - } -+ return info; -+} -+ -+static bool -+nva3_pm_grcp_idle(void *data) -+{ -+ struct drm_device *dev = data; - -- if ((nv_rd32(dev, pll->src1) & 0x00000101) != 0x00000101) -- pll->old_pnm = nv_rd32(dev, pll->coef); -- return pll; -+ if (!(nv_rd32(dev, 0x400304) & 0x00000001)) -+ return true; -+ if (nv_rd32(dev, 0x400308) == 0x0050001c) -+ return true; -+ return false; - } - - void --nva3_pm_clock_set(struct drm_device *dev, void *pre_state) -+nva3_pm_clocks_set(struct drm_device *dev, void *pre_state) - { -- struct nva3_pm_state *pll = pre_state; -- u32 ctrl = 0; -+ struct drm_nouveau_private *dev_priv = dev->dev_private; -+ struct nva3_pm_state *info = pre_state; -+ unsigned long flags; - -- /* For the memory clock, NVIDIA will build a "script" describing -- * the reclocking process and ask PDAEMON to execute it. -- */ -- if (pll->type == PLL_MEMORY) { -- nv_wr32(dev, 0x100210, 0); -- nv_wr32(dev, 0x1002dc, 1); -- nv_wr32(dev, 0x004018, 0x00001000); -- ctrl = 0x18000100; -+ /* prevent any new grctx switches from starting */ -+ spin_lock_irqsave(&dev_priv->context_switch_lock, flags); -+ nv_wr32(dev, 0x400324, 0x00000000); -+ nv_wr32(dev, 0x400328, 0x0050001c); /* wait flag 0x1c */ -+ /* wait for any pending grctx switches to complete */ -+ if (!nv_wait_cb(dev, nva3_pm_grcp_idle, dev)) { -+ NV_ERROR(dev, "pm: ctxprog didn't go idle\n"); -+ goto cleanup; - } -- -- if (pll->old_pnm || !pll->new_pnm) { -- nv_mask(dev, pll->src1, 0x003c0101, 0x00000101 | -- (pll->new_div << 18)); -- nv_wr32(dev, pll->ctrl, 0x0001001d | ctrl); -- nv_mask(dev, pll->ctrl, 0x00000001, 0x00000000); -+ /* freeze PFIFO */ -+ nv_mask(dev, 0x002504, 0x00000001, 0x00000001); -+ if (!nv_wait(dev, 0x002504, 0x00000010, 0x00000010)) { -+ NV_ERROR(dev, "pm: fifo didn't go idle\n"); -+ goto cleanup; - } - -- if (pll->new_pnm) { -- nv_mask(dev, pll->src0, 0x00000101, 0x00000101); -- nv_wr32(dev, pll->coef, pll->new_pnm); -- nv_wr32(dev, pll->ctrl, 0x0001001d | ctrl); -- nv_mask(dev, pll->ctrl, 0x00000010, 0x00000000); -- nv_mask(dev, pll->ctrl, 0x00020010, 0x00020010); -- nv_wr32(dev, pll->ctrl, 0x00010015 | ctrl); -- nv_mask(dev, pll->src1, 0x00000100, 0x00000000); -- nv_mask(dev, pll->src1, 0x00000001, 0x00000000); -- if (pll->type == PLL_MEMORY) -- nv_wr32(dev, 0x4018, 0x10005000); -- } else { -- nv_mask(dev, pll->ctrl, 0x00000001, 0x00000000); -- nv_mask(dev, pll->src0, 0x00000100, 0x00000000); -- nv_mask(dev, pll->src0, 0x00000001, 0x00000000); -- if (pll->type == PLL_MEMORY) -- nv_wr32(dev, 0x4018, 0x1000d000); -- } -+ prog_pll(dev, 0x00, 0x004200, &info->nclk); -+ prog_pll(dev, 0x01, 0x004220, &info->sclk); -+ prog_clk(dev, 0x20, &info->unka0); -+ prog_clk(dev, 0x21, &info->vdec); - -- if (pll->type == PLL_MEMORY) { -+ if (info->mclk.clk || info->mclk.pll) { -+ nv_wr32(dev, 0x100210, 0); -+ nv_wr32(dev, 0x1002dc, 1); -+ nv_wr32(dev, 0x004018, 0x00001000); -+ prog_pll(dev, 0x02, 0x004000, &info->mclk); -+ if (nv_rd32(dev, 0x4000) & 0x00000008) -+ nv_wr32(dev, 0x004018, 0x1000d000); -+ else -+ nv_wr32(dev, 0x004018, 0x10005000); - nv_wr32(dev, 0x1002dc, 0); - nv_wr32(dev, 0x100210, 0x80000000); - } - -- kfree(pll); -+cleanup: -+ /* unfreeze PFIFO */ -+ nv_mask(dev, 0x002504, 0x00000001, 0x00000000); -+ /* restore ctxprog to normal */ -+ nv_wr32(dev, 0x400324, 0x00000000); -+ nv_wr32(dev, 0x400328, 0x0070009c); /* set flag 0x1c */ -+ /* unblock it if necessary */ -+ if (nv_rd32(dev, 0x400308) == 0x0050001c) -+ nv_mask(dev, 0x400824, 0x10000000, 0x10000000); -+ spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); -+ kfree(info); - } -- -diff --git a/drivers/gpu/drm/nouveau/nvc0_fb.c b/drivers/gpu/drm/nouveau/nvc0_fb.c -index 08e6b11..5bf5503 100644 ---- a/drivers/gpu/drm/nouveau/nvc0_fb.c -+++ b/drivers/gpu/drm/nouveau/nvc0_fb.c -@@ -32,6 +32,30 @@ struct nvc0_fb_priv { - dma_addr_t r100c10; - }; - -+static inline void -+nvc0_mfb_subp_isr(struct drm_device *dev, int unit, int subp) -+{ -+ u32 subp_base = 0x141000 + (unit * 0x2000) + (subp * 0x400); -+ u32 stat = nv_rd32(dev, subp_base + 0x020); -+ -+ if (stat) { -+ NV_INFO(dev, "PMFB%d_SUBP%d: 0x%08x\n", unit, subp, stat); -+ nv_wr32(dev, subp_base + 0x020, stat); -+ } -+} -+ -+static void -+nvc0_mfb_isr(struct drm_device *dev) -+{ -+ u32 units = nv_rd32(dev, 0x00017c); -+ while (units) { -+ u32 subp, unit = ffs(units) - 1; -+ for (subp = 0; subp < 2; subp++) -+ nvc0_mfb_subp_isr(dev, unit, subp); -+ units &= ~(1 << unit); -+ } -+} -+ - static void - nvc0_fb_destroy(struct drm_device *dev) - { -@@ -39,6 +63,8 @@ nvc0_fb_destroy(struct drm_device *dev) - struct nouveau_fb_engine *pfb = &dev_priv->engine.fb; - struct nvc0_fb_priv *priv = pfb->priv; - -+ nouveau_irq_unregister(dev, 25); -+ - if (priv->r100c10_page) { - pci_unmap_page(dev->pdev, priv->r100c10, PAGE_SIZE, - PCI_DMA_BIDIRECTIONAL); -@@ -74,6 +100,7 @@ nvc0_fb_create(struct drm_device *dev) - return -EFAULT; - } - -+ nouveau_irq_register(dev, 25, nvc0_mfb_isr); - return 0; - } - -diff --git a/drivers/gpu/drm/nouveau/nvc0_fifo.c b/drivers/gpu/drm/nouveau/nvc0_fifo.c -index 6f9f341..dcbe0d5 100644 ---- a/drivers/gpu/drm/nouveau/nvc0_fifo.c -+++ b/drivers/gpu/drm/nouveau/nvc0_fifo.c -@@ -322,7 +322,7 @@ nvc0_fifo_init(struct drm_device *dev) - } - - /* PSUBFIFO[n] */ -- for (i = 0; i < 3; i++) { -+ for (i = 0; i < priv->spoon_nr; i++) { - nv_mask(dev, 0x04013c + (i * 0x2000), 0x10000100, 0x00000000); - nv_wr32(dev, 0x040108 + (i * 0x2000), 0xffffffff); /* INTR */ - nv_wr32(dev, 0x04010c + (i * 0x2000), 0xfffffeff); /* INTR_EN */ -diff --git a/drivers/gpu/drm/nouveau/nvc0_graph.c b/drivers/gpu/drm/nouveau/nvc0_graph.c -index 5b2f6f4..4b8d0b3 100644 ---- a/drivers/gpu/drm/nouveau/nvc0_graph.c -+++ b/drivers/gpu/drm/nouveau/nvc0_graph.c -@@ -390,7 +390,7 @@ nvc0_graph_init_gpc_0(struct drm_device *dev) - } - - nv_wr32(dev, GPC_BCAST(0x1bd4), magicgpc918); -- nv_wr32(dev, GPC_BCAST(0x08ac), priv->rop_nr); -+ nv_wr32(dev, GPC_BCAST(0x08ac), nv_rd32(dev, 0x100800)); - } - - static void -@@ -700,22 +700,6 @@ nvc0_graph_isr(struct drm_device *dev) - nv_wr32(dev, 0x400500, 0x00010001); - } - --static void --nvc0_runk140_isr(struct drm_device *dev) --{ -- u32 units = nv_rd32(dev, 0x00017c) & 0x1f; -- -- while (units) { -- u32 unit = ffs(units) - 1; -- u32 reg = 0x140000 + unit * 0x2000; -- u32 st0 = nv_mask(dev, reg + 0x1020, 0, 0); -- u32 st1 = nv_mask(dev, reg + 0x1420, 0, 0); -- -- NV_DEBUG(dev, "PRUNK140: %d 0x%08x 0x%08x\n", unit, st0, st1); -- units &= ~(1 << unit); -- } --} -- - static int - nvc0_graph_create_fw(struct drm_device *dev, const char *fwname, - struct nvc0_graph_fuc *fuc) -@@ -764,7 +748,6 @@ nvc0_graph_destroy(struct drm_device *dev, int engine) - } - - nouveau_irq_unregister(dev, 12); -- nouveau_irq_unregister(dev, 25); - - nouveau_gpuobj_ref(NULL, &priv->unk4188b8); - nouveau_gpuobj_ref(NULL, &priv->unk4188b4); -@@ -803,7 +786,6 @@ nvc0_graph_create(struct drm_device *dev) - - NVOBJ_ENGINE_ADD(dev, GR, &priv->base); - nouveau_irq_register(dev, 12, nvc0_graph_isr); -- nouveau_irq_register(dev, 25, nvc0_runk140_isr); - - if (nouveau_ctxfw) { - NV_INFO(dev, "PGRAPH: using external firmware\n"); -@@ -864,6 +846,9 @@ nvc0_graph_create(struct drm_device *dev) - case 0xce: /* 4/4/0/0, 4 */ - priv->magic_not_rop_nr = 0x03; - break; -+ case 0xcf: /* 4/0/0/0, 3 */ -+ priv->magic_not_rop_nr = 0x03; -+ break; - } - - if (!priv->magic_not_rop_nr) { -@@ -889,20 +874,3 @@ error: - nvc0_graph_destroy(dev, NVOBJ_ENGINE_GR); - return ret; - } -- --MODULE_FIRMWARE("nouveau/nvc0_fuc409c"); --MODULE_FIRMWARE("nouveau/nvc0_fuc409d"); --MODULE_FIRMWARE("nouveau/nvc0_fuc41ac"); --MODULE_FIRMWARE("nouveau/nvc0_fuc41ad"); --MODULE_FIRMWARE("nouveau/nvc3_fuc409c"); --MODULE_FIRMWARE("nouveau/nvc3_fuc409d"); --MODULE_FIRMWARE("nouveau/nvc3_fuc41ac"); --MODULE_FIRMWARE("nouveau/nvc3_fuc41ad"); --MODULE_FIRMWARE("nouveau/nvc4_fuc409c"); --MODULE_FIRMWARE("nouveau/nvc4_fuc409d"); --MODULE_FIRMWARE("nouveau/nvc4_fuc41ac"); --MODULE_FIRMWARE("nouveau/nvc4_fuc41ad"); --MODULE_FIRMWARE("nouveau/fuc409c"); --MODULE_FIRMWARE("nouveau/fuc409d"); --MODULE_FIRMWARE("nouveau/fuc41ac"); --MODULE_FIRMWARE("nouveau/fuc41ad"); -diff --git a/drivers/gpu/drm/nouveau/nvc0_graph.h b/drivers/gpu/drm/nouveau/nvc0_graph.h -index 55689e9..636fe98 100644 ---- a/drivers/gpu/drm/nouveau/nvc0_graph.h -+++ b/drivers/gpu/drm/nouveau/nvc0_graph.h -@@ -82,6 +82,7 @@ nvc0_graph_class(struct drm_device *dev) - case 0xc3: - case 0xc4: - case 0xce: /* guess, mmio trace shows only 0x9097 state */ -+ case 0xcf: /* guess, mmio trace shows only 0x9097 state */ - return 0x9097; - case 0xc1: - return 0x9197; -diff --git a/drivers/gpu/drm/nouveau/nvc0_grctx.c b/drivers/gpu/drm/nouveau/nvc0_grctx.c -index 31018ea..dd0e6a7 100644 ---- a/drivers/gpu/drm/nouveau/nvc0_grctx.c -+++ b/drivers/gpu/drm/nouveau/nvc0_grctx.c -@@ -1678,7 +1678,10 @@ nvc0_grctx_generate_tp(struct drm_device *dev) - nv_wr32(dev, 0x419c04, 0x00000006); - nv_wr32(dev, 0x419c08, 0x00000002); - nv_wr32(dev, 0x419c20, 0x00000000); -- nv_wr32(dev, 0x419cb0, 0x00060048); //XXX: 0xce 0x00020048 -+ if (chipset == 0xce || chipset == 0xcf) -+ nv_wr32(dev, 0x419cb0, 0x00020048); -+ else -+ nv_wr32(dev, 0x419cb0, 0x00060048); - nv_wr32(dev, 0x419ce8, 0x00000000); - nv_wr32(dev, 0x419cf4, 0x00000183); - nv_wr32(dev, 0x419d20, chipset != 0xc1 ? 0x02180000 : 0x12180000); -@@ -1783,11 +1786,7 @@ nvc0_grctx_generate(struct nouveau_channel *chan) - nv_wr32(dev, 0x40587c, 0x00000000); - - if (1) { -- const u8 chipset_tp_max[] = { 16, 4, 0, 4, 8, 0, 0, 0, -- 16, 0, 0, 0, 0, 0, 8, 0 }; -- u8 max = chipset_tp_max[dev_priv->chipset & 0x0f]; -- u8 tpnr[GPC_MAX]; -- u8 data[TP_MAX]; -+ u8 tpnr[GPC_MAX], data[TP_MAX]; - - memcpy(tpnr, priv->tp_nr, sizeof(priv->tp_nr)); - memset(data, 0x1f, sizeof(data)); -@@ -1801,7 +1800,7 @@ nvc0_grctx_generate(struct nouveau_channel *chan) - data[tp] = gpc; - } - -- for (i = 0; i < max / 4; i++) -+ for (i = 0; i < 4; i++) - nv_wr32(dev, 0x4060a8 + (i * 4), ((u32 *)data)[i]); - } - -diff --git a/drivers/gpu/drm/nouveau/nvc0_grgpc.fuc b/drivers/gpu/drm/nouveau/nvc0_grgpc.fuc -index 0ec2add..06f5e26 100644 ---- a/drivers/gpu/drm/nouveau/nvc0_grgpc.fuc -+++ b/drivers/gpu/drm/nouveau/nvc0_grgpc.fuc -@@ -77,6 +77,11 @@ chipsets: - .b16 nvc0_gpc_mmio_tail - .b16 nvc0_tpc_mmio_head - .b16 nvc3_tpc_mmio_tail -+.b8 0xcf 0 0 0 -+.b16 nvc0_gpc_mmio_head -+.b16 nvc0_gpc_mmio_tail -+.b16 nvc0_tpc_mmio_head -+.b16 nvcf_tpc_mmio_tail - .b8 0 0 0 0 - - // GPC mmio lists -@@ -134,8 +139,9 @@ mmctx_data(0x000750, 2) - nvc0_tpc_mmio_tail: - mmctx_data(0x000758, 1) - mmctx_data(0x0002c4, 1) --mmctx_data(0x0004bc, 1) - mmctx_data(0x0006e0, 1) -+nvcf_tpc_mmio_tail: -+mmctx_data(0x0004bc, 1) - nvc3_tpc_mmio_tail: - mmctx_data(0x000544, 1) - nvc1_tpc_mmio_tail: -diff --git a/drivers/gpu/drm/nouveau/nvc0_grgpc.fuc.h b/drivers/gpu/drm/nouveau/nvc0_grgpc.fuc.h -index 1896c89..6f82032 100644 ---- a/drivers/gpu/drm/nouveau/nvc0_grgpc.fuc.h -+++ b/drivers/gpu/drm/nouveau/nvc0_grgpc.fuc.h -@@ -25,23 +25,26 @@ uint32_t nvc0_grgpc_data[] = { - 0x00000000, - 0x00000000, - 0x000000c0, -- 0x011000b0, -- 0x01640114, -+ 0x011c00bc, -+ 0x01700120, - 0x000000c1, -- 0x011400b0, -- 0x01780114, -+ 0x012000bc, -+ 0x01840120, - 0x000000c3, -- 0x011000b0, -- 0x01740114, -+ 0x011c00bc, -+ 0x01800120, - 0x000000c4, -- 0x011000b0, -- 0x01740114, -+ 0x011c00bc, -+ 0x01800120, - 0x000000c8, -- 0x011000b0, -- 0x01640114, -+ 0x011c00bc, -+ 0x01700120, - 0x000000ce, -- 0x011000b0, -- 0x01740114, -+ 0x011c00bc, -+ 0x01800120, -+ 0x000000cf, -+ 0x011c00bc, -+ 0x017c0120, - 0x00000000, - 0x00000380, - 0x14000400, -@@ -90,8 +93,8 @@ uint32_t nvc0_grgpc_data[] = { - 0x04000750, - 0x00000758, - 0x000002c4, -- 0x000004bc, - 0x000006e0, -+ 0x000004bc, - 0x00000544, - }; - -diff --git a/drivers/gpu/drm/nouveau/nvc0_grhub.fuc b/drivers/gpu/drm/nouveau/nvc0_grhub.fuc -index a1a5991..e4f8c7e 100644 ---- a/drivers/gpu/drm/nouveau/nvc0_grhub.fuc -+++ b/drivers/gpu/drm/nouveau/nvc0_grhub.fuc -@@ -56,6 +56,9 @@ chipsets: - .b8 0xce 0 0 0 - .b16 nvc0_hub_mmio_head - .b16 nvc0_hub_mmio_tail -+.b8 0xcf 0 0 0 -+.b16 nvc0_hub_mmio_head -+.b16 nvc0_hub_mmio_tail - .b8 0 0 0 0 - - nvc0_hub_mmio_head: -diff --git a/drivers/gpu/drm/nouveau/nvc0_grhub.fuc.h b/drivers/gpu/drm/nouveau/nvc0_grhub.fuc.h -index b3b541b..241d326 100644 ---- a/drivers/gpu/drm/nouveau/nvc0_grhub.fuc.h -+++ b/drivers/gpu/drm/nouveau/nvc0_grhub.fuc.h -@@ -23,17 +23,19 @@ uint32_t nvc0_grhub_data[] = { - 0x00000000, - 0x00000000, - 0x000000c0, -- 0x012c0090, -+ 0x01340098, - 0x000000c1, -- 0x01300090, -+ 0x01380098, - 0x000000c3, -- 0x012c0090, -+ 0x01340098, - 0x000000c4, -- 0x012c0090, -+ 0x01340098, - 0x000000c8, -- 0x012c0090, -+ 0x01340098, - 0x000000ce, -- 0x012c0090, -+ 0x01340098, -+ 0x000000cf, -+ 0x01340098, - 0x00000000, - 0x0417e91c, - 0x04400204, -@@ -190,8 +192,6 @@ uint32_t nvc0_grhub_data[] = { - 0x00000000, - 0x00000000, - 0x00000000, -- 0x00000000, -- 0x00000000, - }; - - uint32_t nvc0_grhub_code[] = { -diff --git a/drivers/gpu/drm/nouveau/nvc0_pm.c b/drivers/gpu/drm/nouveau/nvc0_pm.c -new file mode 100644 -index 0000000..929aded ---- /dev/null -+++ b/drivers/gpu/drm/nouveau/nvc0_pm.c -@@ -0,0 +1,155 @@ -+/* -+ * Copyright 2011 Red Hat Inc. -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a -+ * copy of this software and associated documentation files (the "Software"), -+ * to deal in the Software without restriction, including without limitation -+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, -+ * and/or sell copies of the Software, and to permit persons to whom the -+ * Software is furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR -+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -+ * OTHER DEALINGS IN THE SOFTWARE. -+ * -+ * Authors: Ben Skeggs -+ */ -+ -+#include "drmP.h" -+#include "nouveau_drv.h" -+#include "nouveau_bios.h" -+#include "nouveau_pm.h" -+ -+static u32 read_div(struct drm_device *, int, u32, u32); -+static u32 read_pll(struct drm_device *, u32); -+ -+static u32 -+read_vco(struct drm_device *dev, u32 dsrc) -+{ -+ u32 ssrc = nv_rd32(dev, dsrc); -+ if (!(ssrc & 0x00000100)) -+ return read_pll(dev, 0x00e800); -+ return read_pll(dev, 0x00e820); -+} -+ -+static u32 -+read_pll(struct drm_device *dev, u32 pll) -+{ -+ u32 ctrl = nv_rd32(dev, pll + 0); -+ u32 coef = nv_rd32(dev, pll + 4); -+ u32 P = (coef & 0x003f0000) >> 16; -+ u32 N = (coef & 0x0000ff00) >> 8; -+ u32 M = (coef & 0x000000ff) >> 0; -+ u32 sclk, doff; -+ -+ if (!(ctrl & 0x00000001)) -+ return 0; -+ -+ switch (pll & 0xfff000) { -+ case 0x00e000: -+ sclk = 27000; -+ P = 1; -+ break; -+ case 0x137000: -+ doff = (pll - 0x137000) / 0x20; -+ sclk = read_div(dev, doff, 0x137120, 0x137140); -+ break; -+ case 0x132000: -+ switch (pll) { -+ case 0x132000: -+ sclk = read_pll(dev, 0x132020); -+ break; -+ case 0x132020: -+ sclk = read_div(dev, 0, 0x137320, 0x137330); -+ break; -+ default: -+ return 0; -+ } -+ break; -+ default: -+ return 0; -+ } -+ -+ return sclk * N / M / P; -+} -+ -+static u32 -+read_div(struct drm_device *dev, int doff, u32 dsrc, u32 dctl) -+{ -+ u32 ssrc = nv_rd32(dev, dsrc + (doff * 4)); -+ u32 sctl = nv_rd32(dev, dctl + (doff * 4)); -+ -+ switch (ssrc & 0x00000003) { -+ case 0: -+ if ((ssrc & 0x00030000) != 0x00030000) -+ return 27000; -+ return 108000; -+ case 2: -+ return 100000; -+ case 3: -+ if (sctl & 0x80000000) { -+ u32 sclk = read_vco(dev, dsrc + (doff * 4)); -+ u32 sdiv = (sctl & 0x0000003f) + 2; -+ return (sclk * 2) / sdiv; -+ } -+ -+ return read_vco(dev, dsrc + (doff * 4)); -+ default: -+ return 0; -+ } -+} -+ -+static u32 -+read_mem(struct drm_device *dev) -+{ -+ u32 ssel = nv_rd32(dev, 0x1373f0); -+ if (ssel & 0x00000001) -+ return read_div(dev, 0, 0x137300, 0x137310); -+ return read_pll(dev, 0x132000); -+} -+ -+static u32 -+read_clk(struct drm_device *dev, int clk) -+{ -+ u32 sctl = nv_rd32(dev, 0x137250 + (clk * 4)); -+ u32 ssel = nv_rd32(dev, 0x137100); -+ u32 sclk, sdiv; -+ -+ if (ssel & (1 << clk)) { -+ if (clk < 7) -+ sclk = read_pll(dev, 0x137000 + (clk * 0x20)); -+ else -+ sclk = read_pll(dev, 0x1370e0); -+ sdiv = ((sctl & 0x00003f00) >> 8) + 2; -+ } else { -+ sclk = read_div(dev, clk, 0x137160, 0x1371d0); -+ sdiv = ((sctl & 0x0000003f) >> 0) + 2; -+ } -+ -+ if (sctl & 0x80000000) -+ return (sclk * 2) / sdiv; -+ return sclk; -+} -+ -+int -+nvc0_pm_clocks_get(struct drm_device *dev, struct nouveau_pm_level *perflvl) -+{ -+ perflvl->shader = read_clk(dev, 0x00); -+ perflvl->core = perflvl->shader / 2; -+ perflvl->memory = read_mem(dev); -+ perflvl->rop = read_clk(dev, 0x01); -+ perflvl->hub07 = read_clk(dev, 0x02); -+ perflvl->hub06 = read_clk(dev, 0x07); -+ perflvl->hub01 = read_clk(dev, 0x08); -+ perflvl->copy = read_clk(dev, 0x09); -+ perflvl->daemon = read_clk(dev, 0x0c); -+ perflvl->vdec = read_clk(dev, 0x0e); -+ return 0; -+} -diff --git a/drivers/gpu/drm/nouveau/nvc0_vram.c b/drivers/gpu/drm/nouveau/nvc0_vram.c -index e45a24d..edbfe93 100644 ---- a/drivers/gpu/drm/nouveau/nvc0_vram.c -+++ b/drivers/gpu/drm/nouveau/nvc0_vram.c -@@ -61,7 +61,7 @@ nvc0_vram_new(struct drm_device *dev, u64 size, u32 align, u32 ncmin, - u32 type, struct nouveau_mem **pmem) - { - struct drm_nouveau_private *dev_priv = dev->dev_private; -- struct nouveau_mm *mm = dev_priv->engine.vram.mm; -+ struct nouveau_mm *mm = &dev_priv->engine.vram.mm; - struct nouveau_mm_node *r; - struct nouveau_mem *mem; - int ret; -@@ -106,12 +106,50 @@ nvc0_vram_init(struct drm_device *dev) - struct nouveau_vram_engine *vram = &dev_priv->engine.vram; - const u32 rsvd_head = ( 256 * 1024) >> 12; /* vga memory */ - const u32 rsvd_tail = (1024 * 1024) >> 12; /* vbios etc */ -- u32 length; -+ u32 parts = nv_rd32(dev, 0x121c74); -+ u32 bsize = nv_rd32(dev, 0x10f20c); -+ u32 offset, length; -+ bool uniform = true; -+ int ret, i; - -- dev_priv->vram_size = nv_rd32(dev, 0x10f20c) << 20; -- dev_priv->vram_size *= nv_rd32(dev, 0x121c74); -+ NV_DEBUG(dev, "0x100800: 0x%08x\n", nv_rd32(dev, 0x100800)); -+ NV_DEBUG(dev, "parts 0x%08x bcast_mem_amount 0x%08x\n", parts, bsize); - -- length = (dev_priv->vram_size >> 12) - rsvd_head - rsvd_tail; -+ /* read amount of vram attached to each memory controller */ -+ for (i = 0; i < parts; i++) { -+ u32 psize = nv_rd32(dev, 0x11020c + (i * 0x1000)); -+ if (psize != bsize) { -+ if (psize < bsize) -+ bsize = psize; -+ uniform = false; -+ } -+ -+ NV_DEBUG(dev, "%d: mem_amount 0x%08x\n", i, psize); -+ -+ dev_priv->vram_size += (u64)psize << 20; -+ } -+ -+ /* if all controllers have the same amount attached, there's no holes */ -+ if (uniform) { -+ offset = rsvd_head; -+ length = (dev_priv->vram_size >> 12) - rsvd_head - rsvd_tail; -+ return nouveau_mm_init(&vram->mm, offset, length, 1); -+ } - -- return nouveau_mm_init(&vram->mm, rsvd_head, length, 1); -+ /* otherwise, address lowest common amount from 0GiB */ -+ ret = nouveau_mm_init(&vram->mm, rsvd_head, (bsize << 8) * parts, 1); -+ if (ret) -+ return ret; -+ -+ /* and the rest starting from (8GiB + common_size) */ -+ offset = (0x0200000000ULL >> 12) + (bsize << 8); -+ length = (dev_priv->vram_size >> 12) - (bsize << 8) - rsvd_tail; -+ -+ ret = nouveau_mm_init(&vram->mm, offset, length, 0); -+ if (ret) { -+ nouveau_mm_fini(&vram->mm); -+ return ret; -+ } -+ -+ return 0; - } -diff --git a/drivers/gpu/drm/nouveau/nvd0_display.c b/drivers/gpu/drm/nouveau/nvd0_display.c -new file mode 100644 -index 0000000..23d63b4 ---- /dev/null -+++ b/drivers/gpu/drm/nouveau/nvd0_display.c -@@ -0,0 +1,1473 @@ -+/* -+ * Copyright 2011 Red Hat Inc. -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a -+ * copy of this software and associated documentation files (the "Software"), -+ * to deal in the Software without restriction, including without limitation -+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, -+ * and/or sell copies of the Software, and to permit persons to whom the -+ * Software is furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice shall be included in -+ * all copies or substantial portions of the Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR -+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -+ * OTHER DEALINGS IN THE SOFTWARE. -+ * -+ * Authors: Ben Skeggs -+ */ -+ -+#include <linux/dma-mapping.h> -+ -+#include "drmP.h" -+#include "drm_crtc_helper.h" -+ -+#include "nouveau_drv.h" -+#include "nouveau_connector.h" -+#include "nouveau_encoder.h" -+#include "nouveau_crtc.h" -+#include "nouveau_dma.h" -+#include "nouveau_fb.h" -+#include "nv50_display.h" -+ -+struct nvd0_display { -+ struct nouveau_gpuobj *mem; -+ struct { -+ dma_addr_t handle; -+ u32 *ptr; -+ } evo[1]; -+ -+ struct tasklet_struct tasklet; -+ u32 modeset; -+}; -+ -+static struct nvd0_display * -+nvd0_display(struct drm_device *dev) -+{ -+ struct drm_nouveau_private *dev_priv = dev->dev_private; -+ return dev_priv->engine.display.priv; -+} -+ -+static inline int -+evo_icmd(struct drm_device *dev, int id, u32 mthd, u32 data) -+{ -+ int ret = 0; -+ nv_mask(dev, 0x610700 + (id * 0x10), 0x00000001, 0x00000001); -+ nv_wr32(dev, 0x610704 + (id * 0x10), data); -+ nv_mask(dev, 0x610704 + (id * 0x10), 0x80000ffc, 0x80000000 | mthd); -+ if (!nv_wait(dev, 0x610704 + (id * 0x10), 0x80000000, 0x00000000)) -+ ret = -EBUSY; -+ nv_mask(dev, 0x610700 + (id * 0x10), 0x00000001, 0x00000000); -+ return ret; -+} -+ -+static u32 * -+evo_wait(struct drm_device *dev, int id, int nr) -+{ -+ struct nvd0_display *disp = nvd0_display(dev); -+ u32 put = nv_rd32(dev, 0x640000 + (id * 0x1000)) / 4; -+ -+ if (put + nr >= (PAGE_SIZE / 4)) { -+ disp->evo[id].ptr[put] = 0x20000000; -+ -+ nv_wr32(dev, 0x640000 + (id * 0x1000), 0x00000000); -+ if (!nv_wait(dev, 0x640004 + (id * 0x1000), ~0, 0x00000000)) { -+ NV_ERROR(dev, "evo %d dma stalled\n", id); -+ return NULL; -+ } -+ -+ put = 0; -+ } -+ -+ return disp->evo[id].ptr + put; -+} -+ -+static void -+evo_kick(u32 *push, struct drm_device *dev, int id) -+{ -+ struct nvd0_display *disp = nvd0_display(dev); -+ nv_wr32(dev, 0x640000 + (id * 0x1000), (push - disp->evo[id].ptr) << 2); -+} -+ -+#define evo_mthd(p,m,s) *((p)++) = (((s) << 18) | (m)) -+#define evo_data(p,d) *((p)++) = (d) -+ -+static struct drm_crtc * -+nvd0_display_crtc_get(struct drm_encoder *encoder) -+{ -+ return nouveau_encoder(encoder)->crtc; -+} -+ -+/****************************************************************************** -+ * CRTC -+ *****************************************************************************/ -+static int -+nvd0_crtc_set_dither(struct nouveau_crtc *nv_crtc, bool on, bool update) -+{ -+ struct drm_device *dev = nv_crtc->base.dev; -+ u32 *push, mode; -+ -+ mode = 0x00000000; -+ if (on) { -+ /* 0x11: 6bpc dynamic 2x2 -+ * 0x13: 8bpc dynamic 2x2 -+ * 0x19: 6bpc static 2x2 -+ * 0x1b: 8bpc static 2x2 -+ * 0x21: 6bpc temporal -+ * 0x23: 8bpc temporal -+ */ -+ mode = 0x00000011; -+ } -+ -+ push = evo_wait(dev, 0, 4); -+ if (push) { -+ evo_mthd(push, 0x0490 + (nv_crtc->index * 0x300), 1); -+ evo_data(push, mode); -+ if (update) { -+ evo_mthd(push, 0x0080, 1); -+ evo_data(push, 0x00000000); -+ } -+ evo_kick(push, dev, 0); -+ } -+ -+ return 0; -+} -+ -+static int -+nvd0_crtc_set_scale(struct nouveau_crtc *nv_crtc, int type, bool update) -+{ -+ struct drm_display_mode *mode = &nv_crtc->base.mode; -+ struct drm_device *dev = nv_crtc->base.dev; -+ struct nouveau_connector *nv_connector; -+ u32 *push, outX, outY; -+ -+ outX = mode->hdisplay; -+ outY = mode->vdisplay; -+ -+ nv_connector = nouveau_crtc_connector_get(nv_crtc); -+ if (nv_connector && nv_connector->native_mode) { -+ struct drm_display_mode *native = nv_connector->native_mode; -+ u32 xratio = (native->hdisplay << 19) / mode->hdisplay; -+ u32 yratio = (native->vdisplay << 19) / mode->vdisplay; -+ -+ switch (type) { -+ case DRM_MODE_SCALE_ASPECT: -+ if (xratio > yratio) { -+ outX = (mode->hdisplay * yratio) >> 19; -+ outY = (mode->vdisplay * yratio) >> 19; -+ } else { -+ outX = (mode->hdisplay * xratio) >> 19; -+ outY = (mode->vdisplay * xratio) >> 19; -+ } -+ break; -+ case DRM_MODE_SCALE_FULLSCREEN: -+ outX = native->hdisplay; -+ outY = native->vdisplay; -+ break; -+ default: -+ break; -+ } -+ } -+ -+ push = evo_wait(dev, 0, 16); -+ if (push) { -+ evo_mthd(push, 0x04c0 + (nv_crtc->index * 0x300), 3); -+ evo_data(push, (outY << 16) | outX); -+ evo_data(push, (outY << 16) | outX); -+ evo_data(push, (outY << 16) | outX); -+ evo_mthd(push, 0x0494 + (nv_crtc->index * 0x300), 1); -+ evo_data(push, 0x00000000); -+ evo_mthd(push, 0x04b8 + (nv_crtc->index * 0x300), 1); -+ evo_data(push, (mode->vdisplay << 16) | mode->hdisplay); -+ if (update) { -+ evo_mthd(push, 0x0080, 1); -+ evo_data(push, 0x00000000); -+ } -+ evo_kick(push, dev, 0); -+ } -+ -+ return 0; -+} -+ -+static int -+nvd0_crtc_set_image(struct nouveau_crtc *nv_crtc, struct drm_framebuffer *fb, -+ int x, int y, bool update) -+{ -+ struct nouveau_framebuffer *nvfb = nouveau_framebuffer(fb); -+ u32 *push; -+ -+ push = evo_wait(fb->dev, 0, 16); -+ if (push) { -+ evo_mthd(push, 0x0460 + (nv_crtc->index * 0x300), 1); -+ evo_data(push, nvfb->nvbo->bo.offset >> 8); -+ evo_mthd(push, 0x0468 + (nv_crtc->index * 0x300), 4); -+ evo_data(push, (fb->height << 16) | fb->width); -+ evo_data(push, nvfb->r_pitch); -+ evo_data(push, nvfb->r_format); -+ evo_data(push, nvfb->r_dma); -+ evo_mthd(push, 0x04b0 + (nv_crtc->index * 0x300), 1); -+ evo_data(push, (y << 16) | x); -+ if (update) { -+ evo_mthd(push, 0x0080, 1); -+ evo_data(push, 0x00000000); -+ } -+ evo_kick(push, fb->dev, 0); -+ } -+ -+ nv_crtc->fb.tile_flags = nvfb->r_dma; -+ return 0; -+} -+ -+static void -+nvd0_crtc_cursor_show(struct nouveau_crtc *nv_crtc, bool show, bool update) -+{ -+ struct drm_device *dev = nv_crtc->base.dev; -+ u32 *push = evo_wait(dev, 0, 16); -+ if (push) { -+ if (show) { -+ evo_mthd(push, 0x0480 + (nv_crtc->index * 0x300), 2); -+ evo_data(push, 0x85000000); -+ evo_data(push, nv_crtc->cursor.nvbo->bo.offset >> 8); -+ evo_mthd(push, 0x048c + (nv_crtc->index * 0x300), 1); -+ evo_data(push, NvEvoVRAM); -+ } else { -+ evo_mthd(push, 0x0480 + (nv_crtc->index * 0x300), 1); -+ evo_data(push, 0x05000000); -+ evo_mthd(push, 0x048c + (nv_crtc->index * 0x300), 1); -+ evo_data(push, 0x00000000); -+ } -+ -+ if (update) { -+ evo_mthd(push, 0x0080, 1); -+ evo_data(push, 0x00000000); -+ } -+ -+ evo_kick(push, dev, 0); -+ } -+} -+ -+static void -+nvd0_crtc_dpms(struct drm_crtc *crtc, int mode) -+{ -+} -+ -+static void -+nvd0_crtc_prepare(struct drm_crtc *crtc) -+{ -+ struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); -+ u32 *push; -+ -+ push = evo_wait(crtc->dev, 0, 2); -+ if (push) { -+ evo_mthd(push, 0x0474 + (nv_crtc->index * 0x300), 1); -+ evo_data(push, 0x00000000); -+ evo_mthd(push, 0x0440 + (nv_crtc->index * 0x300), 1); -+ evo_data(push, 0x03000000); -+ evo_mthd(push, 0x045c + (nv_crtc->index * 0x300), 1); -+ evo_data(push, 0x00000000); -+ evo_kick(push, crtc->dev, 0); -+ } -+ -+ nvd0_crtc_cursor_show(nv_crtc, false, false); -+} -+ -+static void -+nvd0_crtc_commit(struct drm_crtc *crtc) -+{ -+ struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); -+ u32 *push; -+ -+ push = evo_wait(crtc->dev, 0, 32); -+ if (push) { -+ evo_mthd(push, 0x0474 + (nv_crtc->index * 0x300), 1); -+ evo_data(push, nv_crtc->fb.tile_flags); -+ evo_mthd(push, 0x0440 + (nv_crtc->index * 0x300), 4); -+ evo_data(push, 0x83000000); -+ evo_data(push, nv_crtc->lut.nvbo->bo.offset >> 8); -+ evo_data(push, 0x00000000); -+ evo_data(push, 0x00000000); -+ evo_mthd(push, 0x045c + (nv_crtc->index * 0x300), 1); -+ evo_data(push, NvEvoVRAM); -+ evo_mthd(push, 0x0430 + (nv_crtc->index * 0x300), 1); -+ evo_data(push, 0xffffff00); -+ evo_kick(push, crtc->dev, 0); -+ } -+ -+ nvd0_crtc_cursor_show(nv_crtc, nv_crtc->cursor.visible, true); -+} -+ -+static bool -+nvd0_crtc_mode_fixup(struct drm_crtc *crtc, struct drm_display_mode *mode, -+ struct drm_display_mode *adjusted_mode) -+{ -+ return true; -+} -+ -+static int -+nvd0_crtc_swap_fbs(struct drm_crtc *crtc, struct drm_framebuffer *old_fb) -+{ -+ struct nouveau_framebuffer *nvfb = nouveau_framebuffer(crtc->fb); -+ int ret; -+ -+ ret = nouveau_bo_pin(nvfb->nvbo, TTM_PL_FLAG_VRAM); -+ if (ret) -+ return ret; -+ -+ if (old_fb) { -+ nvfb = nouveau_framebuffer(old_fb); -+ nouveau_bo_unpin(nvfb->nvbo); -+ } -+ -+ return 0; -+} -+ -+static int -+nvd0_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *umode, -+ struct drm_display_mode *mode, int x, int y, -+ struct drm_framebuffer *old_fb) -+{ -+ struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); -+ struct nouveau_connector *nv_connector; -+ u32 htotal = mode->htotal; -+ u32 vtotal = mode->vtotal; -+ u32 hsyncw = mode->hsync_end - mode->hsync_start - 1; -+ u32 vsyncw = mode->vsync_end - mode->vsync_start - 1; -+ u32 hfrntp = mode->hsync_start - mode->hdisplay; -+ u32 vfrntp = mode->vsync_start - mode->vdisplay; -+ u32 hbackp = mode->htotal - mode->hsync_end; -+ u32 vbackp = mode->vtotal - mode->vsync_end; -+ u32 hss2be = hsyncw + hbackp; -+ u32 vss2be = vsyncw + vbackp; -+ u32 hss2de = htotal - hfrntp; -+ u32 vss2de = vtotal - vfrntp; -+ u32 syncs, *push; -+ int ret; -+ -+ syncs = 0x00000001; -+ if (mode->flags & DRM_MODE_FLAG_NHSYNC) -+ syncs |= 0x00000008; -+ if (mode->flags & DRM_MODE_FLAG_NVSYNC) -+ syncs |= 0x00000010; -+ -+ ret = nvd0_crtc_swap_fbs(crtc, old_fb); -+ if (ret) -+ return ret; -+ -+ push = evo_wait(crtc->dev, 0, 64); -+ if (push) { -+ evo_mthd(push, 0x0410 + (nv_crtc->index * 0x300), 5); -+ evo_data(push, 0x00000000); -+ evo_data(push, (vtotal << 16) | htotal); -+ evo_data(push, (vsyncw << 16) | hsyncw); -+ evo_data(push, (vss2be << 16) | hss2be); -+ evo_data(push, (vss2de << 16) | hss2de); -+ evo_mthd(push, 0x042c + (nv_crtc->index * 0x300), 1); -+ evo_data(push, 0x00000000); /* ??? */ -+ evo_mthd(push, 0x0450 + (nv_crtc->index * 0x300), 3); -+ evo_data(push, mode->clock * 1000); -+ evo_data(push, 0x00200000); /* ??? */ -+ evo_data(push, mode->clock * 1000); -+ evo_mthd(push, 0x0404 + (nv_crtc->index * 0x300), 1); -+ evo_data(push, syncs); -+ evo_kick(push, crtc->dev, 0); -+ } -+ -+ nv_connector = nouveau_crtc_connector_get(nv_crtc); -+ nvd0_crtc_set_dither(nv_crtc, nv_connector->use_dithering, false); -+ nvd0_crtc_set_scale(nv_crtc, nv_connector->scaling_mode, false); -+ nvd0_crtc_set_image(nv_crtc, crtc->fb, x, y, false); -+ return 0; -+} -+ -+static int -+nvd0_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, -+ struct drm_framebuffer *old_fb) -+{ -+ struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); -+ int ret; -+ -+ if (!crtc->fb) { -+ NV_DEBUG_KMS(crtc->dev, "No FB bound\n"); -+ return 0; -+ } -+ -+ ret = nvd0_crtc_swap_fbs(crtc, old_fb); -+ if (ret) -+ return ret; -+ -+ nvd0_crtc_set_image(nv_crtc, crtc->fb, x, y, true); -+ return 0; -+} -+ -+static int -+nvd0_crtc_mode_set_base_atomic(struct drm_crtc *crtc, -+ struct drm_framebuffer *fb, int x, int y, -+ enum mode_set_atomic state) -+{ -+ struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); -+ nvd0_crtc_set_image(nv_crtc, fb, x, y, true); -+ return 0; -+} -+ -+static void -+nvd0_crtc_lut_load(struct drm_crtc *crtc) -+{ -+ struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); -+ void __iomem *lut = nvbo_kmap_obj_iovirtual(nv_crtc->lut.nvbo); -+ int i; -+ -+ for (i = 0; i < 256; i++) { -+ writew(0x6000 + (nv_crtc->lut.r[i] >> 2), lut + (i * 0x20) + 0); -+ writew(0x6000 + (nv_crtc->lut.g[i] >> 2), lut + (i * 0x20) + 2); -+ writew(0x6000 + (nv_crtc->lut.b[i] >> 2), lut + (i * 0x20) + 4); -+ } -+} -+ -+static int -+nvd0_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv, -+ uint32_t handle, uint32_t width, uint32_t height) -+{ -+ struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); -+ struct drm_device *dev = crtc->dev; -+ struct drm_gem_object *gem; -+ struct nouveau_bo *nvbo; -+ bool visible = (handle != 0); -+ int i, ret = 0; -+ -+ if (visible) { -+ if (width != 64 || height != 64) -+ return -EINVAL; -+ -+ gem = drm_gem_object_lookup(dev, file_priv, handle); -+ if (unlikely(!gem)) -+ return -ENOENT; -+ nvbo = nouveau_gem_object(gem); -+ -+ ret = nouveau_bo_map(nvbo); -+ if (ret == 0) { -+ for (i = 0; i < 64 * 64; i++) { -+ u32 v = nouveau_bo_rd32(nvbo, i); -+ nouveau_bo_wr32(nv_crtc->cursor.nvbo, i, v); -+ } -+ nouveau_bo_unmap(nvbo); -+ } -+ -+ drm_gem_object_unreference_unlocked(gem); -+ } -+ -+ if (visible != nv_crtc->cursor.visible) { -+ nvd0_crtc_cursor_show(nv_crtc, visible, true); -+ nv_crtc->cursor.visible = visible; -+ } -+ -+ return ret; -+} -+ -+static int -+nvd0_crtc_cursor_move(struct drm_crtc *crtc, int x, int y) -+{ -+ struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); -+ const u32 data = (y << 16) | x; -+ -+ nv_wr32(crtc->dev, 0x64d084 + (nv_crtc->index * 0x1000), data); -+ nv_wr32(crtc->dev, 0x64d080 + (nv_crtc->index * 0x1000), 0x00000000); -+ return 0; -+} -+ -+static void -+nvd0_crtc_gamma_set(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b, -+ uint32_t start, uint32_t size) -+{ -+ struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); -+ u32 end = max(start + size, (u32)256); -+ u32 i; -+ -+ for (i = start; i < end; i++) { -+ nv_crtc->lut.r[i] = r[i]; -+ nv_crtc->lut.g[i] = g[i]; -+ nv_crtc->lut.b[i] = b[i]; -+ } -+ -+ nvd0_crtc_lut_load(crtc); -+} -+ -+static void -+nvd0_crtc_destroy(struct drm_crtc *crtc) -+{ -+ struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); -+ nouveau_bo_unmap(nv_crtc->cursor.nvbo); -+ nouveau_bo_ref(NULL, &nv_crtc->cursor.nvbo); -+ nouveau_bo_unmap(nv_crtc->lut.nvbo); -+ nouveau_bo_ref(NULL, &nv_crtc->lut.nvbo); -+ drm_crtc_cleanup(crtc); -+ kfree(crtc); -+} -+ -+static const struct drm_crtc_helper_funcs nvd0_crtc_hfunc = { -+ .dpms = nvd0_crtc_dpms, -+ .prepare = nvd0_crtc_prepare, -+ .commit = nvd0_crtc_commit, -+ .mode_fixup = nvd0_crtc_mode_fixup, -+ .mode_set = nvd0_crtc_mode_set, -+ .mode_set_base = nvd0_crtc_mode_set_base, -+ .mode_set_base_atomic = nvd0_crtc_mode_set_base_atomic, -+ .load_lut = nvd0_crtc_lut_load, -+}; -+ -+static const struct drm_crtc_funcs nvd0_crtc_func = { -+ .cursor_set = nvd0_crtc_cursor_set, -+ .cursor_move = nvd0_crtc_cursor_move, -+ .gamma_set = nvd0_crtc_gamma_set, -+ .set_config = drm_crtc_helper_set_config, -+ .destroy = nvd0_crtc_destroy, -+}; -+ -+static void -+nvd0_cursor_set_pos(struct nouveau_crtc *nv_crtc, int x, int y) -+{ -+} -+ -+static void -+nvd0_cursor_set_offset(struct nouveau_crtc *nv_crtc, uint32_t offset) -+{ -+} -+ -+static int -+nvd0_crtc_create(struct drm_device *dev, int index) -+{ -+ struct nouveau_crtc *nv_crtc; -+ struct drm_crtc *crtc; -+ int ret, i; -+ -+ nv_crtc = kzalloc(sizeof(*nv_crtc), GFP_KERNEL); -+ if (!nv_crtc) -+ return -ENOMEM; -+ -+ nv_crtc->index = index; -+ nv_crtc->set_dither = nvd0_crtc_set_dither; -+ nv_crtc->set_scale = nvd0_crtc_set_scale; -+ nv_crtc->cursor.set_offset = nvd0_cursor_set_offset; -+ nv_crtc->cursor.set_pos = nvd0_cursor_set_pos; -+ for (i = 0; i < 256; i++) { -+ nv_crtc->lut.r[i] = i << 8; -+ nv_crtc->lut.g[i] = i << 8; -+ nv_crtc->lut.b[i] = i << 8; -+ } -+ -+ crtc = &nv_crtc->base; -+ drm_crtc_init(dev, crtc, &nvd0_crtc_func); -+ drm_crtc_helper_add(crtc, &nvd0_crtc_hfunc); -+ drm_mode_crtc_set_gamma_size(crtc, 256); -+ -+ ret = nouveau_bo_new(dev, 64 * 64 * 4, 0x100, TTM_PL_FLAG_VRAM, -+ 0, 0x0000, &nv_crtc->cursor.nvbo); -+ if (!ret) { -+ ret = nouveau_bo_pin(nv_crtc->cursor.nvbo, TTM_PL_FLAG_VRAM); -+ if (!ret) -+ ret = nouveau_bo_map(nv_crtc->cursor.nvbo); -+ if (ret) -+ nouveau_bo_ref(NULL, &nv_crtc->cursor.nvbo); -+ } -+ -+ if (ret) -+ goto out; -+ -+ ret = nouveau_bo_new(dev, 8192, 0x100, TTM_PL_FLAG_VRAM, -+ 0, 0x0000, &nv_crtc->lut.nvbo); -+ if (!ret) { -+ ret = nouveau_bo_pin(nv_crtc->lut.nvbo, TTM_PL_FLAG_VRAM); -+ if (!ret) -+ ret = nouveau_bo_map(nv_crtc->lut.nvbo); -+ if (ret) -+ nouveau_bo_ref(NULL, &nv_crtc->lut.nvbo); -+ } -+ -+ if (ret) -+ goto out; -+ -+ nvd0_crtc_lut_load(crtc); -+ -+out: -+ if (ret) -+ nvd0_crtc_destroy(crtc); -+ return ret; -+} -+ -+/****************************************************************************** -+ * DAC -+ *****************************************************************************/ -+static void -+nvd0_dac_dpms(struct drm_encoder *encoder, int mode) -+{ -+ struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); -+ struct drm_device *dev = encoder->dev; -+ int or = nv_encoder->or; -+ u32 dpms_ctrl; -+ -+ dpms_ctrl = 0x80000000; -+ if (mode == DRM_MODE_DPMS_STANDBY || mode == DRM_MODE_DPMS_OFF) -+ dpms_ctrl |= 0x00000001; -+ if (mode == DRM_MODE_DPMS_SUSPEND || mode == DRM_MODE_DPMS_OFF) -+ dpms_ctrl |= 0x00000004; -+ -+ nv_wait(dev, 0x61a004 + (or * 0x0800), 0x80000000, 0x00000000); -+ nv_mask(dev, 0x61a004 + (or * 0x0800), 0xc000007f, dpms_ctrl); -+ nv_wait(dev, 0x61a004 + (or * 0x0800), 0x80000000, 0x00000000); -+} -+ -+static bool -+nvd0_dac_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode, -+ struct drm_display_mode *adjusted_mode) -+{ -+ struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); -+ struct nouveau_connector *nv_connector; -+ -+ nv_connector = nouveau_encoder_connector_get(nv_encoder); -+ if (nv_connector && nv_connector->native_mode) { -+ if (nv_connector->scaling_mode != DRM_MODE_SCALE_NONE) { -+ int id = adjusted_mode->base.id; -+ *adjusted_mode = *nv_connector->native_mode; -+ adjusted_mode->base.id = id; -+ } -+ } -+ -+ return true; -+} -+ -+static void -+nvd0_dac_prepare(struct drm_encoder *encoder) -+{ -+} -+ -+static void -+nvd0_dac_commit(struct drm_encoder *encoder) -+{ -+} -+ -+static void -+nvd0_dac_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, -+ struct drm_display_mode *adjusted_mode) -+{ -+ struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); -+ struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc); -+ u32 *push; -+ -+ nvd0_dac_dpms(encoder, DRM_MODE_DPMS_ON); -+ -+ push = evo_wait(encoder->dev, 0, 4); -+ if (push) { -+ evo_mthd(push, 0x0180 + (nv_encoder->or * 0x20), 2); -+ evo_data(push, 1 << nv_crtc->index); -+ evo_data(push, 0x00ff); -+ evo_kick(push, encoder->dev, 0); -+ } -+ -+ nv_encoder->crtc = encoder->crtc; -+} -+ -+static void -+nvd0_dac_disconnect(struct drm_encoder *encoder) -+{ -+ struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); -+ struct drm_device *dev = encoder->dev; -+ u32 *push; -+ -+ if (nv_encoder->crtc) { -+ nvd0_crtc_prepare(nv_encoder->crtc); -+ -+ push = evo_wait(dev, 0, 4); -+ if (push) { -+ evo_mthd(push, 0x0180 + (nv_encoder->or * 0x20), 1); -+ evo_data(push, 0x00000000); -+ evo_mthd(push, 0x0080, 1); -+ evo_data(push, 0x00000000); -+ evo_kick(push, dev, 0); -+ } -+ -+ nv_encoder->crtc = NULL; -+ } -+} -+ -+static enum drm_connector_status -+nvd0_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector) -+{ -+ enum drm_connector_status status = connector_status_disconnected; -+ struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); -+ struct drm_device *dev = encoder->dev; -+ int or = nv_encoder->or; -+ u32 load; -+ -+ nv_wr32(dev, 0x61a00c + (or * 0x800), 0x00100000); -+ udelay(9500); -+ nv_wr32(dev, 0x61a00c + (or * 0x800), 0x80000000); -+ -+ load = nv_rd32(dev, 0x61a00c + (or * 0x800)); -+ if ((load & 0x38000000) == 0x38000000) -+ status = connector_status_connected; -+ -+ nv_wr32(dev, 0x61a00c + (or * 0x800), 0x00000000); -+ return status; -+} -+ -+static void -+nvd0_dac_destroy(struct drm_encoder *encoder) -+{ -+ drm_encoder_cleanup(encoder); -+ kfree(encoder); -+} -+ -+static const struct drm_encoder_helper_funcs nvd0_dac_hfunc = { -+ .dpms = nvd0_dac_dpms, -+ .mode_fixup = nvd0_dac_mode_fixup, -+ .prepare = nvd0_dac_prepare, -+ .commit = nvd0_dac_commit, -+ .mode_set = nvd0_dac_mode_set, -+ .disable = nvd0_dac_disconnect, -+ .get_crtc = nvd0_display_crtc_get, -+ .detect = nvd0_dac_detect -+}; -+ -+static const struct drm_encoder_funcs nvd0_dac_func = { -+ .destroy = nvd0_dac_destroy, -+}; -+ -+static int -+nvd0_dac_create(struct drm_connector *connector, struct dcb_entry *dcbe) -+{ -+ struct drm_device *dev = connector->dev; -+ struct nouveau_encoder *nv_encoder; -+ struct drm_encoder *encoder; -+ -+ nv_encoder = kzalloc(sizeof(*nv_encoder), GFP_KERNEL); -+ if (!nv_encoder) -+ return -ENOMEM; -+ nv_encoder->dcb = dcbe; -+ nv_encoder->or = ffs(dcbe->or) - 1; -+ -+ encoder = to_drm_encoder(nv_encoder); -+ encoder->possible_crtcs = dcbe->heads; -+ encoder->possible_clones = 0; -+ drm_encoder_init(dev, encoder, &nvd0_dac_func, DRM_MODE_ENCODER_DAC); -+ drm_encoder_helper_add(encoder, &nvd0_dac_hfunc); -+ -+ drm_mode_connector_attach_encoder(connector, encoder); -+ return 0; -+} -+ -+/****************************************************************************** -+ * SOR -+ *****************************************************************************/ -+static void -+nvd0_sor_dpms(struct drm_encoder *encoder, int mode) -+{ -+ struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); -+ struct drm_device *dev = encoder->dev; -+ struct drm_encoder *partner; -+ int or = nv_encoder->or; -+ u32 dpms_ctrl; -+ -+ nv_encoder->last_dpms = mode; -+ -+ list_for_each_entry(partner, &dev->mode_config.encoder_list, head) { -+ struct nouveau_encoder *nv_partner = nouveau_encoder(partner); -+ -+ if (partner->encoder_type != DRM_MODE_ENCODER_TMDS) -+ continue; -+ -+ if (nv_partner != nv_encoder && -+ nv_partner->dcb->or == nv_encoder->or) { -+ if (nv_partner->last_dpms == DRM_MODE_DPMS_ON) -+ return; -+ break; -+ } -+ } -+ -+ dpms_ctrl = (mode == DRM_MODE_DPMS_ON); -+ dpms_ctrl |= 0x80000000; -+ -+ nv_wait(dev, 0x61c004 + (or * 0x0800), 0x80000000, 0x00000000); -+ nv_mask(dev, 0x61c004 + (or * 0x0800), 0x80000001, dpms_ctrl); -+ nv_wait(dev, 0x61c004 + (or * 0x0800), 0x80000000, 0x00000000); -+ nv_wait(dev, 0x61c030 + (or * 0x0800), 0x10000000, 0x00000000); -+} -+ -+static bool -+nvd0_sor_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode, -+ struct drm_display_mode *adjusted_mode) -+{ -+ struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); -+ struct nouveau_connector *nv_connector; -+ -+ nv_connector = nouveau_encoder_connector_get(nv_encoder); -+ if (nv_connector && nv_connector->native_mode) { -+ if (nv_connector->scaling_mode != DRM_MODE_SCALE_NONE) { -+ int id = adjusted_mode->base.id; -+ *adjusted_mode = *nv_connector->native_mode; -+ adjusted_mode->base.id = id; -+ } -+ } -+ -+ return true; -+} -+ -+static void -+nvd0_sor_prepare(struct drm_encoder *encoder) -+{ -+} -+ -+static void -+nvd0_sor_commit(struct drm_encoder *encoder) -+{ -+} -+ -+static void -+nvd0_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *umode, -+ struct drm_display_mode *mode) -+{ -+ struct drm_nouveau_private *dev_priv = encoder->dev->dev_private; -+ struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); -+ struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc); -+ struct nouveau_connector *nv_connector; -+ struct nvbios *bios = &dev_priv->vbios; -+ u32 mode_ctrl = (1 << nv_crtc->index); -+ u32 *push, or_config; -+ -+ nv_connector = nouveau_encoder_connector_get(nv_encoder); -+ switch (nv_encoder->dcb->type) { -+ case OUTPUT_TMDS: -+ if (nv_encoder->dcb->sorconf.link & 1) { -+ if (mode->clock < 165000) -+ mode_ctrl |= 0x00000100; -+ else -+ mode_ctrl |= 0x00000500; -+ } else { -+ mode_ctrl |= 0x00000200; -+ } -+ -+ or_config = (mode_ctrl & 0x00000f00) >> 8; -+ if (mode->clock >= 165000) -+ or_config |= 0x0100; -+ break; -+ case OUTPUT_LVDS: -+ or_config = (mode_ctrl & 0x00000f00) >> 8; -+ if (bios->fp_no_ddc) { -+ if (bios->fp.dual_link) -+ or_config |= 0x0100; -+ if (bios->fp.if_is_24bit) -+ or_config |= 0x0200; -+ } else { -+ if (nv_connector->dcb->type == DCB_CONNECTOR_LVDS_SPWG) { -+ if (((u8 *)nv_connector->edid)[121] == 2) -+ or_config |= 0x0100; -+ } else -+ if (mode->clock >= bios->fp.duallink_transition_clk) { -+ or_config |= 0x0100; -+ } -+ -+ if (or_config & 0x0100) { -+ if (bios->fp.strapless_is_24bit & 2) -+ or_config |= 0x0200; -+ } else { -+ if (bios->fp.strapless_is_24bit & 1) -+ or_config |= 0x0200; -+ } -+ -+ if (nv_connector->base.display_info.bpc == 8) -+ or_config |= 0x0200; -+ -+ } -+ break; -+ default: -+ BUG_ON(1); -+ break; -+ } -+ -+ nvd0_sor_dpms(encoder, DRM_MODE_DPMS_ON); -+ -+ push = evo_wait(encoder->dev, 0, 4); -+ if (push) { -+ evo_mthd(push, 0x0200 + (nv_encoder->or * 0x20), 2); -+ evo_data(push, mode_ctrl); -+ evo_data(push, or_config); -+ evo_kick(push, encoder->dev, 0); -+ } -+ -+ nv_encoder->crtc = encoder->crtc; -+} -+ -+static void -+nvd0_sor_disconnect(struct drm_encoder *encoder) -+{ -+ struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); -+ struct drm_device *dev = encoder->dev; -+ u32 *push; -+ -+ if (nv_encoder->crtc) { -+ nvd0_crtc_prepare(nv_encoder->crtc); -+ -+ push = evo_wait(dev, 0, 4); -+ if (push) { -+ evo_mthd(push, 0x0200 + (nv_encoder->or * 0x20), 1); -+ evo_data(push, 0x00000000); -+ evo_mthd(push, 0x0080, 1); -+ evo_data(push, 0x00000000); -+ evo_kick(push, dev, 0); -+ } -+ -+ nv_encoder->crtc = NULL; -+ nv_encoder->last_dpms = DRM_MODE_DPMS_OFF; -+ } -+} -+ -+static void -+nvd0_sor_destroy(struct drm_encoder *encoder) -+{ -+ drm_encoder_cleanup(encoder); -+ kfree(encoder); -+} -+ -+static const struct drm_encoder_helper_funcs nvd0_sor_hfunc = { -+ .dpms = nvd0_sor_dpms, -+ .mode_fixup = nvd0_sor_mode_fixup, -+ .prepare = nvd0_sor_prepare, -+ .commit = nvd0_sor_commit, -+ .mode_set = nvd0_sor_mode_set, -+ .disable = nvd0_sor_disconnect, -+ .get_crtc = nvd0_display_crtc_get, -+}; -+ -+static const struct drm_encoder_funcs nvd0_sor_func = { -+ .destroy = nvd0_sor_destroy, -+}; -+ -+static int -+nvd0_sor_create(struct drm_connector *connector, struct dcb_entry *dcbe) -+{ -+ struct drm_device *dev = connector->dev; -+ struct nouveau_encoder *nv_encoder; -+ struct drm_encoder *encoder; -+ -+ nv_encoder = kzalloc(sizeof(*nv_encoder), GFP_KERNEL); -+ if (!nv_encoder) -+ return -ENOMEM; -+ nv_encoder->dcb = dcbe; -+ nv_encoder->or = ffs(dcbe->or) - 1; -+ nv_encoder->last_dpms = DRM_MODE_DPMS_OFF; -+ -+ encoder = to_drm_encoder(nv_encoder); -+ encoder->possible_crtcs = dcbe->heads; -+ encoder->possible_clones = 0; -+ drm_encoder_init(dev, encoder, &nvd0_sor_func, DRM_MODE_ENCODER_TMDS); -+ drm_encoder_helper_add(encoder, &nvd0_sor_hfunc); -+ -+ drm_mode_connector_attach_encoder(connector, encoder); -+ return 0; -+} -+ -+/****************************************************************************** -+ * IRQ -+ *****************************************************************************/ -+static struct dcb_entry * -+lookup_dcb(struct drm_device *dev, int id, u32 mc) -+{ -+ struct drm_nouveau_private *dev_priv = dev->dev_private; -+ int type, or, i; -+ -+ if (id < 4) { -+ type = OUTPUT_ANALOG; -+ or = id; -+ } else { -+ switch (mc & 0x00000f00) { -+ case 0x00000000: type = OUTPUT_LVDS; break; -+ case 0x00000100: type = OUTPUT_TMDS; break; -+ case 0x00000200: type = OUTPUT_TMDS; break; -+ case 0x00000500: type = OUTPUT_TMDS; break; -+ default: -+ NV_ERROR(dev, "PDISP: unknown SOR mc 0x%08x\n", mc); -+ return NULL; -+ } -+ -+ or = id - 4; -+ } -+ -+ for (i = 0; i < dev_priv->vbios.dcb.entries; i++) { -+ struct dcb_entry *dcb = &dev_priv->vbios.dcb.entry[i]; -+ if (dcb->type == type && (dcb->or & (1 << or))) -+ return dcb; -+ } -+ -+ NV_ERROR(dev, "PDISP: DCB for %d/0x%08x not found\n", id, mc); -+ return NULL; -+} -+ -+static void -+nvd0_display_unk1_handler(struct drm_device *dev, u32 crtc, u32 mask) -+{ -+ struct dcb_entry *dcb; -+ int i; -+ -+ for (i = 0; mask && i < 8; i++) { -+ u32 mcc = nv_rd32(dev, 0x640180 + (i * 0x20)); -+ if (!(mcc & (1 << crtc))) -+ continue; -+ -+ dcb = lookup_dcb(dev, i, mcc); -+ if (!dcb) -+ continue; -+ -+ nouveau_bios_run_display_table(dev, 0x0000, -1, dcb, crtc); -+ } -+ -+ nv_wr32(dev, 0x6101d4, 0x00000000); -+ nv_wr32(dev, 0x6109d4, 0x00000000); -+ nv_wr32(dev, 0x6101d0, 0x80000000); -+} -+ -+static void -+nvd0_display_unk2_handler(struct drm_device *dev, u32 crtc, u32 mask) -+{ -+ struct dcb_entry *dcb; -+ u32 or, tmp, pclk; -+ int i; -+ -+ for (i = 0; mask && i < 8; i++) { -+ u32 mcc = nv_rd32(dev, 0x640180 + (i * 0x20)); -+ if (!(mcc & (1 << crtc))) -+ continue; -+ -+ dcb = lookup_dcb(dev, i, mcc); -+ if (!dcb) -+ continue; -+ -+ nouveau_bios_run_display_table(dev, 0x0000, -2, dcb, crtc); -+ } -+ -+ pclk = nv_rd32(dev, 0x660450 + (crtc * 0x300)) / 1000; -+ if (mask & 0x00010000) { -+ nv50_crtc_set_clock(dev, crtc, pclk); -+ } -+ -+ for (i = 0; mask && i < 8; i++) { -+ u32 mcp = nv_rd32(dev, 0x660180 + (i * 0x20)); -+ u32 cfg = nv_rd32(dev, 0x660184 + (i * 0x20)); -+ if (!(mcp & (1 << crtc))) -+ continue; -+ -+ dcb = lookup_dcb(dev, i, mcp); -+ if (!dcb) -+ continue; -+ or = ffs(dcb->or) - 1; -+ -+ nouveau_bios_run_display_table(dev, cfg, pclk, dcb, crtc); -+ -+ nv_wr32(dev, 0x612200 + (crtc * 0x800), 0x00000000); -+ switch (dcb->type) { -+ case OUTPUT_ANALOG: -+ nv_wr32(dev, 0x612280 + (or * 0x800), 0x00000000); -+ break; -+ case OUTPUT_TMDS: -+ case OUTPUT_LVDS: -+ if (cfg & 0x00000100) -+ tmp = 0x00000101; -+ else -+ tmp = 0x00000000; -+ -+ nv_mask(dev, 0x612300 + (or * 0x800), 0x00000707, tmp); -+ break; -+ default: -+ break; -+ } -+ -+ break; -+ } -+ -+ nv_wr32(dev, 0x6101d4, 0x00000000); -+ nv_wr32(dev, 0x6109d4, 0x00000000); -+ nv_wr32(dev, 0x6101d0, 0x80000000); -+} -+ -+static void -+nvd0_display_unk4_handler(struct drm_device *dev, u32 crtc, u32 mask) -+{ -+ struct dcb_entry *dcb; -+ int pclk, i; -+ -+ pclk = nv_rd32(dev, 0x660450 + (crtc * 0x300)) / 1000; -+ -+ for (i = 0; mask && i < 8; i++) { -+ u32 mcp = nv_rd32(dev, 0x660180 + (i * 0x20)); -+ u32 cfg = nv_rd32(dev, 0x660184 + (i * 0x20)); -+ if (!(mcp & (1 << crtc))) -+ continue; -+ -+ dcb = lookup_dcb(dev, i, mcp); -+ if (!dcb) -+ continue; -+ -+ nouveau_bios_run_display_table(dev, cfg, -pclk, dcb, crtc); -+ } -+ -+ nv_wr32(dev, 0x6101d4, 0x00000000); -+ nv_wr32(dev, 0x6109d4, 0x00000000); -+ nv_wr32(dev, 0x6101d0, 0x80000000); -+} -+ -+static void -+nvd0_display_bh(unsigned long data) -+{ -+ struct drm_device *dev = (struct drm_device *)data; -+ struct nvd0_display *disp = nvd0_display(dev); -+ u32 mask, crtc; -+ int i; -+ -+ if (drm_debug & (DRM_UT_DRIVER | DRM_UT_KMS)) { -+ NV_INFO(dev, "PDISP: modeset req %d\n", disp->modeset); -+ NV_INFO(dev, " STAT: 0x%08x 0x%08x 0x%08x\n", -+ nv_rd32(dev, 0x6101d0), -+ nv_rd32(dev, 0x6101d4), nv_rd32(dev, 0x6109d4)); -+ for (i = 0; i < 8; i++) { -+ NV_INFO(dev, " %s%d: 0x%08x 0x%08x\n", -+ i < 4 ? "DAC" : "SOR", i, -+ nv_rd32(dev, 0x640180 + (i * 0x20)), -+ nv_rd32(dev, 0x660180 + (i * 0x20))); -+ } -+ } -+ -+ mask = nv_rd32(dev, 0x6101d4); -+ crtc = 0; -+ if (!mask) { -+ mask = nv_rd32(dev, 0x6109d4); -+ crtc = 1; -+ } -+ -+ if (disp->modeset & 0x00000001) -+ nvd0_display_unk1_handler(dev, crtc, mask); -+ if (disp->modeset & 0x00000002) -+ nvd0_display_unk2_handler(dev, crtc, mask); -+ if (disp->modeset & 0x00000004) -+ nvd0_display_unk4_handler(dev, crtc, mask); -+} -+ -+static void -+nvd0_display_intr(struct drm_device *dev) -+{ -+ struct nvd0_display *disp = nvd0_display(dev); -+ u32 intr = nv_rd32(dev, 0x610088); -+ -+ if (intr & 0x00000002) { -+ u32 stat = nv_rd32(dev, 0x61009c); -+ int chid = ffs(stat) - 1; -+ if (chid >= 0) { -+ u32 mthd = nv_rd32(dev, 0x6101f0 + (chid * 12)); -+ u32 data = nv_rd32(dev, 0x6101f4 + (chid * 12)); -+ u32 unkn = nv_rd32(dev, 0x6101f8 + (chid * 12)); -+ -+ NV_INFO(dev, "EvoCh: chid %d mthd 0x%04x data 0x%08x " -+ "0x%08x 0x%08x\n", -+ chid, (mthd & 0x0000ffc), data, mthd, unkn); -+ nv_wr32(dev, 0x61009c, (1 << chid)); -+ nv_wr32(dev, 0x6101f0 + (chid * 12), 0x90000000); -+ } -+ -+ intr &= ~0x00000002; -+ } -+ -+ if (intr & 0x00100000) { -+ u32 stat = nv_rd32(dev, 0x6100ac); -+ -+ if (stat & 0x00000007) { -+ disp->modeset = stat; -+ tasklet_schedule(&disp->tasklet); -+ -+ nv_wr32(dev, 0x6100ac, (stat & 0x00000007)); -+ stat &= ~0x00000007; -+ } -+ -+ if (stat) { -+ NV_INFO(dev, "PDISP: unknown intr24 0x%08x\n", stat); -+ nv_wr32(dev, 0x6100ac, stat); -+ } -+ -+ intr &= ~0x00100000; -+ } -+ -+ if (intr & 0x01000000) { -+ u32 stat = nv_rd32(dev, 0x6100bc); -+ nv_wr32(dev, 0x6100bc, stat); -+ intr &= ~0x01000000; -+ } -+ -+ if (intr & 0x02000000) { -+ u32 stat = nv_rd32(dev, 0x6108bc); -+ nv_wr32(dev, 0x6108bc, stat); -+ intr &= ~0x02000000; -+ } -+ -+ if (intr) -+ NV_INFO(dev, "PDISP: unknown intr 0x%08x\n", intr); -+} -+ -+/****************************************************************************** -+ * Init -+ *****************************************************************************/ -+static void -+nvd0_display_fini(struct drm_device *dev) -+{ -+ int i; -+ -+ /* fini cursors */ -+ for (i = 14; i >= 13; i--) { -+ if (!(nv_rd32(dev, 0x610490 + (i * 0x10)) & 0x00000001)) -+ continue; -+ -+ nv_mask(dev, 0x610490 + (i * 0x10), 0x00000001, 0x00000000); -+ nv_wait(dev, 0x610490 + (i * 0x10), 0x00010000, 0x00000000); -+ nv_mask(dev, 0x610090, 1 << i, 0x00000000); -+ nv_mask(dev, 0x6100a0, 1 << i, 0x00000000); -+ } -+ -+ /* fini master */ -+ if (nv_rd32(dev, 0x610490) & 0x00000010) { -+ nv_mask(dev, 0x610490, 0x00000010, 0x00000000); -+ nv_mask(dev, 0x610490, 0x00000003, 0x00000000); -+ nv_wait(dev, 0x610490, 0x80000000, 0x00000000); -+ nv_mask(dev, 0x610090, 0x00000001, 0x00000000); -+ nv_mask(dev, 0x6100a0, 0x00000001, 0x00000000); -+ } -+} -+ -+int -+nvd0_display_init(struct drm_device *dev) -+{ -+ struct nvd0_display *disp = nvd0_display(dev); -+ u32 *push; -+ int i; -+ -+ if (nv_rd32(dev, 0x6100ac) & 0x00000100) { -+ nv_wr32(dev, 0x6100ac, 0x00000100); -+ nv_mask(dev, 0x6194e8, 0x00000001, 0x00000000); -+ if (!nv_wait(dev, 0x6194e8, 0x00000002, 0x00000000)) { -+ NV_ERROR(dev, "PDISP: 0x6194e8 0x%08x\n", -+ nv_rd32(dev, 0x6194e8)); -+ return -EBUSY; -+ } -+ } -+ -+ /* nfi what these are exactly, i do know that SOR_MODE_CTRL won't -+ * work at all unless you do the SOR part below. -+ */ -+ for (i = 0; i < 3; i++) { -+ u32 dac = nv_rd32(dev, 0x61a000 + (i * 0x800)); -+ nv_wr32(dev, 0x6101c0 + (i * 0x800), dac); -+ } -+ -+ for (i = 0; i < 4; i++) { -+ u32 sor = nv_rd32(dev, 0x61c000 + (i * 0x800)); -+ nv_wr32(dev, 0x6301c4 + (i * 0x800), sor); -+ } -+ -+ for (i = 0; i < 2; i++) { -+ u32 crtc0 = nv_rd32(dev, 0x616104 + (i * 0x800)); -+ u32 crtc1 = nv_rd32(dev, 0x616108 + (i * 0x800)); -+ u32 crtc2 = nv_rd32(dev, 0x61610c + (i * 0x800)); -+ nv_wr32(dev, 0x6101b4 + (i * 0x800), crtc0); -+ nv_wr32(dev, 0x6101b8 + (i * 0x800), crtc1); -+ nv_wr32(dev, 0x6101bc + (i * 0x800), crtc2); -+ } -+ -+ /* point at our hash table / objects, enable interrupts */ -+ nv_wr32(dev, 0x610010, (disp->mem->vinst >> 8) | 9); -+ nv_mask(dev, 0x6100b0, 0x00000307, 0x00000307); -+ -+ /* init master */ -+ nv_wr32(dev, 0x610494, (disp->evo[0].handle >> 8) | 3); -+ nv_wr32(dev, 0x610498, 0x00010000); -+ nv_wr32(dev, 0x61049c, 0x00000001); -+ nv_mask(dev, 0x610490, 0x00000010, 0x00000010); -+ nv_wr32(dev, 0x640000, 0x00000000); -+ nv_wr32(dev, 0x610490, 0x01000013); -+ if (!nv_wait(dev, 0x610490, 0x80000000, 0x00000000)) { -+ NV_ERROR(dev, "PDISP: master 0x%08x\n", -+ nv_rd32(dev, 0x610490)); -+ return -EBUSY; -+ } -+ nv_mask(dev, 0x610090, 0x00000001, 0x00000001); -+ nv_mask(dev, 0x6100a0, 0x00000001, 0x00000001); -+ -+ /* init cursors */ -+ for (i = 13; i <= 14; i++) { -+ nv_wr32(dev, 0x610490 + (i * 0x10), 0x00000001); -+ if (!nv_wait(dev, 0x610490 + (i * 0x10), 0x00010000, 0x00010000)) { -+ NV_ERROR(dev, "PDISP: curs%d 0x%08x\n", i, -+ nv_rd32(dev, 0x610490 + (i * 0x10))); -+ return -EBUSY; -+ } -+ -+ nv_mask(dev, 0x610090, 1 << i, 1 << i); -+ nv_mask(dev, 0x6100a0, 1 << i, 1 << i); -+ } -+ -+ push = evo_wait(dev, 0, 32); -+ if (!push) -+ return -EBUSY; -+ evo_mthd(push, 0x0088, 1); -+ evo_data(push, NvEvoSync); -+ evo_mthd(push, 0x0084, 1); -+ evo_data(push, 0x00000000); -+ evo_mthd(push, 0x0084, 1); -+ evo_data(push, 0x80000000); -+ evo_mthd(push, 0x008c, 1); -+ evo_data(push, 0x00000000); -+ evo_kick(push, dev, 0); -+ -+ return 0; -+} -+ -+void -+nvd0_display_destroy(struct drm_device *dev) -+{ -+ struct drm_nouveau_private *dev_priv = dev->dev_private; -+ struct nvd0_display *disp = nvd0_display(dev); -+ struct pci_dev *pdev = dev->pdev; -+ -+ nvd0_display_fini(dev); -+ -+ pci_free_consistent(pdev, PAGE_SIZE, disp->evo[0].ptr, disp->evo[0].handle); -+ nouveau_gpuobj_ref(NULL, &disp->mem); -+ nouveau_irq_unregister(dev, 26); -+ -+ dev_priv->engine.display.priv = NULL; -+ kfree(disp); -+} -+ -+int -+nvd0_display_create(struct drm_device *dev) -+{ -+ struct drm_nouveau_private *dev_priv = dev->dev_private; -+ struct nouveau_instmem_engine *pinstmem = &dev_priv->engine.instmem; -+ struct dcb_table *dcb = &dev_priv->vbios.dcb; -+ struct drm_connector *connector, *tmp; -+ struct pci_dev *pdev = dev->pdev; -+ struct nvd0_display *disp; -+ struct dcb_entry *dcbe; -+ int ret, i; -+ -+ disp = kzalloc(sizeof(*disp), GFP_KERNEL); -+ if (!disp) -+ return -ENOMEM; -+ dev_priv->engine.display.priv = disp; -+ -+ /* create crtc objects to represent the hw heads */ -+ for (i = 0; i < 2; i++) { -+ ret = nvd0_crtc_create(dev, i); -+ if (ret) -+ goto out; -+ } -+ -+ /* create encoder/connector objects based on VBIOS DCB table */ -+ for (i = 0, dcbe = &dcb->entry[0]; i < dcb->entries; i++, dcbe++) { -+ connector = nouveau_connector_create(dev, dcbe->connector); -+ if (IS_ERR(connector)) -+ continue; -+ -+ if (dcbe->location != DCB_LOC_ON_CHIP) { -+ NV_WARN(dev, "skipping off-chip encoder %d/%d\n", -+ dcbe->type, ffs(dcbe->or) - 1); -+ continue; -+ } -+ -+ switch (dcbe->type) { -+ case OUTPUT_TMDS: -+ case OUTPUT_LVDS: -+ nvd0_sor_create(connector, dcbe); -+ break; -+ case OUTPUT_ANALOG: -+ nvd0_dac_create(connector, dcbe); -+ break; -+ default: -+ NV_WARN(dev, "skipping unsupported encoder %d/%d\n", -+ dcbe->type, ffs(dcbe->or) - 1); -+ continue; -+ } -+ } -+ -+ /* cull any connectors we created that don't have an encoder */ -+ list_for_each_entry_safe(connector, tmp, &dev->mode_config.connector_list, head) { -+ if (connector->encoder_ids[0]) -+ continue; -+ -+ NV_WARN(dev, "%s has no encoders, removing\n", -+ drm_get_connector_name(connector)); -+ connector->funcs->destroy(connector); -+ } -+ -+ /* setup interrupt handling */ -+ tasklet_init(&disp->tasklet, nvd0_display_bh, (unsigned long)dev); -+ nouveau_irq_register(dev, 26, nvd0_display_intr); -+ -+ /* hash table and dma objects for the memory areas we care about */ -+ ret = nouveau_gpuobj_new(dev, NULL, 0x4000, 0x10000, -+ NVOBJ_FLAG_ZERO_ALLOC, &disp->mem); -+ if (ret) -+ goto out; -+ -+ nv_wo32(disp->mem, 0x1000, 0x00000049); -+ nv_wo32(disp->mem, 0x1004, (disp->mem->vinst + 0x2000) >> 8); -+ nv_wo32(disp->mem, 0x1008, (disp->mem->vinst + 0x2fff) >> 8); -+ nv_wo32(disp->mem, 0x100c, 0x00000000); -+ nv_wo32(disp->mem, 0x1010, 0x00000000); -+ nv_wo32(disp->mem, 0x1014, 0x00000000); -+ nv_wo32(disp->mem, 0x0000, NvEvoSync); -+ nv_wo32(disp->mem, 0x0004, (0x1000 << 9) | 0x00000001); -+ -+ nv_wo32(disp->mem, 0x1020, 0x00000049); -+ nv_wo32(disp->mem, 0x1024, 0x00000000); -+ nv_wo32(disp->mem, 0x1028, (dev_priv->vram_size - 1) >> 8); -+ nv_wo32(disp->mem, 0x102c, 0x00000000); -+ nv_wo32(disp->mem, 0x1030, 0x00000000); -+ nv_wo32(disp->mem, 0x1034, 0x00000000); -+ nv_wo32(disp->mem, 0x0008, NvEvoVRAM); -+ nv_wo32(disp->mem, 0x000c, (0x1020 << 9) | 0x00000001); -+ -+ nv_wo32(disp->mem, 0x1040, 0x00000009); -+ nv_wo32(disp->mem, 0x1044, 0x00000000); -+ nv_wo32(disp->mem, 0x1048, (dev_priv->vram_size - 1) >> 8); -+ nv_wo32(disp->mem, 0x104c, 0x00000000); -+ nv_wo32(disp->mem, 0x1050, 0x00000000); -+ nv_wo32(disp->mem, 0x1054, 0x00000000); -+ nv_wo32(disp->mem, 0x0010, NvEvoVRAM_LP); -+ nv_wo32(disp->mem, 0x0014, (0x1040 << 9) | 0x00000001); -+ -+ nv_wo32(disp->mem, 0x1060, 0x0fe00009); -+ nv_wo32(disp->mem, 0x1064, 0x00000000); -+ nv_wo32(disp->mem, 0x1068, (dev_priv->vram_size - 1) >> 8); -+ nv_wo32(disp->mem, 0x106c, 0x00000000); -+ nv_wo32(disp->mem, 0x1070, 0x00000000); -+ nv_wo32(disp->mem, 0x1074, 0x00000000); -+ nv_wo32(disp->mem, 0x0018, NvEvoFB32); -+ nv_wo32(disp->mem, 0x001c, (0x1060 << 9) | 0x00000001); -+ -+ pinstmem->flush(dev); -+ -+ /* push buffers for evo channels */ -+ disp->evo[0].ptr = -+ pci_alloc_consistent(pdev, PAGE_SIZE, &disp->evo[0].handle); -+ if (!disp->evo[0].ptr) { -+ ret = -ENOMEM; -+ goto out; -+ } -+ -+ ret = nvd0_display_init(dev); -+ if (ret) -+ goto out; -+ -+out: -+ if (ret) -+ nvd0_display_destroy(dev); -+ return ret; -+} |