Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c3b6ef86 authored by Dave Airlie's avatar Dave Airlie
Browse files

Merge remote branch 'nouveau/for-airlied' of /ssd/git/drm-nouveau-next into drm-core-next

* 'nouveau/for-airlied' of /ssd/git/drm-nouveau-next: (27 commits)
  drm/nvc0: fix typo in PRAMIN flush
  drm/nouveau: Fix DCB TMDS config parsing.
  drm/nv30: Fix PFB init for nv31.
  drm/nv04: Fix up SGRAM density detection.
  drm/i2c/ch7006: Don't use POWER_LEVEL_FULL_POWER_OFF on early chip versions.
  drm/nouveau: Init dcb->or on cards that have no usable DCB table.
  drm/nouveau: reduce severity of some "error" messages
  drm/nvc0: backup bar3 channel on suspend
  drm/nouveau: implement init table opcodex 0x5e and 0x9a
  drm/nouveau: implement init table op 0x57, INIT_LTIME
  drm/nvc0: implement crtc pll setting
  drm/nvc0: fix evo dma object so we display something
  drm/nvc0: rudimentary instmem support
  drm/nvc0: implement memory detection
  drm/nvc0: allow INIT_GPIO
  drm/nvc0: starting point for GF100 support, everything stubbed
  drm/nv30: Workaround dual TMDS brain damage.
  drm/nouveau: No need to set slave TV encoder configs explicitly.
  drm/nv17-nv4x: Attempt to init some external TMDS transmitters.
  drm/nv10: Fix up switching of NV10TCL_DMA_VTXBUF.
  ...
parents d8ab3557 2dc5d2ec
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -470,6 +470,7 @@ static int ch7006_encoder_init(struct i2c_client *client,
	priv->hmargin = 50;
	priv->vmargin = 50;
	priv->last_dpms = -1;
	priv->chip_version = ch7006_read(client, CH7006_VERSION_ID);

	if (ch7006_tv_norm) {
		for (i = 0; i < NUM_TV_NORMS; i++) {
+4 −1
Original line number Diff line number Diff line
@@ -316,7 +316,10 @@ void ch7006_setup_power_state(struct drm_encoder *encoder)
		}

	} else {
		if (priv->chip_version >= 0x20)
			*power |= bitfs(CH7006_POWER_LEVEL, FULL_POWER_OFF);
		else
			*power |= bitfs(CH7006_POWER_LEVEL, POWER_OFF);
	}
}

+1 −0
Original line number Diff line number Diff line
@@ -95,6 +95,7 @@ struct ch7006_priv {
	int flicker;
	int scale;

	int chip_version;
	int last_dpms;
};

+4 −4
Original line number Diff line number Diff line
@@ -12,12 +12,12 @@ nouveau-y := nouveau_drv.o nouveau_state.o nouveau_channel.o nouveau_mem.o \
             nouveau_dp.o \
             nv04_timer.o \
             nv04_mc.o nv40_mc.o nv50_mc.o \
             nv04_fb.o nv10_fb.o nv30_fb.o nv40_fb.o nv50_fb.o \
             nv04_fifo.o nv10_fifo.o nv40_fifo.o nv50_fifo.o \
             nv04_fb.o nv10_fb.o nv30_fb.o nv40_fb.o nv50_fb.o nvc0_fb.o \
             nv04_fifo.o nv10_fifo.o nv40_fifo.o nv50_fifo.o nvc0_fifo.o \
             nv04_graph.o nv10_graph.o nv20_graph.o \
             nv40_graph.o nv50_graph.o \
             nv40_graph.o nv50_graph.o nvc0_graph.o \
             nv40_grctx.o nv50_grctx.o \
             nv04_instmem.o nv50_instmem.o \
             nv04_instmem.o nv50_instmem.o nvc0_instmem.o \
             nv50_crtc.o nv50_dac.o nv50_sor.o \
             nv50_cursor.o nv50_display.o nv50_fbcon.o \
             nv04_dac.o nv04_dfp.o nv04_tv.o nv17_tv.o nv17_tv_modes.o \
+182 −12
Original line number Diff line number Diff line
@@ -1927,6 +1927,31 @@ init_condition_time(struct nvbios *bios, uint16_t offset,
	return 3;
}

static int
init_ltime(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
{
	/*
	 * INIT_LTIME   opcode: 0x57 ('V')
	 *
	 * offset      (8  bit): opcode
	 * offset + 1  (16 bit): time
	 *
	 * Sleep for "time" miliseconds.
	 */

	unsigned time = ROM16(bios->data[offset + 1]);

	if (!iexec->execute)
		return 3;

	BIOSLOG(bios, "0x%04X: Sleeping for 0x%04X miliseconds\n",
		offset, time);

	msleep(time);

	return 3;
}

static int
init_zm_reg_sequence(struct nvbios *bios, uint16_t offset,
		     struct init_exec *iexec)
@@ -1994,6 +2019,64 @@ init_sub_direct(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
	return 3;
}

static int
init_i2c_if(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
{
	/*
	 * INIT_I2C_IF   opcode: 0x5E ('^')
	 *
	 * offset      (8 bit): opcode
	 * offset + 1  (8 bit): DCB I2C table entry index
	 * offset + 2  (8 bit): I2C slave address
	 * offset + 3  (8 bit): I2C register
	 * offset + 4  (8 bit): mask
	 * offset + 5  (8 bit): data
	 *
	 * Read the register given by "I2C register" on the device addressed
	 * by "I2C slave address" on the I2C bus given by "DCB I2C table
	 * entry index". Compare the result AND "mask" to "data".
	 * If they're not equal, skip subsequent opcodes until condition is
	 * inverted (INIT_NOT), or we hit INIT_RESUME
	 */

	uint8_t i2c_index = bios->data[offset + 1];
	uint8_t i2c_address = bios->data[offset + 2] >> 1;
	uint8_t reg = bios->data[offset + 3];
	uint8_t mask = bios->data[offset + 4];
	uint8_t data = bios->data[offset + 5];
	struct nouveau_i2c_chan *chan;
	union i2c_smbus_data val;
	int ret;

	/* no execute check by design */

	BIOSLOG(bios, "0x%04X: DCBI2CIndex: 0x%02X, I2CAddress: 0x%02X\n",
		offset, i2c_index, i2c_address);

	chan = init_i2c_device_find(bios->dev, i2c_index);
	if (!chan)
		return -ENODEV;

	ret = i2c_smbus_xfer(&chan->adapter, i2c_address, 0,
			     I2C_SMBUS_READ, reg,
			     I2C_SMBUS_BYTE_DATA, &val);
	if (ret < 0) {
		BIOSLOG(bios, "0x%04X: I2CReg: 0x%02X, Value: [no device], "
			      "Mask: 0x%02X, Data: 0x%02X\n",
			offset, reg, mask, data);
		iexec->execute = 0;
		return 6;
	}

	BIOSLOG(bios, "0x%04X: I2CReg: 0x%02X, Value: 0x%02X, "
		      "Mask: 0x%02X, Data: 0x%02X\n",
		offset, reg, val.byte, mask, data);

	iexec->execute = ((val.byte & mask) == data);

	return 6;
}

static int
init_copy_nv_reg(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
{
@@ -2083,9 +2166,10 @@ peek_fb(struct drm_device *dev, struct io_mapping *fb,
	uint32_t val = 0;

	if (off < pci_resource_len(dev->pdev, 1)) {
		uint32_t __iomem *p = io_mapping_map_atomic_wc(fb, off, KM_USER0);
		uint32_t __iomem *p =
			io_mapping_map_atomic_wc(fb, off & PAGE_MASK, KM_USER0);

		val = ioread32(p);
		val = ioread32(p + (off & ~PAGE_MASK));

		io_mapping_unmap_atomic(p, KM_USER0);
	}
@@ -2098,9 +2182,10 @@ poke_fb(struct drm_device *dev, struct io_mapping *fb,
	uint32_t off, uint32_t val)
{
	if (off < pci_resource_len(dev->pdev, 1)) {
		uint32_t __iomem *p = io_mapping_map_atomic_wc(fb, off, KM_USER0);
		uint32_t __iomem *p =
			io_mapping_map_atomic_wc(fb, off & PAGE_MASK, KM_USER0);

		iowrite32(val, p);
		iowrite32(val, p + (off & ~PAGE_MASK));
		wmb();

		io_mapping_unmap_atomic(p, KM_USER0);
@@ -2165,7 +2250,7 @@ nv04_init_compute_mem(struct nvbios *bios)
			  NV04_PFB_BOOT_0_RAM_AMOUNT,
			  NV04_PFB_BOOT_0_RAM_AMOUNT_4MB);

	} else if (peek_fb(dev, fb, 0) == patt) {
	} else if (peek_fb(dev, fb, 0) != patt) {
		if (read_back_fb(dev, fb, 0x800000, patt))
			bios_md32(bios, NV04_PFB_BOOT_0,
				  NV04_PFB_BOOT_0_RAM_AMOUNT,
@@ -2593,7 +2678,7 @@ init_configure_preinit(struct nvbios *bios, uint16_t offset,
	/* no iexec->execute check by design */

	uint32_t straps = bios_rd32(bios, NV_PEXTDEV_BOOT_0);
	uint8_t cr3c = ((straps << 2) & 0xf0) | (straps & (1 << 6));
	uint8_t cr3c = ((straps << 2) & 0xf0) | (straps & 0x40) >> 6;

	if (bios->major_version > 2)
		return 0;
@@ -3140,7 +3225,7 @@ init_gpio(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
	const uint32_t nv50_gpio_ctl[2] = { 0xe100, 0xe28c };
	int i;

	if (dev_priv->card_type != NV_50) {
	if (dev_priv->card_type < NV_50) {
		NV_ERROR(bios->dev, "INIT_GPIO on unsupported chipset\n");
		return 1;
	}
@@ -3490,6 +3575,69 @@ init_zm_auxch(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
	return len;
}

static int
init_i2c_long_if(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
{
	/*
	 * INIT_I2C_LONG_IF   opcode: 0x9A ('')
	 *
	 * offset      (8 bit): opcode
	 * offset + 1  (8 bit): DCB I2C table entry index
	 * offset + 2  (8 bit): I2C slave address
	 * offset + 3  (16 bit): I2C register
	 * offset + 5  (8 bit): mask
	 * offset + 6  (8 bit): data
	 *
	 * Read the register given by "I2C register" on the device addressed
	 * by "I2C slave address" on the I2C bus given by "DCB I2C table
	 * entry index". Compare the result AND "mask" to "data".
	 * If they're not equal, skip subsequent opcodes until condition is
	 * inverted (INIT_NOT), or we hit INIT_RESUME
	 */

	uint8_t i2c_index = bios->data[offset + 1];
	uint8_t i2c_address = bios->data[offset + 2] >> 1;
	uint8_t reglo = bios->data[offset + 3];
	uint8_t reghi = bios->data[offset + 4];
	uint8_t mask = bios->data[offset + 5];
	uint8_t data = bios->data[offset + 6];
	struct nouveau_i2c_chan *chan;
	uint8_t buf0[2] = { reghi, reglo };
	uint8_t buf1[1];
	struct i2c_msg msg[2] = {
		{ i2c_address, 0, 1, buf0 },
		{ i2c_address, I2C_M_RD, 1, buf1 },
	};
	int ret;

	/* no execute check by design */

	BIOSLOG(bios, "0x%04X: DCBI2CIndex: 0x%02X, I2CAddress: 0x%02X\n",
		offset, i2c_index, i2c_address);

	chan = init_i2c_device_find(bios->dev, i2c_index);
	if (!chan)
		return -ENODEV;


	ret = i2c_transfer(&chan->adapter, msg, 2);
	if (ret < 0) {
		BIOSLOG(bios, "0x%04X: I2CReg: 0x%02X:0x%02X, Value: [no device], "
			      "Mask: 0x%02X, Data: 0x%02X\n",
			offset, reghi, reglo, mask, data);
		iexec->execute = 0;
		return 7;
	}

	BIOSLOG(bios, "0x%04X: I2CReg: 0x%02X:0x%02X, Value: 0x%02X, "
		      "Mask: 0x%02X, Data: 0x%02X\n",
		offset, reghi, reglo, buf1[0], mask, data);

	iexec->execute = ((buf1[0] & mask) == data);

	return 7;
}

static struct init_tbl_entry itbl_entry[] = {
	/* command name                       , id  , length  , offset  , mult    , command handler                 */
	/* INIT_PROG (0x31, 15, 10, 4) removed due to no example of use */
@@ -3516,9 +3664,11 @@ static struct init_tbl_entry itbl_entry[] = {
	{ "INIT_ZM_CR"                        , 0x53, init_zm_cr                      },
	{ "INIT_ZM_CR_GROUP"                  , 0x54, init_zm_cr_group                },
	{ "INIT_CONDITION_TIME"               , 0x56, init_condition_time             },
	{ "INIT_LTIME"                        , 0x57, init_ltime                      },
	{ "INIT_ZM_REG_SEQUENCE"              , 0x58, init_zm_reg_sequence            },
	/* INIT_INDIRECT_REG (0x5A, 7, 0, 0) removed due to no example of use */
	{ "INIT_SUB_DIRECT"                   , 0x5B, init_sub_direct                 },
	{ "INIT_I2C_IF"                       , 0x5E, init_i2c_if                     },
	{ "INIT_COPY_NV_REG"                  , 0x5F, init_copy_nv_reg                },
	{ "INIT_ZM_INDEX_IO"                  , 0x62, init_zm_index_io                },
	{ "INIT_COMPUTE_MEM"                  , 0x63, init_compute_mem                },
@@ -3552,6 +3702,7 @@ static struct init_tbl_entry itbl_entry[] = {
	{ "INIT_97"                           , 0x97, init_97                         },
	{ "INIT_AUXCH"                        , 0x98, init_auxch                      },
	{ "INIT_ZM_AUXCH"                     , 0x99, init_zm_auxch                   },
	{ "INIT_I2C_LONG_IF"                  , 0x9A, init_i2c_long_if                },
	{ NULL                                , 0   , NULL                            }
};

@@ -4410,7 +4561,7 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent,
					  bios->display.script_table_ptr,
					  table[2], table[3], table[0] >= 0x21);
	if (!otable) {
		NV_ERROR(dev, "Couldn't find matching output script table\n");
		NV_DEBUG_KMS(dev, "failed to match any output table\n");
		return 1;
	}

@@ -4467,7 +4618,7 @@ nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent,
		if (script)
			script = clkcmptable(bios, script, pxclk);
		if (!script) {
			NV_ERROR(dev, "clock script 0 not found\n");
			NV_DEBUG_KMS(dev, "clock script 0 not found\n");
			return 1;
		}

@@ -4826,7 +4977,7 @@ int get_pll_limits(struct drm_device *dev, uint32_t limit_match, struct pll_lims
		pll_lim->min_p = record[12];
		pll_lim->max_p = record[13];
		/* where did this go to?? */
		if (limit_match == 0x00614100 || limit_match == 0x00614900)
		if ((entry[0] & 0xf0) == 0x80)
			pll_lim->refclk = 27000;
		else
			pll_lim->refclk = 100000;
@@ -5852,7 +6003,7 @@ static void fabricate_vga_output(struct dcb_table *dcb, int i2c, int heads)
	entry->i2c_index = i2c;
	entry->heads = heads;
	entry->location = DCB_LOC_ON_CHIP;
	/* "or" mostly unused in early gen crt modesetting, 0 is fine */
	entry->or = 1;
}

static void fabricate_dvi_i_output(struct dcb_table *dcb, bool twoHeads)
@@ -5980,7 +6131,13 @@ parse_dcb20_entry(struct drm_device *dev, struct dcb_table *dcb,
		}
		break;
	case OUTPUT_TMDS:
		if (dcb->version >= 0x40)
			entry->tmdsconf.sor.link = (conf & 0x00000030) >> 4;
		else if (dcb->version >= 0x30)
			entry->tmdsconf.slave_addr = (conf & 0x00000700) >> 8;
		else if (dcb->version >= 0x22)
			entry->tmdsconf.slave_addr = (conf & 0x00000070) >> 4;

		break;
	case 0xe:
		/* weird g80 mobile type that "nv" treats as a terminator */
@@ -6270,6 +6427,19 @@ parse_dcb_table(struct drm_device *dev, struct nvbios *bios, bool twoHeads)
		dcb->i2c_table = &bios->data[i2ctabptr];
		if (dcb->version >= 0x30)
			dcb->i2c_default_indices = dcb->i2c_table[4];

		/*
		 * Parse the "management" I2C bus, used for hardware
		 * monitoring and some external TMDS transmitters.
		 */
		if (dcb->version >= 0x22) {
			int idx = (dcb->version >= 0x40 ?
				   dcb->i2c_default_indices & 0xf :
				   2);

			read_dcb_i2c_entry(dev, dcb->version, dcb->i2c_table,
					   idx, &dcb->i2c[idx]);
		}
	}

	if (entries > DCB_MAX_NUM_ENTRIES)
Loading