diff options
Diffstat (limited to 'drivers/gpu/drm/nouveau/core/subdev/bios/init.c')
-rw-r--r-- | drivers/gpu/drm/nouveau/core/subdev/bios/init.c | 66 |
1 files changed, 62 insertions, 4 deletions
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/init.c b/drivers/gpu/drm/nouveau/core/subdev/bios/init.c index ae168bb..690ed43 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/bios/init.c +++ b/drivers/gpu/drm/nouveau/core/subdev/bios/init.c @@ -2,11 +2,12 @@ #include <core/device.h> #include <subdev/bios.h> -#include <subdev/bios/conn.h> #include <subdev/bios/bmp.h> #include <subdev/bios/bit.h> +#include <subdev/bios/conn.h> #include <subdev/bios/dcb.h> #include <subdev/bios/dp.h> +#include <subdev/bios/gpio.h> #include <subdev/bios/init.h> #include <subdev/devinit.h> #include <subdev/clock.h> @@ -410,9 +411,25 @@ init_ram_restrict_group_count(struct nvbios_init *init) } static u8 +init_ram_restrict_strap(struct nvbios_init *init) +{ + /* This appears to be the behaviour of the VBIOS parser, and *is* + * important to cache the NV_PEXTDEV_BOOT0 on later chipsets to + * avoid fucking up the memory controller (somehow) by reading it + * on every INIT_RAM_RESTRICT_ZM_GROUP opcode. + * + * Preserving the non-caching behaviour on earlier chipsets just + * in case *not* re-reading the strap causes similar breakage. + */ + if (!init->ramcfg || init->bios->version.major < 0x70) + init->ramcfg = init_rd32(init, 0x101000); + return (init->ramcfg & 0x00000003c) >> 2; +} + +static u8 init_ram_restrict(struct nvbios_init *init) { - u32 strap = (init_rd32(init, 0x101000) & 0x0000003c) >> 2; + u8 strap = init_ram_restrict_strap(init); u16 table = init_ram_restrict_table(init); if (table) return nv_ro08(init->bios, table + strap); @@ -1517,7 +1534,6 @@ init_io(struct nvbios_init *init) mdelay(10); init_wr32(init, 0x614100, 0x10000018); init_wr32(init, 0x614900, 0x10000018); - return; } value = init_rdport(init, port) & mask; @@ -1781,7 +1797,7 @@ init_gpio(struct nvbios_init *init) init->offset += 1; if (init_exec(init) && gpio && gpio->reset) - gpio->reset(gpio); + gpio->reset(gpio, DCB_GPIO_UNUSED); } /** @@ -1995,6 +2011,47 @@ init_i2c_long_if(struct nvbios_init *init) init_exec_set(init, false); } +/** + * INIT_GPIO_NE - opcode 0xa9 + * + */ +static void +init_gpio_ne(struct nvbios_init *init) +{ + struct nouveau_bios *bios = init->bios; + struct nouveau_gpio *gpio = nouveau_gpio(bios); + struct dcb_gpio_func func; + u8 count = nv_ro08(bios, init->offset + 1); + u8 idx = 0, ver, len; + u16 data, i; + + trace("GPIO_NE\t"); + init->offset += 2; + + for (i = init->offset; i < init->offset + count; i++) + cont("0x%02x ", nv_ro08(bios, i)); + cont("\n"); + + while ((data = dcb_gpio_parse(bios, 0, idx++, &ver, &len, &func))) { + if (func.func != DCB_GPIO_UNUSED) { + for (i = init->offset; i < init->offset + count; i++) { + if (func.func == nv_ro08(bios, i)) + break; + } + + trace("\tFUNC[0x%02x]", func.func); + if (i == (init->offset + count)) { + cont(" *"); + if (init_exec(init) && gpio && gpio->reset) + gpio->reset(gpio, func.func); + } + cont("\n"); + } + } + + init->offset += count; +} + static struct nvbios_init_opcode { void (*exec)(struct nvbios_init *); } init_opcode[] = { @@ -2059,6 +2116,7 @@ static struct nvbios_init_opcode { [0x98] = { init_auxch }, [0x99] = { init_zm_auxch }, [0x9a] = { init_i2c_long_if }, + [0xa9] = { init_gpio_ne }, }; #define init_opcode_nr (sizeof(init_opcode) / sizeof(init_opcode[0])) |