summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/nouveau/nouveau_bios.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-10-03 23:29:23 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2012-10-03 23:29:23 -0700
commit612a9aab56a93533e76e3ad91642db7033e03b69 (patch)
tree8402096973f67af941f9392f7da06cca03e0b58a /drivers/gpu/drm/nouveau/nouveau_bios.c
parent3a494318b14b1bc0f59d2d6ce84c505c74d82d2a (diff)
parent268d28371cd326be4dfcd7eba5917bf4b9d30c8f (diff)
Merge branch 'drm-next' of git://people.freedesktop.org/~airlied/linux
Pull drm merge (part 1) from Dave Airlie: "So first of all my tree and uapi stuff has a conflict mess, its my fault as the nouveau stuff didn't hit -next as were trying to rebase regressions out of it before we merged. Highlights: - SH mobile modesetting driver and associated helpers - some DRM core documentation - i915 modesetting rework, haswell hdmi, haswell and vlv fixes, write combined pte writing, ilk rc6 support, - nouveau: major driver rework into a hw core driver, makes features like SLI a lot saner to implement, - psb: add eDP/DP support for Cedarview - radeon: 2 layer page tables, async VM pte updates, better PLL selection for > 2 screens, better ACPI interactions The rest is general grab bag of fixes. So why part 1? well I have the exynos pull req which came in a bit late but was waiting for me to do something they shouldn't have and it looks fairly safe, and David Howells has some more header cleanups he'd like me to pull, that seem like a good idea, but I'd like to get this merge out of the way so -next dosen't get blocked." Tons of conflicts mostly due to silly include line changes, but mostly mindless. A few other small semantic conflicts too, noted from Dave's pre-merged branch. * 'drm-next' of git://people.freedesktop.org/~airlied/linux: (447 commits) drm/nv98/crypt: fix fuc build with latest envyas drm/nouveau/devinit: fixup various issues with subdev ctor/init ordering drm/nv41/vm: fix and enable use of "real" pciegart drm/nv44/vm: fix and enable use of "real" pciegart drm/nv04/dmaobj: fixup vm target handling in preparation for nv4x pcie drm/nouveau: store supported dma mask in vmmgr drm/nvc0/ibus: initial implementation of subdev drm/nouveau/therm: add support for fan-control modes drm/nouveau/hwmon: rename pwm0* to pmw1* to follow hwmon's rules drm/nouveau/therm: calculate the pwm divisor on nv50+ drm/nouveau/fan: rewrite the fan tachometer driver to get more precision, faster drm/nouveau/therm: move thermal-related functions to the therm subdev drm/nouveau/bios: parse the pwm divisor from the perf table drm/nouveau/therm: use the EXTDEV table to detect i2c monitoring devices drm/nouveau/therm: rework thermal table parsing drm/nouveau/gpio: expose the PWM/TOGGLE parameter found in the gpio vbios table drm/nouveau: fix pm initialization order drm/nouveau/bios: check that fixed tvdac gpio data is valid before using it drm/nouveau: log channel debug/error messages from client object rather than drm client drm/nouveau: have drm debugging macros build on top of core macros ...
Diffstat (limited to 'drivers/gpu/drm/nouveau/nouveau_bios.c')
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_bios.c4567
1 files changed, 211 insertions, 4356 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c
index a84290562ca7..09fdef235882 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bios.c
+++ b/drivers/gpu/drm/nouveau/nouveau_bios.c
@@ -22,12 +22,14 @@
* SOFTWARE.
*/
+#include <subdev/bios.h>
+
#include <drm/drmP.h>
-#define NV_DEBUG_NOTRACE
-#include "nouveau_drv.h"
+
+#include "nouveau_drm.h"
+#include "nouveau_reg.h"
#include "nouveau_hw.h"
#include "nouveau_encoder.h"
-#include "nouveau_gpio.h"
#include <linux/io-mapping.h>
#include <linux/firmware.h>
@@ -65,3677 +67,6 @@ static bool nv_cksum(const uint8_t *data, unsigned int length)
return false;
}
-static int
-score_vbios(struct nvbios *bios, const bool writeable)
-{
- if (!bios->data || bios->data[0] != 0x55 || bios->data[1] != 0xAA) {
- NV_TRACEWARN(bios->dev, "... BIOS signature not found\n");
- return 0;
- }
-
- if (nv_cksum(bios->data, bios->data[2] * 512)) {
- NV_TRACEWARN(bios->dev, "... BIOS checksum invalid\n");
- /* if a ro image is somewhat bad, it's probably all rubbish */
- return writeable ? 2 : 1;
- }
-
- NV_TRACE(bios->dev, "... appears to be valid\n");
- return 3;
-}
-
-static void
-bios_shadow_prom(struct nvbios *bios)
-{
- struct drm_device *dev = bios->dev;
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- u32 pcireg, access;
- u16 pcir;
- int i;
-
- /* enable access to rom */
- if (dev_priv->card_type >= NV_50)
- pcireg = 0x088050;
- else
- pcireg = NV_PBUS_PCI_NV_20;
- access = nv_mask(dev, pcireg, 0x00000001, 0x00000000);
-
- /* bail if no rom signature, with a workaround for a PROM reading
- * issue on some chipsets. the first read after a period of
- * inactivity returns the wrong result, so retry the first header
- * byte a few times before giving up as a workaround
- */
- i = 16;
- do {
- if (nv_rd08(dev, NV_PROM_OFFSET + 0) == 0x55)
- break;
- } while (i--);
-
- if (!i || nv_rd08(dev, NV_PROM_OFFSET + 1) != 0xaa)
- goto out;
-
- /* additional check (see note below) - read PCI record header */
- pcir = nv_rd08(dev, NV_PROM_OFFSET + 0x18) |
- nv_rd08(dev, NV_PROM_OFFSET + 0x19) << 8;
- if (nv_rd08(dev, NV_PROM_OFFSET + pcir + 0) != 'P' ||
- nv_rd08(dev, NV_PROM_OFFSET + pcir + 1) != 'C' ||
- nv_rd08(dev, NV_PROM_OFFSET + pcir + 2) != 'I' ||
- nv_rd08(dev, NV_PROM_OFFSET + pcir + 3) != 'R')
- goto out;
-
- /* read entire bios image to system memory */
- bios->length = nv_rd08(dev, NV_PROM_OFFSET + 2) * 512;
- bios->data = kmalloc(bios->length, GFP_KERNEL);
- if (bios->data) {
- for (i = 0; i < bios->length; i++)
- bios->data[i] = nv_rd08(dev, NV_PROM_OFFSET + i);
- }
-
-out:
- /* disable access to rom */
- nv_wr32(dev, pcireg, access);
-}
-
-static void
-bios_shadow_pramin(struct nvbios *bios)
-{
- struct drm_device *dev = bios->dev;
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- u32 bar0 = 0;
- int i;
-
- if (dev_priv->card_type >= NV_50) {
- u64 addr = (u64)(nv_rd32(dev, 0x619f04) & 0xffffff00) << 8;
- if (!addr) {
- addr = (u64)nv_rd32(dev, 0x001700) << 16;
- addr += 0xf0000;
- }
-
- bar0 = nv_mask(dev, 0x001700, 0xffffffff, addr >> 16);
- }
-
- /* bail if no rom signature */
- if (nv_rd08(dev, NV_PRAMIN_OFFSET + 0) != 0x55 ||
- nv_rd08(dev, NV_PRAMIN_OFFSET + 1) != 0xaa)
- goto out;
-
- bios->length = nv_rd08(dev, NV_PRAMIN_OFFSET + 2) * 512;
- bios->data = kmalloc(bios->length, GFP_KERNEL);
- if (bios->data) {
- for (i = 0; i < bios->length; i++)
- bios->data[i] = nv_rd08(dev, NV_PRAMIN_OFFSET + i);
- }
-
-out:
- if (dev_priv->card_type >= NV_50)
- nv_wr32(dev, 0x001700, bar0);
-}
-
-static void
-bios_shadow_pci(struct nvbios *bios)
-{
- struct pci_dev *pdev = bios->dev->pdev;
- size_t length;
-
- if (!pci_enable_rom(pdev)) {
- void __iomem *rom = pci_map_rom(pdev, &length);
- if (rom && length) {
- bios->data = kmalloc(length, GFP_KERNEL);
- if (bios->data) {
- memcpy_fromio(bios->data, rom, length);
- bios->length = length;
- }
- }
- if (rom)
- pci_unmap_rom(pdev, rom);
-
- pci_disable_rom(pdev);
- }
-}
-
-static void
-bios_shadow_acpi(struct nvbios *bios)
-{
- struct pci_dev *pdev = bios->dev->pdev;
- int cnt = 65536 / ROM_BIOS_PAGE;
- int ret;
-
- if (!nouveau_acpi_rom_supported(pdev))
- return;
-
- bios->data = kmalloc(cnt * ROM_BIOS_PAGE, GFP_KERNEL);
- if (!bios->data)
- return;
-
- bios->length = 0;
- while (cnt--) {
- ret = nouveau_acpi_get_bios_chunk(bios->data, bios->length,
- ROM_BIOS_PAGE);
- if (ret != ROM_BIOS_PAGE)
- return;
-
- bios->length += ROM_BIOS_PAGE;
- }
-}
-
-struct methods {
- const char desc[8];
- void (*shadow)(struct nvbios *);
- const bool rw;
- int score;
- u32 size;
- u8 *data;
-};
-
-static bool
-bios_shadow(struct drm_device *dev)
-{
- struct methods shadow_methods[] = {
- { "PRAMIN", bios_shadow_pramin, true, 0, 0, NULL },
- { "PROM", bios_shadow_prom, false, 0, 0, NULL },
- { "ACPI", bios_shadow_acpi, true, 0, 0, NULL },
- { "PCIROM", bios_shadow_pci, true, 0, 0, NULL },
- {}
- };
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nvbios *bios = &dev_priv->vbios;
- struct methods *mthd, *best;
- const struct firmware *fw;
- char fname[32];
- int ret;
-
- if (nouveau_vbios) {
- /* try to match one of the built-in methods */
- mthd = shadow_methods;
- do {
- if (strcasecmp(nouveau_vbios, mthd->desc))
- continue;
- NV_INFO(dev, "VBIOS source: %s\n", mthd->desc);
-
- mthd->shadow(bios);
- mthd->score = score_vbios(bios, mthd->rw);
- if (mthd->score)
- return true;
- } while ((++mthd)->shadow);
-
- /* attempt to load firmware image */
- snprintf(fname, sizeof(fname), "nouveau/%s", nouveau_vbios);
- ret = request_firmware(&fw, fname, &dev->pdev->dev);
- if (ret == 0) {
- bios->length = fw->size;
- bios->data = kmemdup(fw->data, fw->size, GFP_KERNEL);
- release_firmware(fw);
-
- NV_INFO(dev, "VBIOS image: %s\n", nouveau_vbios);
- if (score_vbios(bios, 1))
- return true;
-
- kfree(bios->data);
- bios->data = NULL;
- }
-
- NV_ERROR(dev, "VBIOS source \'%s\' invalid\n", nouveau_vbios);
- }
-
- mthd = shadow_methods;
- do {
- NV_TRACE(dev, "Checking %s for VBIOS\n", mthd->desc);
- mthd->shadow(bios);
- mthd->score = score_vbios(bios, mthd->rw);
- mthd->size = bios->length;
- mthd->data = bios->data;
- bios->data = NULL;
- } while (mthd->score != 3 && (++mthd)->shadow);
-
- mthd = shadow_methods;
- best = mthd;
- do {
- if (mthd->score > best->score) {
- kfree(best->data);
- best = mthd;
- }
- } while ((++mthd)->shadow);
-
- if (best->score) {
- NV_TRACE(dev, "Using VBIOS from %s\n", best->desc);
- bios->length = best->size;
- bios->data = best->data;
- return true;
- }
-
- NV_ERROR(dev, "No valid VBIOS image found\n");
- return false;
-}
-
-struct init_tbl_entry {
- char *name;
- uint8_t id;
- /* Return:
- * > 0: success, length of opcode
- * 0: success, but abort further parsing of table (INIT_DONE etc)
- * < 0: failure, table parsing will be aborted
- */
- int (*handler)(struct nvbios *, uint16_t, struct init_exec *);
-};
-
-static int parse_init_table(struct nvbios *, uint16_t, struct init_exec *);
-
-#define MACRO_INDEX_SIZE 2
-#define MACRO_SIZE 8
-#define CONDITION_SIZE 12
-#define IO_FLAG_CONDITION_SIZE 9
-#define IO_CONDITION_SIZE 5
-#define MEM_INIT_SIZE 66
-
-static void still_alive(void)
-{
-#if 0
- sync();
- mdelay(2);
-#endif
-}
-
-static uint32_t
-munge_reg(struct nvbios *bios, uint32_t reg)
-{
- struct drm_nouveau_private *dev_priv = bios->dev->dev_private;
- struct dcb_entry *dcbent = bios->display.output;
-
- 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);
-
- reg += (ffs(dcbent->or) - 1) * 0x800;
- if ((reg & 0x20000000) && !(dcbent->sorconf.link & 1))
- reg += 0x00000080;
- }
-
- reg &= ~0xe0000000;
- return reg;
-}
-
-static int
-valid_reg(struct nvbios *bios, uint32_t reg)
-{
- struct drm_nouveau_private *dev_priv = bios->dev->dev_private;
- struct drm_device *dev = bios->dev;
-
- /* C51 has misaligned regs on purpose. Marvellous */
- if (reg & 0x2 ||
- (reg & 0x1 && dev_priv->vbios.chip_version != 0x51))
- NV_ERROR(dev, "======= misaligned reg 0x%08X =======\n", reg);
-
- /* warn on C51 regs that haven't been verified accessible in tracing */
- if (reg & 0x1 && dev_priv->vbios.chip_version == 0x51 &&
- reg != 0x130d && reg != 0x1311 && reg != 0x60081d)
- NV_WARN(dev, "=== C51 misaligned reg 0x%08X not verified ===\n",
- reg);
-
- if (reg >= (8*1024*1024)) {
- NV_ERROR(dev, "=== reg 0x%08x out of mapped bounds ===\n", reg);
- return 0;
- }
-
- return 1;
-}
-
-static bool
-valid_idx_port(struct nvbios *bios, uint16_t port)
-{
- struct drm_nouveau_private *dev_priv = bios->dev->dev_private;
- struct drm_device *dev = bios->dev;
-
- /*
- * If adding more ports here, the read/write functions below will need
- * updating so that the correct mmio range (PRMCIO, PRMDIO, PRMVIO) is
- * used for the port in question
- */
- if (dev_priv->card_type < NV_50) {
- if (port == NV_CIO_CRX__COLOR)
- return true;
- if (port == NV_VIO_SRX)
- return true;
- } else {
- if (port == NV_CIO_CRX__COLOR)
- return true;
- }
-
- NV_ERROR(dev, "========== unknown indexed io port 0x%04X ==========\n",
- port);
-
- return false;
-}
-
-static bool
-valid_port(struct nvbios *bios, uint16_t port)
-{
- struct drm_device *dev = bios->dev;
-
- /*
- * If adding more ports here, the read/write functions below will need
- * updating so that the correct mmio range (PRMCIO, PRMDIO, PRMVIO) is
- * used for the port in question
- */
- if (port == NV_VIO_VSE2)
- return true;
-
- NV_ERROR(dev, "========== unknown io port 0x%04X ==========\n", port);
-
- return false;
-}
-
-static uint32_t
-bios_rd32(struct nvbios *bios, uint32_t reg)
-{
- uint32_t data;
-
- reg = munge_reg(bios, reg);
- if (!valid_reg(bios, reg))
- return 0;
-
- /*
- * C51 sometimes uses regs with bit0 set in the address. For these
- * cases there should exist a translation in a BIOS table to an IO
- * port address which the BIOS uses for accessing the reg
- *
- * These only seem to appear for the power control regs to a flat panel,
- * and the GPIO regs at 0x60081*. In C51 mmio traces the normal regs
- * for 0x1308 and 0x1310 are used - hence the mask below. An S3
- * suspend-resume mmio trace from a C51 will be required to see if this
- * is true for the power microcode in 0x14.., or whether the direct IO
- * port access method is needed
- */
- if (reg & 0x1)
- reg &= ~0x1;
-
- data = nv_rd32(bios->dev, reg);
-
- BIOSLOG(bios, " Read: Reg: 0x%08X, Data: 0x%08X\n", reg, data);
-
- return data;
-}
-
-static void
-bios_wr32(struct nvbios *bios, uint32_t reg, uint32_t data)
-{
- struct drm_nouveau_private *dev_priv = bios->dev->dev_private;
-
- reg = munge_reg(bios, reg);
- if (!valid_reg(bios, reg))
- return;
-
- /* see note in bios_rd32 */
- if (reg & 0x1)
- reg &= 0xfffffffe;
-
- LOG_OLD_VALUE(bios_rd32(bios, reg));
- BIOSLOG(bios, " Write: Reg: 0x%08X, Data: 0x%08X\n", reg, data);
-
- if (dev_priv->vbios.execute) {
- still_alive();
- nv_wr32(bios->dev, reg, data);
- }
-}
-
-static uint8_t
-bios_idxprt_rd(struct nvbios *bios, uint16_t port, uint8_t index)
-{
- struct drm_nouveau_private *dev_priv = bios->dev->dev_private;
- struct drm_device *dev = bios->dev;
- uint8_t data;
-
- if (!valid_idx_port(bios, port))
- return 0;
-
- if (dev_priv->card_type < NV_50) {
- if (port == NV_VIO_SRX)
- data = NVReadVgaSeq(dev, bios->state.crtchead, index);
- else /* assume NV_CIO_CRX__COLOR */
- data = NVReadVgaCrtc(dev, bios->state.crtchead, index);
- } else {
- uint32_t data32;
-
- data32 = bios_rd32(bios, NV50_PDISPLAY_VGACRTC(index & ~3));
- data = (data32 >> ((index & 3) << 3)) & 0xff;
- }
-
- BIOSLOG(bios, " Indexed IO read: Port: 0x%04X, Index: 0x%02X, "
- "Head: 0x%02X, Data: 0x%02X\n",
- port, index, bios->state.crtchead, data);
- return data;
-}
-
-static void
-bios_idxprt_wr(struct nvbios *bios, uint16_t port, uint8_t index, uint8_t data)
-{
- struct drm_nouveau_private *dev_priv = bios->dev->dev_private;
- struct drm_device *dev = bios->dev;
-
- if (!valid_idx_port(bios, port))
- return;
-
- /*
- * The current head is maintained in the nvbios member state.crtchead.
- * We trap changes to CR44 and update the head variable and hence the
- * register set written.
- * As CR44 only exists on CRTC0, we update crtchead to head0 in advance
- * of the write, and to head1 after the write
- */
- if (port == NV_CIO_CRX__COLOR && index == NV_CIO_CRE_44 &&
- data != NV_CIO_CRE_44_HEADB)
- bios->state.crtchead = 0;
-
- LOG_OLD_VALUE(bios_idxprt_rd(bios, port, index));
- BIOSLOG(bios, " Indexed IO write: Port: 0x%04X, Index: 0x%02X, "
- "Head: 0x%02X, Data: 0x%02X\n",
- port, index, bios->state.crtchead, data);
-
- if (bios->execute && dev_priv->card_type < NV_50) {
- still_alive();
- if (port == NV_VIO_SRX)
- NVWriteVgaSeq(dev, bios->state.crtchead, index, data);
- else /* assume NV_CIO_CRX__COLOR */
- NVWriteVgaCrtc(dev, bios->state.crtchead, index, data);
- } else
- if (bios->execute) {
- uint32_t data32, shift = (index & 3) << 3;
-
- still_alive();
-
- data32 = bios_rd32(bios, NV50_PDISPLAY_VGACRTC(index & ~3));
- data32 &= ~(0xff << shift);
- data32 |= (data << shift);
- bios_wr32(bios, NV50_PDISPLAY_VGACRTC(index & ~3), data32);
- }
-
- if (port == NV_CIO_CRX__COLOR &&
- index == NV_CIO_CRE_44 && data == NV_CIO_CRE_44_HEADB)
- bios->state.crtchead = 1;
-}
-
-static uint8_t
-bios_port_rd(struct nvbios *bios, uint16_t port)
-{
- uint8_t data, head = bios->state.crtchead;
-
- if (!valid_port(bios, port))
- return 0;
-
- data = NVReadPRMVIO(bios->dev, head, NV_PRMVIO0_OFFSET + port);
-
- BIOSLOG(bios, " IO read: Port: 0x%04X, Head: 0x%02X, Data: 0x%02X\n",
- port, head, data);
-
- return data;
-}
-
-static void
-bios_port_wr(struct nvbios *bios, uint16_t port, uint8_t data)
-{
- int head = bios->state.crtchead;
-
- if (!valid_port(bios, port))
- return;
-
- LOG_OLD_VALUE(bios_port_rd(bios, port));
- BIOSLOG(bios, " IO write: Port: 0x%04X, Head: 0x%02X, Data: 0x%02X\n",
- port, head, data);
-
- if (!bios->execute)
- return;
-
- still_alive();
- NVWritePRMVIO(bios->dev, head, NV_PRMVIO0_OFFSET + port, data);
-}
-
-static bool
-io_flag_condition_met(struct nvbios *bios, uint16_t offset, uint8_t cond)
-{
- /*
- * The IO flag condition entry has 2 bytes for the CRTC port; 1 byte
- * for the CRTC index; 1 byte for the mask to apply to the value
- * retrieved from the CRTC; 1 byte for the shift right to apply to the
- * masked CRTC value; 2 bytes for the offset to the flag array, to
- * which the shifted value is added; 1 byte for the mask applied to the
- * value read from the flag array; and 1 byte for the value to compare
- * against the masked byte from the flag table.
- */
-
- uint16_t condptr = bios->io_flag_condition_tbl_ptr + cond * IO_FLAG_CONDITION_SIZE;
- uint16_t crtcport = ROM16(bios->data[condptr]);
- uint8_t crtcindex = bios->data[condptr + 2];
- uint8_t mask = bios->data[condptr + 3];
- uint8_t shift = bios->data[condptr + 4];
- uint16_t flagarray = ROM16(bios->data[condptr + 5]);
- uint8_t flagarraymask = bios->data[condptr + 7];
- uint8_t cmpval = bios->data[condptr + 8];
- uint8_t data;
-
- BIOSLOG(bios, "0x%04X: Port: 0x%04X, Index: 0x%02X, Mask: 0x%02X, "
- "Shift: 0x%02X, FlagArray: 0x%04X, FAMask: 0x%02X, "
- "Cmpval: 0x%02X\n",
- offset, crtcport, crtcindex, mask, shift, flagarray, flagarraymask, cmpval);
-
- data = bios_idxprt_rd(bios, crtcport, crtcindex);
-
- data = bios->data[flagarray + ((data & mask) >> shift)];
- data &= flagarraymask;
-
- BIOSLOG(bios, "0x%04X: Checking if 0x%02X equals 0x%02X\n",
- offset, data, cmpval);
-
- return (data == cmpval);
-}
-
-static bool
-bios_condition_met(struct nvbios *bios, uint16_t offset, uint8_t cond)
-{
- /*
- * The condition table entry has 4 bytes for the address of the
- * register to check, 4 bytes for a mask to apply to the register and
- * 4 for a test comparison value
- */
-
- uint16_t condptr = bios->condition_tbl_ptr + cond * CONDITION_SIZE;
- uint32_t reg = ROM32(bios->data[condptr]);
- uint32_t mask = ROM32(bios->data[condptr + 4]);
- uint32_t cmpval = ROM32(bios->data[condptr + 8]);
- uint32_t data;
-
- BIOSLOG(bios, "0x%04X: Cond: 0x%02X, Reg: 0x%08X, Mask: 0x%08X\n",
- offset, cond, reg, mask);
-
- data = bios_rd32(bios, reg) & mask;
-
- BIOSLOG(bios, "0x%04X: Checking if 0x%08X equals 0x%08X\n",
- offset, data, cmpval);
-
- return (data == cmpval);
-}
-
-static bool
-io_condition_met(struct nvbios *bios, uint16_t offset, uint8_t cond)
-{
- /*
- * The IO condition entry has 2 bytes for the IO port address; 1 byte
- * for the index to write to io_port; 1 byte for the mask to apply to
- * the byte read from io_port+1; and 1 byte for the value to compare
- * against the masked byte.
- */
-
- uint16_t condptr = bios->io_condition_tbl_ptr + cond * IO_CONDITION_SIZE;
- uint16_t io_port = ROM16(bios->data[condptr]);
- uint8_t port_index = bios->data[condptr + 2];
- uint8_t mask = bios->data[condptr + 3];
- uint8_t cmpval = bios->data[condptr + 4];
-
- uint8_t data = bios_idxprt_rd(bios, io_port, port_index) & mask;
-
- BIOSLOG(bios, "0x%04X: Checking if 0x%02X equals 0x%02X\n",
- offset, data, cmpval);
-
- return (data == cmpval);
-}
-
-static int
-nv50_pll_set(struct drm_device *dev, uint32_t reg, uint32_t clk)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_pll_vals pll;
- struct pll_lims pll_limits;
- u32 ctrl, mask, coef;
- int ret;
-
- ret = get_pll_limits(dev, reg, &pll_limits);
- if (ret)
- return ret;
-
- clk = nouveau_calc_pll_mnp(dev, &pll_limits, clk, &pll);
- if (!clk)
- return -ERANGE;
-
- coef = pll.N1 << 8 | pll.M1;
- ctrl = pll.log2P << 16;
- mask = 0x00070000;
- if (reg == 0x004008) {
- mask |= 0x01f80000;
- ctrl |= (pll_limits.log2p_bias << 19);
- ctrl |= (pll.log2P << 22);
- }
-
- if (!dev_priv->vbios.execute)
- return 0;
-
- nv_mask(dev, reg + 0, mask, ctrl);
- nv_wr32(dev, reg + 4, coef);
- return 0;
-}
-
-static int
-setPLL(struct nvbios *bios, uint32_t reg, uint32_t clk)
-{
- struct drm_device *dev = bios->dev;
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- /* clk in kHz */
- struct pll_lims pll_lim;
- struct nouveau_pll_vals pllvals;
- int ret;
-
- if (dev_priv->card_type >= NV_50)
- return nv50_pll_set(dev, reg, clk);
-
- /* high regs (such as in the mac g5 table) are not -= 4 */
- ret = get_pll_limits(dev, reg > 0x405c ? reg : reg - 4, &pll_lim);
- if (ret)
- return ret;
-
- clk = nouveau_calc_pll_mnp(dev, &pll_lim, clk, &pllvals);
- if (!clk)
- return -ERANGE;
-
- if (bios->execute) {
- still_alive();
- nouveau_hw_setpll(dev, reg, &pllvals);
- }
-
- return 0;
-}
-
-static int dcb_entry_idx_from_crtchead(struct drm_device *dev)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nvbios *bios = &dev_priv->vbios;
-
- /*
- * For the results of this function to be correct, CR44 must have been
- * set (using bios_idxprt_wr to set crtchead), CR58 set for CR57 = 0,
- * and the DCB table parsed, before the script calling the function is
- * run. run_digital_op_script is example of how to do such setup
- */
-
- uint8_t dcb_entry = NVReadVgaCrtc5758(dev, bios->state.crtchead, 0);
-
- if (dcb_entry > bios->dcb.entries) {
- NV_ERROR(dev, "CR58 doesn't have a valid DCB entry currently "
- "(%02X)\n", dcb_entry);
- dcb_entry = 0x7f; /* unused / invalid marker */
- }
-
- return dcb_entry;
-}
-
-static struct nouveau_i2c_chan *
-init_i2c_device_find(struct drm_device *dev, int i2c_index)
-{
- if (i2c_index == 0xff) {
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct dcb_table *dcb = &dev_priv->vbios.dcb;
- /* note: dcb_entry_idx_from_crtchead needs pre-script set-up */
- int idx = dcb_entry_idx_from_crtchead(dev);
-
- i2c_index = NV_I2C_DEFAULT(0);
- if (idx != 0x7f && dcb->entry[idx].i2c_upper_default)
- i2c_index = NV_I2C_DEFAULT(1);
- }
-
- return nouveau_i2c_find(dev, i2c_index);
-}
-
-static uint32_t
-get_tmds_index_reg(struct drm_device *dev, uint8_t mlv)
-{
- /*
- * For mlv < 0x80, it is an index into a table of TMDS base addresses.
- * For mlv == 0x80 use the "or" value of the dcb_entry indexed by
- * CR58 for CR57 = 0 to index a table of offsets to the basic
- * 0x6808b0 address.
- * For mlv == 0x81 use the "or" value of the dcb_entry indexed by
- * CR58 for CR57 = 0 to index a table of offsets to the basic
- * 0x6808b0 address, and then flip the offset by 8.
- */
-
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nvbios *bios = &dev_priv->vbios;
- const int pramdac_offset[13] = {
- 0, 0, 0x8, 0, 0x2000, 0, 0, 0, 0x2008, 0, 0, 0, 0x2000 };
- const uint32_t pramdac_table[4] = {
- 0x6808b0, 0x6808b8, 0x6828b0, 0x6828b8 };
-
- if (mlv >= 0x80) {
- int dcb_entry, dacoffset;
-
- /* note: dcb_entry_idx_from_crtchead needs pre-script set-up */
- dcb_entry = dcb_entry_idx_from_crtchead(dev);
- if (dcb_entry == 0x7f)
- return 0;
- dacoffset = pramdac_offset[bios->dcb.entry[dcb_entry].or];
- if (mlv == 0x81)
- dacoffset ^= 8;
- return 0x6808b0 + dacoffset;
- } else {
- if (mlv >= ARRAY_SIZE(pramdac_table)) {
- NV_ERROR(dev, "Magic Lookup Value too big (%02X)\n",
- mlv);
- return 0;
- }
- return pramdac_table[mlv];
- }
-}
-
-static int
-init_io_restrict_prog(struct nvbios *bios, uint16_t offset,
- struct init_exec *iexec)
-{
- /*
- * INIT_IO_RESTRICT_PROG opcode: 0x32 ('2')
- *
- * offset (8 bit): opcode
- * offset + 1 (16 bit): CRTC port
- * offset + 3 (8 bit): CRTC index
- * offset + 4 (8 bit): mask
- * offset + 5 (8 bit): shift
- * offset + 6 (8 bit): count
- * offset + 7 (32 bit): register
- * offset + 11 (32 bit): configuration 1
- * ...
- *
- * Starting at offset + 11 there are "count" 32 bit values.
- * To find out which value to use read index "CRTC index" on "CRTC
- * port", AND this value with "mask" and then bit shift right "shift"
- * bits. Read the appropriate value using this index and write to
- * "register"
- */
-
- uint16_t crtcport = ROM16(bios->data[offset + 1]);
- uint8_t crtcindex = bios->data[offset + 3];
- uint8_t mask = bios->data[offset + 4];
- uint8_t shift = bios->data[offset + 5];
- uint8_t count = bios->data[offset + 6];
- uint32_t reg = ROM32(bios->data[offset + 7]);
- uint8_t config;
- uint32_t configval;
- int len = 11 + count * 4;
-
- if (!iexec->execute)
- return len;
-
- BIOSLOG(bios, "0x%04X: Port: 0x%04X, Index: 0x%02X, Mask: 0x%02X, "
- "Shift: 0x%02X, Count: 0x%02X, Reg: 0x%08X\n",
- offset, crtcport, crtcindex, mask, shift, count, reg);
-
- config = (bios_idxprt_rd(bios, crtcport, crtcindex) & mask) >> shift;
- if (config > count) {
- NV_ERROR(bios->dev,
- "0x%04X: Config 0x%02X exceeds maximal bound 0x%02X\n",
- offset, config, count);
- return len;
- }
-
- configval = ROM32(bios->data[offset + 11 + config * 4]);
-
- BIOSLOG(bios, "0x%04X: Writing config %02X\n", offset, config);
-
- bios_wr32(bios, reg, configval);
-
- return len;
-}
-
-static int
-init_repeat(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
-{
- /*
- * INIT_REPEAT opcode: 0x33 ('3')
- *
- * offset (8 bit): opcode
- * offset + 1 (8 bit): count
- *
- * Execute script following this opcode up to INIT_REPEAT_END
- * "count" times
- */
-
- uint8_t count = bios->data[offset + 1];
- uint8_t i;
-
- /* no iexec->execute check by design */
-
- BIOSLOG(bios, "0x%04X: Repeating following segment %d times\n",
- offset, count);
-
- iexec->repeat = true;
-
- /*
- * count - 1, as the script block will execute once when we leave this
- * opcode -- this is compatible with bios behaviour as:
- * a) the block is always executed at least once, even if count == 0
- * b) the bios interpreter skips to the op following INIT_END_REPEAT,
- * while we don't
- */
- for (i = 0; i < count - 1; i++)
- parse_init_table(bios, offset + 2, iexec);
-
- iexec->repeat = false;
-
- return 2;
-}
-
-static int
-init_io_restrict_pll(struct nvbios *bios, uint16_t offset,
- struct init_exec *iexec)
-{
- /*
- * INIT_IO_RESTRICT_PLL opcode: 0x34 ('4')
- *
- * offset (8 bit): opcode
- * offset + 1 (16 bit): CRTC port
- * offset + 3 (8 bit): CRTC index
- * offset + 4 (8 bit): mask
- * offset + 5 (8 bit): shift
- * offset + 6 (8 bit): IO flag condition index
- * offset + 7 (8 bit): count
- * offset + 8 (32 bit): register
- * offset + 12 (16 bit): frequency 1
- * ...
- *
- * Starting at offset + 12 there are "count" 16 bit frequencies (10kHz).
- * Set PLL register "register" to coefficients for frequency n,
- * selected by reading index "CRTC index" of "CRTC port" ANDed with
- * "mask" and shifted right by "shift".
- *
- * If "IO flag condition index" > 0, and condition met, double
- * frequency before setting it.
- */
-
- uint16_t crtcport = ROM16(bios->data[offset + 1]);
- uint8_t crtcindex = bios->data[offset + 3];
- uint8_t mask = bios->data[offset + 4];
- uint8_t shift = bios->data[offset + 5];
- int8_t io_flag_condition_idx = bios->data[offset + 6];
- uint8_t count = bios->data[offset + 7];
- uint32_t reg = ROM32(bios->data[offset + 8]);
- uint8_t config;
- uint16_t freq;
- int len = 12 + count * 2;
-
- if (!iexec->execute)
- return len;
-
- BIOSLOG(bios, "0x%04X: Port: 0x%04X, Index: 0x%02X, Mask: 0x%02X, "
- "Shift: 0x%02X, IO Flag Condition: 0x%02X, "
- "Count: 0x%02X, Reg: 0x%08X\n",
- offset, crtcport, crtcindex, mask, shift,
- io_flag_condition_idx, count, reg);
-
- config = (bios_idxprt_rd(bios, crtcport, crtcindex) & mask) >> shift;
- if (config > count) {
- NV_ERROR(bios->dev,
- "0x%04X: Config 0x%02X exceeds maximal bound 0x%02X\n",
- offset, config, count);
- return len;
- }
-
- freq = ROM16(bios->data[offset + 12 + config * 2]);
-
- if (io_flag_condition_idx > 0) {
- if (io_flag_condition_met(bios, offset, io_flag_condition_idx)) {
- BIOSLOG(bios, "0x%04X: Condition fulfilled -- "
- "frequency doubled\n", offset);
- freq *= 2;
- } else
- BIOSLOG(bios, "0x%04X: Condition not fulfilled -- "
- "frequency unchanged\n", offset);
- }
-
- BIOSLOG(bios, "0x%04X: Reg: 0x%08X, Config: 0x%02X, Freq: %d0kHz\n",
- offset, reg, config, freq);
-
- setPLL(bios, reg, freq * 10);
-
- return len;
-}
-
-static int
-init_end_repeat(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
-{
- /*
- * INIT_END_REPEAT opcode: 0x36 ('6')
- *
- * offset (8 bit): opcode
- *
- * Marks the end of the block for INIT_REPEAT to repeat
- */
-
- /* no iexec->execute check by design */
-
- /*
- * iexec->repeat flag necessary to go past INIT_END_REPEAT opcode when
- * we're not in repeat mode
- */
- if (iexec->repeat)
- return 0;
-
- return 1;
-}
-
-static int
-init_copy(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
-{
- /*
- * INIT_COPY opcode: 0x37 ('7')
- *
- * offset (8 bit): opcode
- * offset + 1 (32 bit): register
- * offset + 5 (8 bit): shift
- * offset + 6 (8 bit): srcmask
- * offset + 7 (16 bit): CRTC port
- * offset + 9 (8 bit): CRTC index
- * offset + 10 (8 bit): mask
- *
- * Read index "CRTC index" on "CRTC port", AND with "mask", OR with
- * (REGVAL("register") >> "shift" & "srcmask") and write-back to CRTC
- * port
- */
-
- uint32_t reg = ROM32(bios->data[offset + 1]);
- uint8_t shift = bios->data[offset + 5];
- uint8_t srcmask = bios->data[offset + 6];
- uint16_t crtcport = ROM16(bios->data[offset + 7]);
- uint8_t crtcindex = bios->data[offset + 9];
- uint8_t mask = bios->data[offset + 10];
- uint32_t data;
- uint8_t crtcdata;
-
- if (!iexec->execute)
- return 11;
-
- BIOSLOG(bios, "0x%04X: Reg: 0x%08X, Shift: 0x%02X, SrcMask: 0x%02X, "
- "Port: 0x%04X, Index: 0x%02X, Mask: 0x%02X\n",
- offset, reg, shift, srcmask, crtcport, crtcindex, mask);
-
- data = bios_rd32(bios, reg);
-
- if (shift < 0x80)
- data >>= shift;
- else
- data <<= (0x100 - shift);
-
- data &= srcmask;
-
- crtcdata = bios_idxprt_rd(bios, crtcport, crtcindex) & mask;
- crtcdata |= (uint8_t)data;
- bios_idxprt_wr(bios, crtcport, crtcindex, crtcdata);
-
- return 11;
-}
-
-static int
-init_not(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
-{
- /*
- * INIT_NOT opcode: 0x38 ('8')
- *
- * offset (8 bit): opcode
- *
- * Invert the current execute / no-execute condition (i.e. "else")
- */
- if (iexec->execute)
- BIOSLOG(bios, "0x%04X: ------ Skipping following commands ------\n", offset);
- else
- BIOSLOG(bios, "0x%04X: ------ Executing following commands ------\n", offset);
-
- iexec->execute = !iexec->execute;
- return 1;
-}
-
-static int
-init_io_flag_condition(struct nvbios *bios, uint16_t offset,
- struct init_exec *iexec)
-{
- /*
- * INIT_IO_FLAG_CONDITION opcode: 0x39 ('9')
- *
- * offset (8 bit): opcode
- * offset + 1 (8 bit): condition number
- *
- * Check condition "condition number" in the IO flag condition table.
- * If condition not met skip subsequent opcodes until condition is
- * inverted (INIT_NOT), or we hit INIT_RESUME
- */
-
- uint8_t cond = bios->data[offset + 1];
-
- if (!iexec->execute)
- return 2;
-
- if (io_flag_condition_met(bios, offset, cond))
- BIOSLOG(bios, "0x%04X: Condition fulfilled -- continuing to execute\n", offset);
- else {
- BIOSLOG(bios, "0x%04X: Condition not fulfilled -- skipping following commands\n", offset);
- iexec->execute = false;
- }
-
- return 2;
-}
-
-static int
-init_dp_condition(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
-{
- /*
- * INIT_DP_CONDITION opcode: 0x3A ('')
- *
- * offset (8 bit): opcode
- * offset + 1 (8 bit): "sub" opcode
- * offset + 2 (8 bit): unknown
- *
- */
-
- struct dcb_entry *dcb = bios->display.output;