From 473a1997ace1a9fb545d0457549e50d17eb36175 Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Sun, 22 Jun 2008 16:29:00 +0200 Subject: NV50: Initial import of kernel modesetting. --- linux-core/Makefile | 2 +- linux-core/Makefile.kernel | 5 +- linux-core/drm_crtc.c | 1 + linux-core/drm_crtc.h | 1 + linux-core/drm_edid.c | 34 +- linux-core/drm_modes.c | 5 +- linux-core/nouveau_bios.c | 815 +++++++++++++++++++++++++++++++ linux-core/nouveau_bios.h | 151 ++++++ linux-core/nouveau_drv.c | 7 + linux-core/nv50_connector.c | 207 ++++++++ linux-core/nv50_connector.h | 60 +++ linux-core/nv50_crtc.c | 515 ++++++++++++++++++++ linux-core/nv50_crtc.h | 67 +++ linux-core/nv50_cursor.c | 177 +++++++ linux-core/nv50_cursor.h | 51 ++ linux-core/nv50_dac.c | 177 +++++++ linux-core/nv50_display.c | 337 +++++++++++++ linux-core/nv50_display.h | 83 ++++ linux-core/nv50_display_commands.h | 196 ++++++++ linux-core/nv50_fb.c | 136 ++++++ linux-core/nv50_fb.h | 55 +++ linux-core/nv50_i2c.c | 356 ++++++++++++++ linux-core/nv50_i2c.h | 47 ++ linux-core/nv50_kms_wrapper.c | 960 +++++++++++++++++++++++++++++++++++++ linux-core/nv50_kms_wrapper.h | 94 ++++ linux-core/nv50_lut.c | 171 +++++++ linux-core/nv50_lut.h | 45 ++ linux-core/nv50_output.c | 33 ++ linux-core/nv50_output.h | 60 +++ linux-core/nv50_sor.c | 204 ++++++++ shared-core/nouveau_dma.h | 5 + shared-core/nouveau_drv.h | 26 + shared-core/nouveau_irq.c | 80 +++- shared-core/nouveau_mem.c | 11 + shared-core/nouveau_reg.h | 298 ++++++++++++ shared-core/nouveau_state.c | 50 +- 36 files changed, 5503 insertions(+), 19 deletions(-) create mode 100644 linux-core/nouveau_bios.c create mode 100644 linux-core/nouveau_bios.h create mode 100644 linux-core/nv50_connector.c create mode 100644 linux-core/nv50_connector.h create mode 100644 linux-core/nv50_crtc.c create mode 100644 linux-core/nv50_crtc.h create mode 100644 linux-core/nv50_cursor.c create mode 100644 linux-core/nv50_cursor.h create mode 100644 linux-core/nv50_dac.c create mode 100644 linux-core/nv50_display.c create mode 100644 linux-core/nv50_display.h create mode 100644 linux-core/nv50_display_commands.h create mode 100644 linux-core/nv50_fb.c create mode 100644 linux-core/nv50_fb.h create mode 100644 linux-core/nv50_i2c.c create mode 100644 linux-core/nv50_i2c.h create mode 100644 linux-core/nv50_kms_wrapper.c create mode 100644 linux-core/nv50_kms_wrapper.h create mode 100644 linux-core/nv50_lut.c create mode 100644 linux-core/nv50_lut.h create mode 100644 linux-core/nv50_output.c create mode 100644 linux-core/nv50_output.h create mode 100644 linux-core/nv50_sor.c diff --git a/linux-core/Makefile b/linux-core/Makefile index b9405bbb..9b288851 100644 --- a/linux-core/Makefile +++ b/linux-core/Makefile @@ -90,7 +90,7 @@ VIAHEADERS = via_drm.h via_drv.h via_3d_reg.h via_verifier.h $(DRMHEADERS) MACH64HEADERS = mach64_drv.h mach64_drm.h $(DRMHEADERS) NVHEADERS = nv_drv.h $(DRMHEADERS) FFBHEADERS = ffb_drv.h $(DRMHEADERS) -NOUVEAUHEADERS = nouveau_drv.h nouveau_drm.h nouveau_reg.h $(DRMHEADERS) +NOUVEAUHEADERS = nouveau_drv.h nouveau_drm.h nouveau_reg.h nouveau_display.h $(DRMHEADERS) XGIHEADERS = xgi_cmdlist.h xgi_drv.h xgi_misc.h xgi_regs.h $(DRMHEADERS) RADEONMSHEADERS = radeon_ms_driver.h $(DRMHEADERS) diff --git a/linux-core/Makefile.kernel b/linux-core/Makefile.kernel index ac9baf02..23430140 100644 --- a/linux-core/Makefile.kernel +++ b/linux-core/Makefile.kernel @@ -35,7 +35,10 @@ nouveau-objs := nouveau_drv.o nouveau_state.o nouveau_fifo.o nouveau_mem.o \ nv04_fifo.o nv10_fifo.o nv40_fifo.o nv50_fifo.o \ nv04_graph.o nv10_graph.o nv20_graph.o \ nv40_graph.o nv50_graph.o \ - nv04_instmem.o nv50_instmem.o + nv04_instmem.o nv50_instmem.o \ + nouveau_bios.o \ + nv50_crtc.o nv50_cursor.o nv50_lut.o nv50_fb.o nv50_output.o nv50_sor.o nv50_dac.o nv50_connector.o nv50_i2c.o nv50_display.o \ + nv50_kms_wrapper.o radeon-objs := radeon_drv.o radeon_cp.o radeon_state.o radeon_mem.o radeon_irq.o r300_cmdbuf.o radeon_ms-objs := radeon_ms_drv.o radeon_ms_drm.o radeon_ms_family.o \ radeon_ms_state.o radeon_ms_bo.o radeon_ms_irq.o \ diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index e1b371cc..c8cfaef4 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -100,6 +100,7 @@ char *drm_get_connector_name(struct drm_connector *connector) connector->connector_type_id); return buf; } +EXPORT_SYMBOL(drm_get_connector_name); char *drm_get_connector_status_name(enum drm_connector_status status) { diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index 2b577b93..d6fa4cca 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -619,6 +619,7 @@ extern void drm_fb_release(struct file *filp); extern int drm_mode_group_init_legacy_group(struct drm_device *dev, struct drm_mode_group *group); extern struct edid *drm_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter); +extern unsigned char *drm_do_probe_ddc_edid(struct i2c_adapter *adapter); extern int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid); extern void drm_mode_probed_add(struct drm_connector *connector, struct drm_display_mode *mode); extern void drm_mode_remove(struct drm_connector *connector, struct drm_display_mode *mode); diff --git a/linux-core/drm_edid.c b/linux-core/drm_edid.c index 0d600396..812e64a6 100644 --- a/linux-core/drm_edid.c +++ b/linux-core/drm_edid.c @@ -122,19 +122,30 @@ static bool edid_is_valid(struct edid *edid) if (memcmp(edid->header, edid_header, sizeof(edid_header))) goto bad; - if (edid->version != 1) + if (edid->version != 1) { + DRM_ERROR("EDID has major version %d, instead of 1\n", edid->version); goto bad; - if (edid->revision <= 0 || edid->revision > 3) + } + if (edid->revision <= 0 || edid->revision > 3) { + DRM_ERROR("EDID has minor version %d, which is not between 0-3\n", edid->revision); goto bad; + } for (i = 0; i < EDID_LENGTH; i++) csum += raw_edid[i]; - if (csum) + if (csum) { + DRM_ERROR("EDID checksum is invalid, remainder is %d\n", csum); goto bad; + } return 1; bad: + if (raw_edid) { + DRM_ERROR("Raw EDID:\n"); + print_hex_dump_bytes(KERN_ERR, DUMP_PREFIX_NONE, raw_edid, EDID_LENGTH); + printk("\n"); + } return 0; } @@ -545,7 +556,7 @@ static int add_detailed_info(struct drm_connector *connector, #define DDC_ADDR 0x50 -static unsigned char *drm_do_probe_ddc_edid(struct i2c_adapter *adapter) +unsigned char *drm_do_probe_ddc_edid(struct i2c_adapter *adapter) { unsigned char start = 0x0; unsigned char *buf = kmalloc(EDID_LENGTH, GFP_KERNEL); @@ -576,6 +587,7 @@ static unsigned char *drm_do_probe_ddc_edid(struct i2c_adapter *adapter) kfree(buf); return NULL; } +EXPORT_SYMBOL(drm_do_probe_ddc_edid); static unsigned char *drm_ddc_read(struct i2c_adapter *adapter) { @@ -589,15 +601,15 @@ static unsigned char *drm_ddc_read(struct i2c_adapter *adapter) * Then set clock & data low */ algo_data->setscl(algo_data->data, 1); - udelay(550); /* startup delay */ - algo_data->setscl(algo_data->data, 0); - algo_data->setsda(algo_data->data, 0); + //udelay(550); /* startup delay */ + //algo_data->setscl(algo_data->data, 0); + //algo_data->setsda(algo_data->data, 0); for (i = 0; i < 3; i++) { /* For some old monitors we need the * following process to initialize/stop DDC */ - algo_data->setsda(algo_data->data, 0); + algo_data->setsda(algo_data->data, 1); msleep(13); algo_data->setscl(algo_data->data, 1); @@ -632,16 +644,16 @@ static unsigned char *drm_ddc_read(struct i2c_adapter *adapter) algo_data->setsda(algo_data->data, 1); msleep(15); algo_data->setscl(algo_data->data, 0); + algo_data->setsda(algo_data->data, 0); if (edid) break; } /* Release the DDC lines when done or the Apple Cinema HD display * will switch off */ - algo_data->setsda(algo_data->data, 0); - algo_data->setscl(algo_data->data, 0); + algo_data->setsda(algo_data->data, 1); algo_data->setscl(algo_data->data, 1); - + return edid; } diff --git a/linux-core/drm_modes.c b/linux-core/drm_modes.c index 3ed427fb..df670c74 100644 --- a/linux-core/drm_modes.c +++ b/linux-core/drm_modes.c @@ -89,6 +89,7 @@ void drm_mode_list_concat(struct list_head *head, struct list_head *new) list_move_tail(entry, new); } } +EXPORT_SYMBOL(drm_mode_list_concat); /** * drm_mode_width - get the width of a mode @@ -401,6 +402,7 @@ void drm_mode_prune_invalid(struct drm_device *dev, } } } +EXPORT_SYMBOL(drm_mode_prune_invalid); /** * drm_mode_compare - compare modes for favorability @@ -525,7 +527,7 @@ void drm_mode_sort(struct list_head *mode_list) { list_sort(mode_list, drm_mode_compare); } - +EXPORT_SYMBOL(drm_mode_sort); /** * drm_mode_connector_list_update - update the mode list for the connector @@ -564,3 +566,4 @@ void drm_mode_connector_list_update(struct drm_connector *connector) } } } +EXPORT_SYMBOL(drm_mode_connector_list_update); diff --git a/linux-core/nouveau_bios.c b/linux-core/nouveau_bios.c new file mode 100644 index 00000000..83647418 --- /dev/null +++ b/linux-core/nouveau_bios.c @@ -0,0 +1,815 @@ +/* + * Copyright (C) 2005-2006 Erik Waling + * Copyright (C) 2006 Stephane Marchesin + * Copyright (C) 2007-2008 Stuart Bennett + * Copyright (C) 2008 Maarten Maathuis. + * All Rights Reserved. + * + * 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 (including the + * next paragraph) 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 OWNER(S) AND/OR ITS SUPPLIERS 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. + * + */ + +#include +#include "nouveau_bios.h" +#include "nouveau_drv.h" + +/* returns true if it mismatches */ +static bool nv_checksum(const uint8_t *data, unsigned int length) +{ + /* there's a few checksums in the BIOS, so here's a generic checking function */ + int i; + uint8_t sum = 0; + + for (i = 0; i < length; i++) + sum += data[i]; + + if (sum) + return true; + + return false; +} + +static int nv_valid_bios(struct drm_device *dev, uint8_t *data) +{ + /* check for BIOS signature */ + if (!(data[0] == 0x55 && data[1] == 0xAA)) { + DRM_ERROR("BIOS signature not found.\n"); + return 0; + } + + if (nv_checksum(data, data[2] * 512)) { + DRM_ERROR("BIOS checksum invalid.\n"); + return 1; + } + + return 2; +} + +static void nv_shadow_bios_rom(struct drm_device *dev, uint8_t *data) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + int i; + + /* enable access to rom */ + NV_WRITE(NV04_PBUS_PCI_NV_20, NV04_PBUS_PCI_NV_20_ROM_SHADOW_DISABLED); + + /* This is also valid for pre-NV50, it just happened to be the only define already present. */ + for (i=0; i < NV50_PROM__ESIZE; i++) { + /* Appearantly needed for a 6600GT/6800LE bug. */ + data[i] = DRM_READ8(dev_priv->mmio, NV50_PROM + i); + data[i] = DRM_READ8(dev_priv->mmio, NV50_PROM + i); + data[i] = DRM_READ8(dev_priv->mmio, NV50_PROM + i); + data[i] = DRM_READ8(dev_priv->mmio, NV50_PROM + i); + data[i] = DRM_READ8(dev_priv->mmio, NV50_PROM + i); + } + + /* disable access to rom */ + NV_WRITE(NV04_PBUS_PCI_NV_20, NV04_PBUS_PCI_NV_20_ROM_SHADOW_ENABLED); +} + +static void nv_shadow_bios_ramin(struct drm_device *dev, uint8_t *data) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + uint32_t old_bar0_pramin = 0; + int i; + + /* Move the bios copy to the start of ramin? */ + if (dev_priv->card_type >= NV_50) { + uint32_t vbios_vram = (NV_READ(0x619f04) & ~0xff) << 8; + + if (!vbios_vram) + vbios_vram = (NV_READ(0x1700) << 16) + 0xf0000; + + old_bar0_pramin = NV_READ(0x1700); + NV_WRITE(0x1700, vbios_vram >> 16); + } + + for (i=0; i < NV50_PROM__ESIZE; i++) + data[i] = DRM_READ8(dev_priv->mmio, NV04_PRAMIN + i); + + if (dev_priv->card_type >= NV_50) + NV_WRITE(0x1700, old_bar0_pramin); +} + +static bool nv_shadow_bios(struct drm_device *dev, uint8_t *data) +{ + nv_shadow_bios_rom(dev, data); + if (nv_valid_bios(dev, data) == 2) + return true; + + nv_shadow_bios_ramin(dev, data); + if (nv_valid_bios(dev, data)) + return true; + + return false; +} + +struct bit_entry { + uint8_t id[2]; + uint16_t length; + uint16_t offset; +}; + +static int parse_bit_C_tbl_entry(struct drm_device *dev, struct bios *bios, struct bit_entry *bitentry) +{ + /* offset + 8 (16 bits): PLL limits table pointer + * + * There's more in here, but that's unknown. + */ + + if (bitentry->length < 10) { + DRM_ERROR( "Do not understand BIT C table\n"); + return 0; + } + + bios->pll_limit_tbl_ptr = le16_to_cpu(*((uint16_t *)(&bios->data[bitentry->offset + 8]))); + + return 1; +} + +static void parse_bit_structure(struct drm_device *dev, struct bios *bios, const uint16_t bitoffset) +{ + int entries = bios->data[bitoffset + 4]; + /* parse i first, I next (which needs C & M before it), and L before D */ + char parseorder[] = "iCMILDT"; + struct bit_entry bitentry; + int i, j, offset; + + for (i = 0; i < sizeof(parseorder); i++) { + for (j = 0, offset = bitoffset + 6; j < entries; j++, offset += 6) { + bitentry.id[0] = bios->data[offset]; + bitentry.id[1] = bios->data[offset + 1]; + bitentry.length = le16_to_cpu(*((uint16_t *)&bios->data[offset + 2])); + bitentry.offset = le16_to_cpu(*((uint16_t *)&bios->data[offset + 4])); + + if (bitentry.id[0] != parseorder[i]) + continue; + + switch (bitentry.id[0]) { + case 'C': + parse_bit_C_tbl_entry(dev, bios, &bitentry); + break; + } + } + } +} + +static uint16_t findstr(uint8_t *data, int n, const uint8_t *str, int len) +{ + int i, j; + + for (i = 0; i <= (n - len); i++) { + for (j = 0; j < len; j++) + if (data[i + j] != str[j]) + break; + if (j == len) + return i; + } + + return 0; +} + +static void +read_dcb_i2c_entry(struct drm_device *dev, uint8_t dcb_version, uint16_t i2ctabptr, int index) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct bios *bios = &dev_priv->bios; + uint8_t *i2ctable = &bios->data[i2ctabptr]; + uint8_t headerlen = 0; + int i2c_entries = MAX_NUM_DCB_ENTRIES; + int recordoffset = 0, rdofs = 1, wrofs = 0; + + if (!i2ctabptr) + return; + + if (dcb_version >= 0x30) { + if (i2ctable[0] != dcb_version) /* necessary? */ + DRM_ERROR( + "DCB I2C table version mismatch (%02X vs %02X)\n", + i2ctable[0], dcb_version); + headerlen = i2ctable[1]; + i2c_entries = i2ctable[2]; + + /* same address offset used for read and write for C51 and G80 */ + if (bios->chip_version == 0x51) + rdofs = wrofs = 1; + if (i2ctable[0] >= 0x40) + rdofs = wrofs = 0; + } + /* it's your own fault if you call this function on a DCB 1.1 BIOS -- + * the test below is for DCB 1.2 + */ + if (dcb_version < 0x14) { + recordoffset = 2; + rdofs = 0; + wrofs = 1; + } + + if (index == 0xf) + return; + if (index > i2c_entries) { + DRM_ERROR( + "DCB I2C index too big (%d > %d)\n", + index, i2ctable[2]); + return; + } + if (i2ctable[headerlen + 4 * index + 3] == 0xff) { + DRM_ERROR( + "DCB I2C entry invalid\n"); + return; + } + + if (bios->chip_version == 0x51) { + int port_type = i2ctable[headerlen + 4 * index + 3]; + + if (port_type != 4) + DRM_ERROR( + "DCB I2C table has port type %d\n", port_type); + } + if (i2ctable[0] >= 0x40) { + int port_type = i2ctable[headerlen + 4 * index + 3]; + + if (port_type != 5) + DRM_ERROR( + "DCB I2C table has port type %d\n", port_type); + } + + dev_priv->dcb_table.i2c_read[index] = i2ctable[headerlen + recordoffset + rdofs + 4 * index]; + dev_priv->dcb_table.i2c_write[index] = i2ctable[headerlen + recordoffset + wrofs + 4 * index]; +} + +static bool +parse_dcb_entry(struct drm_device *dev, int index, uint8_t dcb_version, uint16_t i2ctabptr, uint32_t conn, uint32_t conf) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct dcb_entry *entry = &dev_priv->dcb_table.entry[index]; + + memset(entry, 0, sizeof (struct dcb_entry)); + + entry->index = index; + /* safe defaults for a crt */ + entry->type = 0; + entry->i2c_index = 0; + entry->heads = 1; + entry->bus = 0; + entry->location = LOC_ON_CHIP; + entry->or = 1; + entry->duallink_possible = false; + + if (dcb_version >= 0x20) { + entry->type = conn & 0xf; + entry->i2c_index = (conn >> 4) & 0xf; + entry->heads = (conn >> 8) & 0xf; + entry->bus = (conn >> 16) & 0xf; + entry->location = (conn >> 20) & 0xf; + entry->or = (conn >> 24) & 0xf; + /* Normal entries consist of a single bit, but dual link has the + * adjacent more significant bit set too + */ + if ((1 << (ffs(entry->or) - 1)) * 3 == entry->or) + entry->duallink_possible = true; + + switch (entry->type) { + case DCB_OUTPUT_LVDS: + { + uint32_t mask; + if (conf & 0x1) + entry->lvdsconf.use_straps_for_mode = true; + if (dcb_version < 0x22) { + mask = ~0xd; + /* both 0x4 and 0x8 show up in v2.0 tables; assume they mean + * the same thing, which is probably wrong, but might work */ + if (conf & 0x4 || conf & 0x8) + entry->lvdsconf.use_power_scripts = true; + } else { + mask = ~0x5; + if (conf & 0x4) + entry->lvdsconf.use_power_scripts = true; + } + if (conf & mask) { + DRM_ERROR( + "Unknown LVDS configuration bits, please report\n"); + /* cause output setting to fail, so message is seen */ + dev_priv->dcb_table.entries = 0; + return false; + } + break; + } + case 0xe: + /* weird type that appears on g80 mobile bios; nv driver treats it as a terminator */ + return false; + } + read_dcb_i2c_entry(dev, dcb_version, i2ctabptr, entry->i2c_index); + } else if (dcb_version >= 0x14 ) { + if (conn != 0xf0003f00 && conn != 0xf2247f10 && conn != 0xf2204001 && conn != 0xf2204301 && conn != 0xf2244311 && conn != 0xf2045f14 && conn != 0xf2205004 && conn != 0xf2208001 && conn != 0xf4204011 && conn != 0xf4208011 && conn != 0xf4248011) { + DRM_ERROR( + "Unknown DCB 1.4 / 1.5 entry, please report\n"); + /* cause output setting to fail, so message is seen */ + dev_priv->dcb_table.entries = 0; + return false; + } + /* most of the below is a "best guess" atm */ + entry->type = conn & 0xf; + if (entry->type == 4) { /* digital */ + if (conn & 0x10) + entry->type = DCB_OUTPUT_LVDS; + else + entry->type = DCB_OUTPUT_TMDS; + } + /* what's in bits 5-13? could be some brooktree/chrontel/philips thing, in tv case */ + entry->i2c_index = (conn >> 14) & 0xf; + /* raw heads field is in range 0-1, so move to 1-2 */ + entry->heads = ((conn >> 18) & 0x7) + 1; + entry->location = (conn >> 21) & 0xf; + entry->bus = (conn >> 25) & 0x7; + /* set or to be same as heads -- hopefully safe enough */ + entry->or = entry->heads; + + switch (entry->type) { + case DCB_OUTPUT_LVDS: + /* this is probably buried in conn's unknown bits */ + entry->lvdsconf.use_power_scripts = true; + break; + case DCB_OUTPUT_TMDS: + /* invent a DVI-A output, by copying the fields of the DVI-D output + * reported to work by math_b on an NV20(!) */ + memcpy(&entry[1], &entry[0], sizeof(struct dcb_entry)); + entry[1].type = DCB_OUTPUT_ANALOG; + dev_priv->dcb_table.entries++; + } + read_dcb_i2c_entry(dev, dcb_version, i2ctabptr, entry->i2c_index); + } else if (dcb_version >= 0x12) { + /* v1.2 tables normally have the same 5 entries, which are not + * specific to the card, so use the defaults for a crt */ + /* DCB v1.2 does have an I2C table that read_dcb_i2c_table can handle, but cards + * exist (seen on nv11) where the pointer to the table points to the wrong + * place, so for now, we rely on the indices parsed in parse_bmp_structure + */ + entry->i2c_index = dev_priv->bios.legacy.i2c_indices.crt; + } else { /* pre DCB / v1.1 - use the safe defaults for a crt */ + DRM_ERROR( + "No information in BIOS output table; assuming a CRT output exists\n"); + entry->i2c_index = dev_priv->bios.legacy.i2c_indices.crt; + } + + if (entry->type == DCB_OUTPUT_LVDS && dev_priv->bios.fp.strapping != 0xff) + entry->lvdsconf.use_straps_for_mode = true; + + dev_priv->dcb_table.entries++; + + return true; +} + +static void merge_like_dcb_entries(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + + /* DCB v2.0 lists each output combination separately. + * Here we merge compatible entries to have fewer outputs, with more options + */ + int i, newentries = 0; + + for (i = 0; i < dev_priv->dcb_table.entries; i++) { + struct dcb_entry *ient = &dev_priv->dcb_table.entry[i]; + int j; + + for (j = i + 1; j < dev_priv->dcb_table.entries; j++) { + struct dcb_entry *jent = &dev_priv->dcb_table.entry[j]; + + if (jent->type == 100) /* already merged entry */ + continue; + + /* merge heads field when all other fields the same */ + if (jent->i2c_index == ient->i2c_index && jent->type == ient->type && jent->location == ient->location && jent->or == ient->or) { + DRM_INFO( + "Merging DCB entries %d and %d\n", i, j); + ient->heads |= jent->heads; + jent->type = 100; /* dummy value */ + } + } + } + + /* Compact entries merged into others out of dcb_table */ + for (i = 0; i < dev_priv->dcb_table.entries; i++) { + if ( dev_priv->dcb_table.entry[i].type == 100 ) + continue; + + if (newentries != i) + memcpy(&dev_priv->dcb_table.entry[newentries], &dev_priv->dcb_table.entry[i], sizeof(struct dcb_entry)); + newentries++; + } + + dev_priv->dcb_table.entries = newentries; +} + +static unsigned int parse_dcb_table(struct drm_device *dev, struct bios *bios) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + uint16_t dcbptr, i2ctabptr = 0; + uint8_t *dcbtable; + uint8_t dcb_version, headerlen = 0x4, entries = MAX_NUM_DCB_ENTRIES; + bool configblock = true; + int recordlength = 8, confofs = 4; + int i; + + dev_priv->dcb_table.entries = 0; + + /* get the offset from 0x36 */ + dcbptr = le16_to_cpu(*(uint16_t *)&bios->data[0x36]); + + if (dcbptr == 0x0) { + DRM_ERROR( + "No Display Configuration Block pointer found\n"); + /* this situation likely means a really old card, pre DCB, so we'll add the safe CRT entry */ + parse_dcb_entry(dev, 0, 0, 0, 0, 0); + return 1; + } + + dcbtable = &bios->data[dcbptr]; + + /* get DCB version */ + dcb_version = dcbtable[0]; + DRM_INFO( + "Display Configuration Block version %d.%d found\n", + dcb_version >> 4, dcb_version & 0xf); + + if (dcb_version >= 0x20) { /* NV17+ */ + uint32_t sig; + + if (dcb_version >= 0x30) { /* NV40+ */ + headerlen = dcbtable[1]; + entries = dcbtable[2]; + recordlength = dcbtable[3]; + i2ctabptr = le16_to_cpu(*(uint16_t *)&dcbtable[4]); + sig = le32_to_cpu(*(uint32_t *)&dcbtable[6]); + + DRM_INFO( + "DCB header length %d, with %d possible entries\n", + headerlen, entries); + } else { + i2ctabptr = le16_to_cpu(*(uint16_t *)&dcbtable[2]); + sig = le32_to_cpu(*(uint32_t *)&dcbtable[4]); + headerlen = 8; + } + + if (sig != 0x4edcbdcb) { + DRM_ERROR( + "Bad Display Configuration Block signature (%08X)\n", sig); + return 0; + } + } else if (dcb_version >= 0x14) { /* some NV15/16, and NV11+ */ + char sig[8]; + + memset(sig, 0, 8); + strncpy(sig, (char *)&dcbtable[-7], 7); + i2ctabptr = le16_to_cpu(*(uint16_t *)&dcbtable[2]); + recordlength = 10; + confofs = 6; + + if (strcmp(sig, "DEV_REC")) { + DRM_ERROR( + "Bad Display Configuration Block signature (%s)\n", sig); + return 0; + } + } else if (dcb_version >= 0x12) { /* some NV6/10, and NV15+ */ + i2ctabptr = le16_to_cpu(*(uint16_t *)&dcbtable[2]); + configblock = false; + } else { /* NV5+, maybe NV4 */ + /* DCB 1.1 seems to be quite unhelpful - we'll just add the safe CRT entry */ + parse_dcb_entry(dev, 0, dcb_version, 0, 0, 0); + return 1; + } + + if (entries >= MAX_NUM_DCB_ENTRIES) + entries = MAX_NUM_DCB_ENTRIES; + + for (i = 0; i < entries; i++) { + uint32_t connection, config = 0; + + connection = le32_to_cpu(*(uint32_t *)&dcbtable[headerlen + recordlength * i]); + if (configblock) + config = le32_to_cpu(*(uint32_t *)&dcbtable[headerlen + confofs + recordlength * i]); + + /* Should we allow discontinuous DCBs? Certainly DCB I2C tables can be discontinuous */ + if ((connection & 0x0000000f) == 0x0000000f) /* end of records */ + break; + if (connection == 0x00000000) /* seen on an NV11 with DCB v1.5 */ + break; + + DRM_INFO("Raw DCB entry %d: %08x %08x\n", i, connection, config); + if (!parse_dcb_entry(dev, dev_priv->dcb_table.entries, dcb_version, i2ctabptr, connection, config)) + break; + } + + merge_like_dcb_entries(dev); + + return dev_priv->dcb_table.entries; +} + +int nouveau_parse_bios(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + + const uint8_t bit_signature[] = { 'B', 'I', 'T' }; + int offset; + + dev_priv->bios.data = kzalloc(NV50_PROM__ESIZE, GFP_KERNEL); + + if (!nv_shadow_bios(dev, dev_priv->bios.data)) + return -EINVAL; + + dev_priv->bios.length = dev_priv->bios.data[2] * 512; + if (dev_priv->bios.length > NV50_PROM__ESIZE) + dev_priv->bios.length = NV50_PROM__ESIZE; + + if ((offset = findstr(dev_priv->bios.data, dev_priv->bios.length, bit_signature, sizeof(bit_signature)))) { + DRM_INFO("BIT BIOS found\n"); + parse_bit_structure(dev, &dev_priv->bios, offset + 4); + } else { + DRM_ERROR("BIT BIOS not found\n"); + return -EINVAL; + } + + if (parse_dcb_table(dev, &dev_priv->bios)) + DRM_INFO("Found %d entries in DCB\n", dev_priv->dcb_table.entries); + + return 0; +} + +/* temporary */ +#define NV_RAMDAC_NVPLL 0x00680500 +#define NV_RAMDAC_MPLL 0x00680504 +#define NV_RAMDAC_VPLL 0x00680508 +# define NV_RAMDAC_PLL_COEFF_MDIV 0x000000FF +# define NV_RAMDAC_PLL_COEFF_NDIV 0x0000FF00 +# define NV_RAMDAC_PLL_COEFF_PDIV 0x00070000 +# define NV30_RAMDAC_ENABLE_VCO2 (1 << 7) +#define NV_RAMDAC_VPLL2 0x00680520 + +bool get_pll_limits(struct drm_device *dev, uint32_t limit_match, struct pll_lims *pll_lim) +{ + /* PLL limits table + * + * Version 0x10: NV31 + * One byte header (version), one record of 24 bytes + * Version 0x11: NV36 - Not implemented + * Seems to have same record style as 0x10, but 3 records rather than 1 + * Version 0x20: Found on Geforce 6 cards + * Trivial 4 byte BIT header. 31 (0x1f) byte record length + * Version 0x21: Found on Geforce 7, 8 and some Geforce 6 cards + * 5 byte header, fifth byte of unknown purpose. 35 (0x23) byte record + * length in general, some (integrated) have an extra configuration byte + */ + + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct bios *bios = &dev_priv->bios; + uint8_t pll_lim_ver = 0, headerlen = 0, recordlen = 0, entries = 0; + int pllindex = 0; + uint32_t crystal_strap_mask, crystal_straps; + + if (!bios->pll_limit_tbl_ptr) { + if (bios->chip_version >= 0x40 || bios->chip_version == 0x31 || bios->chip_version == 0x36) { + DRM_ERROR("Pointer to PLL limits table invalid\n"); + return false; + } + } else { + pll_lim_ver = bios->data[bios->pll_limit_tbl_ptr]; + + DRM_INFO("Found PLL limits table version 0x%X\n", pll_lim_ver); + } + + crystal_strap_mask = 1 << 6; + /* open coded pNv->twoHeads test */ + if (bios->chip_version > 0x10 && bios->chip_version != 0x15 && + bios->chip_version != 0x1a && bios->chip_version != 0x20) + crystal_strap_mask |= 1 << 22; + crystal_straps = NV_READ(NV50_PEXTDEV + 0x0) & crystal_strap_mask; + + switch (pll_lim_ver) { + /* we use version 0 to indicate a pre limit table bios (single stage pll) + * and load the hard coded limits instead */ + case 0: + break; + case 0x10: + case 0x11: /* strictly v0x11 has 3 entries, but the last two don't seem to get used */ + headerlen = 1; + recordlen = 0x18; + entries = 1; + pllindex = 0; + break; + case 0x20: + case 0x21: + headerlen = bios->data[bios->pll_limit_tbl_ptr + 1]; + recordlen = bios->data[bios->pll_limit_tbl_ptr + 2]; + entries = bios->data[bios->pll_limit_tbl_ptr + 3]; + break; + default: + DRM_ERROR("PLL limits table revision not currently supported\n"); + return false; + } + + /* initialize all members to zero */ + memset(pll_lim, 0, sizeof(struct pll_lims)); + + if (pll_lim_ver == 0x10 || pll_lim_ver == 0x11) { + uint16_t plloffs = bios->pll_limit_tbl_ptr + headerlen + recordlen * pllindex; + + pll_lim->vco1.minfreq = le32_to_cpu(*((uint32_t *)(&bios->data[plloffs]))); + pll_lim->vco1.maxfreq = le32_to_cpu(*((uint32_t *)(&bios->data[plloffs + 4]))); + pll_lim->vco2.minfreq = le32_to_cpu(*((uint32_t *)(&bios->data[plloffs + 8]))); + pll_lim->vco2.maxfreq = le32_to_cpu(*((uint32_t *)(&bios->data[plloffs + 12]))); + pll_lim->vco1.min_inputfreq = le32_to_cpu(*((uint32_t *)(&bios->data[plloffs + 16]))); + pll_lim->vco2.min_inputfreq = le32_to_cpu(*((uint32_t *)(&bios->data[plloffs + 20]))); + pll_lim->vco1.max_inputfreq = pll_lim->vco2.max_inputfreq = INT_MAX; + + /* these values taken from nv30/31/36 */ + pll_lim->vco1.min_n = 0x1; + if (bios->chip_version == 0x36) + pll_lim->vco1.min_n = 0x5; + pll_lim->vco1.max_n = 0xff; + pll_lim->vco1.min_m = 0x1; + pll_lim->vco1.max_m = 0xd; + pll_lim->vco2.min_n = 0x4; + /* on nv30, 31, 36 (i.e. all cards with two stage PLLs with this + * table version (apart from nv35)), N2 is compared to + * maxN2 (0x46) and 10 * maxM2 (0x4), so set maxN2 to 0x28 and + * save a comparison + */ + pll_lim->vco2.max_n = 0x28; + if (bios->chip_version == 0x30 || bios->chip_version == 0x35) + /* only 5 bits available for N2 on nv30/35 */ + pll_lim->vco2.max_n = 0x1f; + pll_lim->vco2.min_m = 0x1; + pll_lim->vco2.max_m = 0x4; + } else if (pll_lim_ver) { /* ver 0x20, 0x21 */ + uint16_t plloffs = bios->pll_limit_tbl_ptr + headerlen; + uint32_t reg = 0; /* default match */ + int i; + + /* first entry is default match, if nothing better. warn if reg field nonzero */ + if (le32_to_cpu(*((uint32_t *)&bios->data[plloffs]))) + DRM_ERROR("Default PLL limit entry has non-zero register field\n"); + + if (limit_match > MAX_PLL_TYPES) + /* we've been passed a reg as the match */ + reg = limit_match; + else /* limit match is a pll type */ + for (i = 1; i < entries && !reg; i++) { + uint32_t cmpreg = le32_to_cpu(*((uint32_t *)(&bios->data[plloffs + recordlen * i]))); + + if (limit_match == NVPLL && (cmpreg == NV_RAMDAC_NVPLL || cmpreg == 0x4000)) + reg = cmpreg; + if (limit_match == MPLL && (cmpreg == NV_RAMDAC_MPLL || cmpreg == 0x4020)) + reg = cmpreg; + if (limit_match == VPLL1 && (cmpreg == NV_RAMDAC_VPLL || cmpreg == 0x4010)) + reg = cmpreg; + if (limit_match == VPLL2 && (cmpreg == NV_RAMDAC_VPLL2 || cmpreg == 0x4018)) + reg = cmpreg; + } + + for (i = 1; i < entries; i++) + if (le32_to_cpu(*((uint32_t *)&bios->data[plloffs + recordlen * i])) == reg) { + pllindex = i; + break; + } + + plloffs += recordlen * pllindex; + + DRM_INFO("Loading PLL limits for reg 0x%08x\n", pllindex ? reg : 0); + + /* frequencies are stored in tables in MHz, kHz are more useful, so we convert */ + + /* What output frequencies can each VCO generate? */ + pll_lim->vco1.minfreq = le16_to_cpu(*((uint16_t *)(&bios->data[plloffs + 4]))) * 1000; + pll_lim->vco1.maxfreq = le16_to_cpu(*((uint16_t *)(&bios->data[plloffs + 6]))) * 1000; + pll_lim->vco2.minfreq = le16_to_cpu(*((uint16_t *)(&bios->data[plloffs + 8]))) * 1000; + pll_lim->vco2.maxfreq = le16_to_cpu(*((uint16_t *)(&bios->data[plloffs + 10]))) * 1000; + + /* What input frequencies do they accept (past the m-divider)? */ + pll_lim->vco1.min_inputfreq = le16_to_cpu(*((uint16_t *)(&bios->data[plloffs + 12]))) * 1000; + pll_lim->vco2.min_inputfreq = le16_to_cpu(*((uint16_t *)(&bios->data[plloffs + 14]))) * 1000; + pll_lim->vco1.max_inputfreq = le16_to_cpu(*((uint16_t *)(&bios->data[plloffs + 16]))) * 1000; + pll_lim->vco2.max_inputfreq = le16_to_cpu(*((uint16_t *)(&bios->data[plloffs + 18]))) * 1000; + + /* What values are accepted as multiplier and divider? */ + pll_lim->vco1.min_n = bios->data[plloffs + 20]; + pll_lim->vco1.max_n = bios->data[plloffs + 21]; + pll_lim->vco1.min_m = bios->data[plloffs + 22]; + pll_lim->vco1.max_m = bios->data[plloffs + 23]; + pll_lim->vco2.min_n = bios->data[plloffs + 24]; + pll_lim->vco2.max_n = bios->data[plloffs + 25]; + pll_lim->vco2.min_m = bios->data[plloffs + 26]; + pll_lim->vco2.max_m = bios->data[plloffs + 27]; + + pll_lim->unk1c = bios->data[plloffs + 28]; + pll_lim->max_log2p_bias = bios->data[plloffs + 29]; + pll_lim->log2p_bias = bios->data[plloffs + 30]; + + if (recordlen > 0x22) + pll_lim->refclk = le32_to_cpu(*((uint32_t *)&bios->data[plloffs + 31])); + + if (recordlen > 0x23) + if (bios->data[plloffs + 35]) + DRM_ERROR("Bits set in PLL configuration byte (%x)\n", bios->data[plloffs + 35]); + + /* C51 special not seen elsewhere */ + /*if (bios->chip_version == 0x51 && !pll_lim->refclk) { + uint32_t sel_clk = nv32_rd(pScrn, NV_RAMDAC_SEL_CLK); + + if (((limit_match == NV_RAMDAC_VPLL || limit_match == VPLL1) && sel_clk & 0x20) || + ((limit_match == NV_RAMDAC_VPLL2 || limit_match == VPLL2) && sel_clk & 0x80)) { + if (nv_idx_port_rd(pScrn, CRTC_INDEX_COLOR, NV_VGA_CRTCX_REVISION) < 0xa3) + pll_lim->refclk = 200000; + else + pll_lim->refclk = 25000; + } + }*/ + } + + /* By now any valid limit table ought to have set a max frequency for + * vco1, so if it's zero it's either a pre limit table bios, or one + * with an empty limit table (seen on nv18) + */ + if (!pll_lim->vco1.maxfreq) { + pll_lim->vco1.minfreq = bios->fminvco; + pll_lim->vco1.maxfreq = bios->fmaxvco; + pll_lim->vco1.min_inputfreq = 0; + pll_lim->vco1.max_inputfreq = INT_MAX; + pll_lim->vco1.min_n = 0x1; + pll_lim->vco1.max_n = 0xff; + pll_lim->vco1.min_m = 0x1; + if (crystal_straps == 0) { + /* nv05 does this, nv11 doesn't, nv10 unknown */ + if (bios->chip_version < 0x11) + pll_lim->vco1.min_m = 0x7; + pll_lim->vco1.max_m = 0xd; + } else { + if (bios->chip_version < 0x11) + pll_lim->vco1.min_m = 0x8; + pll_lim->vco1.max_m = 0xe; + } + } + + if (!pll_lim->refclk) + switch (crystal_straps) { + case 0: + pll_lim->refclk = 13500; + break; + case (1 << 6): + pll_lim->refclk = 14318; + break; + case (1 << 22): + pll_lim->refclk = 27000; + break; + case (1 << 22 | 1 << 6): + pll_lim->refclk = 25000; + break; + } + +#if 1 /* for easy debugging */ + DRM_INFO("pll.vco1.minfreq: %d\n", pll_lim->vco1.minfreq); + DRM_INFO("pll.vco1.maxfreq: %d\n", pll_lim->vco1.maxfreq); + DRM_INFO("pll.vco2.minfreq: %d\n", pll_lim->vco2.minfreq); + DRM_INFO("pll.vco2.maxfreq: %d\n", pll_lim->vco2.maxfreq); + + DRM_INFO("pll.vco1.min_inputfreq: %d\n", pll_lim->vco1.min_inputfreq); + DRM_INFO("pll.vco1.max_inputfreq: %d\n", pll_lim->vco1.max_inputfreq); + DRM_INFO("pll.vco2.min_inputfreq: %d\n", pll_lim->vco2.min_inputfreq); + DRM_INFO("pll.vco2.max_inputfreq: %d\n", pll_lim->vco2.max_inputfreq); + + DRM_INFO("pll.vco1.min_n: %d\n", pll_lim->vco1.min_n); + DRM_INFO("pll.vco1.max_n: %d\n", pll_lim->vco1.max_n); + DRM_INFO("pll.vco1.min_m: %d\n", pll_lim->vco1.min_m); + DRM_INFO("pll.vco1.max_m: %d\n", pll_lim->vco1.max_m); + DRM_INFO("pll.vco2.min_n: %d\n", pll_lim->vco2.min_n); + DRM_INFO("pll.vco2.max_n: %d\n", pll_lim->vco2.max_n); + DRM_INFO("pll.vco2.min_m: %d\n", pll_lim->vco2.min_m); + DRM_INFO("pll.vco2.max_m: %d\n", pll_lim->vco2.max_m); + + DRM_INFO("pll.unk1c: %d\n", pll_lim->unk1c); + DRM_INFO("pll.max_log2p_bias: %d\n", pll_lim->max_log2p_bias); + DRM_INFO("pll.log2p_bias: %d\n", pll_lim->log2p_bias); + + DRM_INFO("pll.refclk: %d\n", pll_lim->refclk); +#endif + + return true; +} diff --git a/linux-core/nouveau_bios.h b/linux-core/nouveau_bios.h new file mode 100644 index 00000000..e33ecd0f --- /dev/null +++ b/linux-core/nouveau_bios.h @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2005-2006 Erik Waling + * Copyright (C) 2006 Stephane Marchesin + * Copyright (C) 2007-2008 Stuart Bennett + * Copyright (C) 2008 Maarten Maathuis. + * All Rights Reserved. + * + * 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 (including the + * next paragraph) 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 OWNER(S) AND/OR ITS SUPPLIERS 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. + * + */ + +#ifndef __NOUVEAU_BIOS_H__ +#define __NOUVEAU_BIOS_H__ + +#include "drmP.h" +#include "drm.h" + +#define LOC_ON_CHIP 0 + +enum dcb_output_type {/* matches DCB types */ + DCB_OUTPUT_NONE = 4, + DCB_OUTPUT_ANALOG = 0, + DCB_OUTPUT_TMDS = 2, + DCB_OUTPUT_LVDS = 3, + DCB_OUTPUT_TV = 1, +}; + +struct bios { + uint8_t *data; + unsigned int length; + bool execute; + + uint8_t major_version, chip_version; + uint8_t feature_byte; + + uint32_t fmaxvco, fminvco; + + uint32_t dactestval; + + uint16_t init_script_tbls_ptr; + uint16_t extra_init_script_tbl_ptr; + uint16_t macro_index_tbl_ptr; + uint16_t macro_tbl_ptr; + uint16_t condition_tbl_ptr; + uint16_t io_condition_tbl_ptr; + uint16_t io_flag_condition_tbl_ptr; + uint16_t init_function_tbl_ptr; + + uint16_t pll_limit_tbl_ptr; + uint16_t ram_restrict_tbl_ptr; + + struct { + struct nouveau_hw_mode *native_mode; + uint8_t *edid; + uint16_t lvdsmanufacturerpointer; + uint16_t xlated_entry; + bool power_off_for_reset; + bool reset_after_pclk_change; + bool dual_link; + bool link_c_increment; + bool if_is_24bit; + bool BITbit1; + int duallink_transition_clk; + /* lower nibble stores PEXTDEV_BOOT_0 strap + * upper nibble stores xlated display strap */ + uint8_t strapping; + } fp; + + struct { + uint16_t output0_script_ptr; + uint16_t output1_script_ptr; + } tmds; + + struct { + uint16_t mem_init_tbl_ptr; + uint16_t sdr_seq_tbl_ptr; + uint16_t ddr_seq_tbl_ptr; + + struct { + uint8_t crt, tv, panel; + } i2c_indices; + } legacy; +}; + +struct dcb_entry { + int index; + uint8_t type; + uint8_t i2c_index; + uint8_t heads; + uint8_t bus; + uint8_t location; + uint8_t or; + bool duallink_possible; + union { + struct { + bool use_straps_for_mode; + bool use_power_scripts; + } lvdsconf; + }; +}; + +/* changing these requires matching changes to reg tables in nv_get_clock */ +#define MAX_PLL_TYPES 4 +enum pll_types { + NVPLL, + MPLL, + VPLL1, + VPLL2 +}; + +struct pll_lims { + struct { + int minfreq; + int maxfreq; + int min_inputfreq; + int max_inputfreq; + + uint8_t min_m; + uint8_t max_m; + uint8_t min_n; + uint8_t max_n; + } vco1, vco2; + + uint8_t unk1c; + uint8_t max_log2p_bias; + uint8_t log2p_bias; + int refclk; +}; + +bool get_pll_limits(struct drm_device *dev, uint32_t limit_match, struct pll_lims *pll_lim); +int nouveau_parse_bios(struct drm_device *dev); + +#endif /* __NOUVEAU_BIOS_H__ */ diff --git a/linux-core/nouveau_drv.c b/linux-core/nouveau_drv.c index c8f57dff..04f002f2 100644 --- a/linux-core/nouveau_drv.c +++ b/linux-core/nouveau_drv.c @@ -28,6 +28,9 @@ #include "drm_pciids.h" +unsigned int nouveau_modeset = 0; /* kms */ +module_param_named(modeset, nouveau_modeset, int, 0400); + static struct pci_device_id pciidlist[] = { { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID), @@ -104,6 +107,10 @@ static int probe(struct pci_dev *pdev, const struct pci_device_id *ent) static int __init nouveau_init(void) { driver.num_ioctls = nouveau_max_ioctl; + + if (nouveau_modeset == 1) + driver.driver_features |= DRIVER_MODESET; + return drm_init(&driver, pciidlist); } diff --git a/linux-core/nv50_connector.c b/linux-core/nv50_connector.c new file mode 100644 index 00000000..d13622b7 --- /dev/null +++ b/linux-core/nv50_connector.c @@ -0,0 +1,207 @@ +/* + * Copyright (C) 2008 Maarten Maathuis. + * All Rights Reserved. + * + * 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 (including the + * next paragraph) 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 OWNER(S) AND/OR ITS SUPPLIERS 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. + * + */ + +#include "nv50_connector.h" + +static struct nv50_output *nv50_connector_to_output(struct nv50_connector *connector, bool digital) +{ + struct nv50_display *display = nv50_get_display(connector->dev); + struct nv50_output *output = NULL; + bool digital_possible = false; + bool analog_possible = false; + + switch (connector->type) { + case CONNECTOR_VGA: + case CONNECTOR_TV: + analog_possible = true; + break; + case CONNECTOR_DVI_I: + analog_possible = true; + digital_possible = true; + break; + case CONNECTOR_DVI_D: + case CONNECTOR_LVDS: + digital_possible = true; + break; + default: + break; + } + + /* Return early on bad situations. */ + if (!analog_possible && !digital_possible) + return NULL; + + if (!analog_possible && !digital) + return NULL; + + if (!digital_possible && digital) + return NULL; + + list_for_each_entry(output, &display->outputs, head) { + if (connector->bus != output->bus) + continue; + if (digital && output->type == OUTPUT_TMDS) + return output; + if (digital && output->type == OUTPUT_LVDS) + return output; + if (!digital && output->type == OUTPUT_DAC) + return output; + if (!digital && output->type == OUTPUT_TV) + return output; + } + + return NULL; +} + +static bool nv50_connector_detect(struct nv50_connector *connector) +{ + /* kindly borrrowed from the intel driver, hope it works. */ + uint8_t out_buf[] = { 0x0, 0x0}; + uint8_t buf[2]; + int ret; + struct i2c_msg msgs[] = { + { + .addr = 0x50, + .flags = 0, + .len = 1, + .buf = out_buf, + }, + { + .addr = 0x50, + .flags = I2C_M_RD, + .len = 1, + .buf = buf, + } + }; + + NV50_DEBUG("\n"); + + if (!connector->i2c_chan) + return false; + + ret = i2c_transfer(&connector->i2c_chan->adapter, msgs, 2); + DRM_INFO("I2C detect returned %d\n", ret); + + if (ret == 2) + return true; + + return false; +} + +static int nv50_connector_destroy(struct nv50_connector *connector) +{ + struct drm_device *dev = connector->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nv50_display *display = nv50_get_display(dev); + + NV50_DEBUG("\n"); + + if (!display || !connector) + return -EINVAL; + + list_del(&connector->head); + + if (connector->i2c_chan) + nv50_i2c_channel_destroy(connector->i2c_chan); + + if (dev_priv->free_connector) + dev_priv->free_connector(connector); + + return 0; +} + +int nv50_connector_create(struct drm_device *dev, int bus, int i2c_index, int type) +{ + struct nv50_connector *connector = NULL; + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nv50_display *display = NULL; + + NV50_DEBUG("\n"); + + /* This allows the public layer to do it's thing. */ + if (dev_priv->alloc_connector) + connector = dev_priv->alloc_connector(dev); + + if (!connector) + return -ENOMEM; + + connector->dev = dev; + + display = nv50_get_display(dev); + if (!display) + goto out; + + if (type == CONNECTOR_UNKNOWN) + goto out; + + list_add_tail(&connector->head, &display->connectors); + + connector->bus = bus; + connector->type = type; + + switch (type) { + case CONNECTOR_VGA: + DRM_INFO("Detected a VGA connector\n"); + break; + case CONNECTOR_DVI_D: + DRM_INFO("Detected a DVI-D connector\n"); + break; + case CONNECTOR_DVI_I: + DRM_INFO("Detected a DVI-I connector\n"); + break; + case CONNECTOR_LVDS: + DRM_INFO("Detected a LVDS connector\n"); + break; + case CONNECTOR_TV: + DRM_INFO("Detected a TV connector\n"); + break; + default: + DRM_ERROR("Unknown connector, this is not good.\n"); + break; + } + + /* some reasonable defaults */ + if (type == CONNECTOR_DVI_D || type == CONNECTOR_LVDS) + connector->scaling_mode = SCALE_FULLSCREEN; + else + connector->scaling_mode = SCALE_PANEL; + + if (i2c_index < 0xf) + connector->i2c_chan = nv50_i2c_channel_create(dev, i2c_index); + + /* set function pointers */ + connector->detect = nv50_connector_detect; + connector->destroy = nv50_connector_destroy; + connector->to_output = nv50_connector_to_output; + + return 0; + +out: + if (dev_priv->free_connector) + dev_priv->free_connector(connector); + + return -EINVAL; +} diff --git a/linux-core/nv50_connector.h b/linux-core/nv50_connector.h new file mode 100644 index 00000000..c70d6ef4 --- /dev/null +++ b/linux-core/nv50_connector.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2008 Maarten Maathuis. + * All Rights Reserved. + * + * 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 (including the + * next paragraph) 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 OWNER(S) AND/OR ITS SUPPLIERS 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. + * + */ + +#ifndef __NV50_CONNECTOR_H__ +#define __NV50_CONNECTOR_H__ + +#include "nv50_output.h" +#include "nv50_i2c.h" + +#define CONNECTOR_UNKNOWN 0 +#define CONNECTOR_VGA 1 +#define CONNECTOR_DVI_D 2 +#define CONNECTOR_DVI_I 3 +#define CONNECTOR_LVDS 4 +#define CONNECTOR_TV 5 + +struct nv50_connector { + struct list_head head; + + struct drm_device *dev; + int type; + + int bus; + struct nv50_i2c_channel *i2c_chan; + struct nv50_output *output; + + int scaling_mode; + bool digital; /* last connected output, this has to be set from the outside*/ + + bool (*detect) (struct nv50_connector *connector); + int (*destroy) (struct nv50_connector *connector); + struct nv50_output *(*to_output) (struct nv50_connector *connector, bool digital); +}; + +int nv50_connector_create(struct drm_device *dev, int bus, int i2c_index, int type); + +#endif /* __NV50_CONNECTOR_H__ */ diff --git a/linux-core/nv50_crtc.c b/linux-core/nv50_crtc.c new file mode 100644 index 00000000..974f5202 --- /dev/null +++ b/linux-core/nv50_crtc.c @@ -0,0 +1,515 @@ +/* + * Copyright (C) 2008 Maarten Maathuis. + * All Rights Reserved. + * + * 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 (including the + * next paragraph) 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 OWNER(S) AND/OR ITS SUPPLIERS 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. + * + */ + +#include "nv50_crtc.h" +#include "nv50_cursor.h" +#include "nv50_lut.h" +#include "nv50_fb.h" + +static int nv50_crtc_validate_mode(struct nv50_crtc *crtc, struct nouveau_hw_mode *mode) +{ + NV50_DEBUG("\n"); + + if (mode->clock > 400000) + return MODE_CLOCK_HIGH; + + if (mode->clock < 25000) + return MODE_CLOCK_LOW; + + return MODE_OK; +} + +static int nv50_crtc_set_mode(struct nv50_crtc *crtc, struct nouveau_hw_mode *mode) +{ + struct nouveau_hw_mode *hw_mode = crtc->mode; + uint8_t rval; + + NV50_DEBUG("index %d\n", crtc->index); + + if (!mode) { + DRM_ERROR("No mode\n"); + return MODE_NOMODE; + } + + if ((rval = crtc->validate_mode(crtc, mode))) { + DRM_ERROR("Mode invalid\n"); + return rval; + } + + /* copy values to mode */ + *hw_mode = *mode; + + return 0; +} + +static int nv50_crtc_execute_mode(struct nv50_crtc *crtc) +{ + struct drm_nouveau_private *dev_priv = crtc->dev->dev_private; + struct nouveau_hw_mode *hw_mode; + uint32_t hsync_dur, vsync_dur, hsync_start_to_end, vsync_start_to_end; + uint32_t hunk1, vunk1, vunk2a, vunk2b; + uint32_t offset = crtc->index * 0x400; + uint32_t pitch; + + NV50_DEBUG("index %d\n", crtc->index); + NV50_DEBUG("%s native mode\n", crtc->use_native_mode ? "using" : "not using"); + + if (crtc->use_native_mode) + hw_mode = crtc->native_mode; + else + hw_mode = crtc->mode; + + hsync_dur = hw_mode->hsync_end - hw_mode->hsync_start; + vsync_dur = hw_mode->vsync_end - hw_mode->vsync_start; + hsync_start_to_end = hw_mode->hblank_end - hw_mode->hsync_start; + vsync_start_to_end = hw_mode->vblank_end - hw_mode->vsync_start; + /* I can't give this a proper name, anyone else can? */ + hunk1 = hw_mode->htotal - hw_mode->hsync_start + hw_mode->hblank_start; + vunk1 = hw_mode->vtotal - hw_mode->vsync_start + hw_mode->vblank_start; + /* Another strange value, this time only for interlaced modes. */ + vunk2a = 2*hw_mode->vtotal - hw_mode->vsync_start + hw_mode->vblank_start; + vunk2b = hw_mode->vtotal - hw_mode->vsync_start + hw_mode->vblank_end; + + if (hw_mode->flags & V_INTERLACE) { + vsync_dur /= 2; + vsync_start_to_end /= 2; + vunk1 /= 2; + vunk2a /= 2; + vunk2b /= 2; + /* magic */ + if (hw_mode->flags & V_DBLSCAN) { + vsync_start_to_end -= 1; + vunk1 -= 1; + vunk2a -= 1; + vunk2b -= 1; + } + } + + OUT_MODE(NV50_CRTC0_CLOCK + offset, hw_mode->clock | 0x800000); + OUT_MODE(NV50_CRTC0_INTERLACE + offset, (hw_mode->flags & V_INTERLACE) ? 2 : 0); + OUT_MODE(NV50_CRTC0_DISPLAY_START + offset, 0); + OUT_MODE(NV50_CRTC0_UNK82C + offset, 0); + OUT_MODE(NV50_CRTC0_DISPLAY_TOTAL + offset, hw_mode->vtotal << 16 | hw_mode->htotal); + OUT_MODE(NV50_CRTC0_SYNC_DURATION + offset, (vsync_dur - 1) << 16 | (hsync_dur - 1)); + OUT_MODE(NV50_CRTC0_SYNC_START_TO_BLANK_END + offset, (vsync_start_to_end - 1) << 16 | (hsync_start_to_end - 1)); + OUT_MODE(NV50_CRTC0_MODE_UNK1 + offset, (vunk1 - 1) << 16 | (hunk1 - 1)); + if (hw_mode->flags & V_INTERLACE) { + OUT_MODE(NV50_CRTC0_MODE_UNK2 + offset, (vunk2b - 1) << 16 | (vunk2a - 1)); + } + OUT_MODE(NV50_CRTC0_FB_SIZE + offset, crtc->fb->height << 16 | crtc->fb->width); + + /* I suspect this flag indicates a linear fb. */ + pitch = ((crtc->fb->width + 63) & ~63) * (crtc->fb->bpp)/8; + NV50_DEBUG("fb_pitch %d\n", pitch); + OUT_MODE(NV50_CRTC0_FB_PITCH + offset, pitch | 0x100000); + + switch (crtc->fb->depth) { + case 8: + OUT_MODE(NV50_CRTC0_DEPTH + offset, NV50_CRTC0_DEPTH_8BPP); + break; + case 15: + OUT_MODE(NV50_CRTC0_DEPTH + offset, NV50_CRTC0_DEPTH_15BPP); + break; + case 16: + OUT_MODE(NV50_CRTC0_DEPTH + offset, NV50_CRTC0_DEPTH_16BPP); + break; + case 24: + OUT_MODE(NV50_CRTC0_DEPTH + offset, NV50_CRTC0_DEPTH_24BPP); + break; + } + crtc->set_dither(crtc); + OUT_MODE(NV50_CRTC0_COLOR_CTRL + offset, NV50_CRTC_COLOR_CTRL_MODE_COLOR); + OUT_MODE(NV50_CRTC0_FB_POS + offset, (crtc->fb->y << 16) | (crtc->fb->x)); + /* This is the actual resolution of the mode. */ + OUT_MODE(NV50_CRTC0_REAL_RES + offset, (crtc->mode->vdisplay << 16) | crtc->mode->hdisplay); + OUT_MODE(NV50_CRTC0_SCALE_CENTER_OFFSET + offset, NV50_CRTC_SCALE_CENTER_OFFSET_VAL(0,0)); + + /* Maybe move this as well? */ + crtc->blank(crtc, FALSE); + + return 0; +} + +static int nv50_crtc_blank(struct nv50_crtc *crtc, bool blanked) +{ + struct drm_nouveau_private *dev_priv = crtc->dev->dev_private; + uint32_t offset = crtc->index * 0x400; + + NV50_DEBUG("index %d\n", crtc->index); + NV50_DEBUG("%s\n", blanked ? "blanked" : "unblanked"); + + /* We really need a framebuffer. */ + if (!crtc->fb->block && !blanked) { + DRM_ERROR("No framebuffer available on crtc %d\n", crtc->index); + return -EINVAL; + } + + if (blanked) { + crtc->cursor->hide(crtc); + + OUT_MODE(NV50_CRTC0_CLUT_MODE + offset, NV50_CRTC0_CLUT_MODE_BLANK); + OUT_MODE(NV50_CRTC0_CLUT_OFFSET + offset, 0); + if (dev_priv->chipset != 0x50) + OUT_MODE(NV84_CRTC0_BLANK_UNK1 + offset, NV84_CRTC0_BLANK_UNK1_BLANK); + OUT_MODE(NV50_CRTC0_BLANK_CTRL + offset, NV50_CRTC0_BLANK_CTRL_BLANK); + if (dev_priv->chipset != 0x50) + OUT_MODE(NV84_CRTC0_BLANK_UNK2 + offset, NV84_CRTC0_BLANK_UNK2_BLANK); + } else { + uint32_t ram_amount; + + OUT_MODE(NV50_CRTC0_FB_OFFSET + offset, crtc->fb->block->start >> 8); + OUT_MODE(0x864 + offset, 0); + /* maybe this needs to be moved. */ + NV_WRITE(NV50_PDISPLAY_UNK_380, 0); + /* RAM is clamped to 256 MiB. */ + ram_amount = nouveau_mem_fb_amount(crtc->dev); + NV50_DEBUG("ram_amount %d\n", ram_amount); + if (ram_amount > 256*1024*1024) + ram_amount = 256*1024*1024; + NV_WRITE(NV50_PDISPLAY_RAM_AMOUNT, ram_amount - 1); + NV_WRITE(NV50_PDISPLAY_UNK_388, 0x150000); + NV_WRITE(NV50_PDISPLAY_UNK_38C, 0); + if (crtc->cursor->block) + OUT_MODE(NV50_CRTC0_CURSOR_OFFSET + offset, crtc->cursor->block->start >> 8); + else + OUT_MODE(NV50_CRTC0_CURSOR_OFFSET + offset, 0); + if (dev_priv->chipset != 0x50) + OUT_MODE(NV84_CRTC0_BLANK_UNK2 + offset, NV84_CRTC0_BLANK_UNK2_UNBLANK); + + if (crtc->cursor->visible) + crtc->cursor->show(crtc); + else + crtc->cursor->hide(crtc); + + OUT_MODE(NV50_CRTC0_CLUT_MODE + offset, + crtc->fb->depth == 8 ? NV50_CRTC0_CLUT_MODE_OFF : NV50_CRTC0_CLUT_MODE_ON); + OUT_MODE(NV50_CRTC0_CLUT_OFFSET + offset, crtc->lut->block->start >> 8); + if (dev_priv->chipset != 0x50) + OUT_MODE(NV84_CRTC0_BLANK_UNK1 + offset, NV84_CRTC0_BLANK_UNK1_UNBLANK); + OUT_MODE(NV50_CRTC0_BLANK_CTRL + offset, NV50_CRTC0_BLANK_CTRL_UNBLANK); + } + + return 0; +} + +static int nv50_crtc_set_dither(struct nv50_crtc *crtc) +{ + struct drm_nouveau_private *dev_priv = crtc->dev->dev_private; + uint32_t offset = crtc->index * 0x400; + + NV50_DEBUG("\n"); + + OUT_MODE(NV50_CRTC0_DITHERING_CTRL + offset, crtc->use_dithering ? + NV50_CRTC0_DITHERING_CTRL_ON : NV50_CRTC0_DITHERING_CTRL_OFF); + + return 0; +} + +static void nv50_crtc_calc_scale(struct nv50_crtc *crtc, uint32_t *outX, uint32_t *outY) +{ + float hor_scale, ver_scale; + + hor_scale = (float)crtc->native_mode->hdisplay/(float)crtc->mode->hdisplay; + ver_scale = (float)crtc->native_mode->vdisplay/(float)crtc->mode->vdisplay; + + if (ver_scale > hor_scale) { + *outX = crtc->mode->hdisplay * hor_scale; + *outY = crtc->mode->vdisplay * hor_scale; + } else { + *outX = crtc->mode->hdisplay * ver_scale; + *outY = crtc->mode->vdisplay * ver_scale; + } +} + +static int nv50_crtc_set_scale(struct nv50_crtc *crtc) +{ + struct drm_nouveau_private *dev_priv = crtc->dev->dev_private; + uint32_t offset = crtc->index * 0x400; + uint32_t outX, outY; + + NV50_DEBUG("\n"); + + switch (crtc->scaling_mode) { + case SCALE_ASPECT: + nv50_crtc_calc_scale(crtc, &outX, &outY); + break; + case SCALE_FULLSCREEN: + outX = crtc->native_mode->hdisplay; + outY = crtc->native_mode->vdisplay; + break; + case SCALE_NOSCALE: + case SCALE_PANEL: + default: + outX = crtc->mode->hdisplay; + outY = crtc->mode->vdisplay; + break; + } + + /* Got a better name for SCALER_ACTIVE? */ + /* One day i've got to really figure out why this is needed. */ + if ((crtc->mode->flags & V_DBLSCAN) || (crtc->mode->flags & V_INTERLACE) || + crtc->mode->hdisplay != outX || crtc->mode->vdisplay != outY) { + OUT_MODE(NV50_CRTC0_SCALE_CTRL + offset, NV50_CRTC0_SCALE_CTRL_SCALER_ACTIVE); + } else { + OUT_MODE(NV50_CRTC0_SCALE_CTRL + offset, NV50_CRTC0_SCALE_CTRL_SCALER_INACTIVE); + } + + OUT_MODE(NV50_CRTC0_SCALE_RES1 + offset, outY << 16 | outX); + OUT_MODE(NV50_CRTC0_SCALE_RES2 + offset, outY << 16 | outX); + + return 0; +} + +static int nv50_crtc_calc_clock(struct nv50_crtc *crtc, + uint32_t *bestN1, uint32_t *bestN2, uint32_t *bestM1, uint32_t *bestM2, uint32_t *bestlog2P) +{ + struct nouveau_hw_mode *hw_mode; + struct pll_lims limits; + int clk, vco2, crystal; + int minvco1, minvco2, minU1, maxU1, minU2, maxU2, minM1, maxM1; + int maxvco1, maxvco2, minN1, maxN1, minM2, maxM2, minN2, maxN2; + bool fixedgain2; + int M1, N1, M2, N2, log2P; + int clkP, calcclk1, calcclk2, calcclkout; + int delta, bestdelta = INT_MAX; + int bestclk = 0; + + NV50_DEBUG("\n"); + + if (crtc->use_native_mode) + hw_mode = crtc->native_mode; + else + hw_mode = crtc->mode; + + clk = hw_mode->clock; + + /* These are in the g80 bios tables, at least in mine. */ + if (!get_pll_limits(crtc->dev, NV50_PDISPLAY_CRTC_CLK_CLK_CTRL1(crtc->index), &limits)) + return -EINVAL; + + minvco1 = limits.vco1.minfreq, maxvco1 = limits.vco1.maxfreq; + minvco2 = limits.vco2.minfreq, maxvco2 = limits.vco2.maxfreq; + minU1 = limits.vco1.min_inputfreq, minU2 = limits.vco2.min_inputfreq; + maxU1 = limits.vco1.max_inputfreq, maxU2 = limits.vco2.max_inputfreq; + minM1 = limits.vco1.min_m, maxM1 = limits.vco1.max_m; + minN1 = limits.vco1.min_n, maxN1 = limits.vco1.max_n; + minM2 = limits.vco2.min_m, maxM2 = limits.vco2.max_m; + minN2 = limits.vco2.min_n, maxN2 = limits.vco2.max_n; + crystal = limits.refclk; + fixedgain2 = (minM2 == maxM2 && minN2 == maxN2); + + vco2 = (maxvco2 - maxvco2/200) / 2; + for (log2P = 0; clk && log2P < 6 && clk <= (vco2 >> log2P); log2P++) /* log2P is maximum of 6 */ + ; + clkP = clk << log2P; + + if (maxvco2 < clk + clk/200) /* +0.5% */ + maxvco2 = clk + clk/200; + + for (M1 = minM1; M1 <= maxM1; M1++) { + if (crystal/M1 < minU1) + return bestclk; + if (crystal/M1 > maxU1) + continue; + + for (N1 = minN1; N1 <= maxN1; N1++) { + calcclk1 = crystal * N1 / M1; + if (calcclk1 < minvco1) + continue; + if (calcclk1 > maxvco1) + break; + + for (M2 = minM2; M2 <= maxM2; M2++) { + if (calcclk1/M2 < minU2) + break; + if (calcclk1/M2 > maxU2) + continue; + + /* add calcclk1/2 to round better */ + N2 = (clkP * M2 + calcclk1/2) / calcclk1; + if (N2 < minN2) + continue; + if (N2 > maxN2) + break; + + if (!fixedgain2) { + calcclk2 = calcclk1 * N2 / M2; + if (calcclk2 < minvco2) + break; + if (calcclk2 > maxvco2) + continue; + } else + calcclk2 = calcclk1; + + calcclkout = calcclk2 >> log2P; + delta = abs(calcclkout - clk); + /* we do an exhaustive search rather than terminating + * on an optimality condition... + */ + if (delta < bestdelta) { + bestdelta = delta; + bestclk = calcclkout; + *bestN1 = N1; + *bestN2 = N2; + *bestM1 = M1; + *bestM2 = M2; + *bestlog2P = log2P; + if (delta == 0) /* except this one */ + return bestclk; + } + } + } + } + + return bestclk; +} + +static int nv50_crtc_set_clock(struct nv50_crtc *crtc) +{ + struct drm_nouveau_private *dev_priv = crtc->dev->dev_private; + + uint32_t pll_reg = NV50_PDISPLAY_CRTC_CLK_CLK_CTRL1(crtc->index); + + uint32_t N1 = 0, N2 = 0, M1 = 0, M2 = 0, log2P = 0; + + uint32_t reg1 = NV_READ(pll_reg + 4); + uint32_t reg2 = NV_READ(pll_reg + 8); + + NV50_DEBUG("\n"); + + NV_WRITE(pll_reg, NV50_PDISPLAY_CRTC_CLK_CLK_CTRL1_CONNECTED | 0x10000011); + + /* The other bits are typically empty, but let's be on the safe side. */ + reg1 &= 0xff00ff00; + reg2 &= 0x8000ff00; + + if (!nv50_crtc_calc_clock(crtc, &N1, &N2, &M1, &M2, &log2P)) + return -EINVAL; + + NV50_DEBUG("N1 %d N2 %d M1 %d M2 %d log2P %d\n", N1, N2, M1, M2, log2P); + + reg1 |= (M1 << 16) | N1; + reg2 |= (log2P << 28) | (M2 << 16) | N2; + + NV_WRITE(pll_reg + 4, reg1); + NV_WRITE(pll_reg + 8, reg2); + + return 0; +} + +static int nv50_crtc_set_clock_mode(struct nv50_crtc *crtc) +{ + struct drm_nouveau_private *dev_priv = crtc->dev->dev_private; + + NV50_DEBUG("\n"); + + /* This acknowledges a clock request. */ + NV_WRITE(NV50_PDISPLAY_CRTC_CLK_CLK_CTRL2(crtc->index), 0); + + return 0; +} + +static int nv50_crtc_destroy(struct nv50_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nv50_display *display = nv50_get_display(dev); + + NV50_DEBUG("\n"); + + if (!display || !crtc) + return -EINVAL; + + list_del(&crtc->head); + + nv50_fb_destroy(crtc); + nv50_lut_destroy(crtc); + nv50_cursor_destroy(crtc); + + kfree(crtc->mode); + kfree(crtc->native_mode); + + if (dev_priv->free_crtc) + dev_priv->free_crtc(crtc); + + return 0; +} + +int nv50_crtc_create(struct drm_device *dev, int index) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nv50_crtc *crtc = NULL; + struct nv50_display *display = NULL; + + NV50_DEBUG("\n"); + + /* This allows the public layer to do it's thing. */ + if (dev_priv->alloc_crtc) + crtc = dev_priv->alloc_crtc(dev); + + if (!crtc) + return -ENOMEM; + + crtc->dev = dev; + + display = nv50_get_display(dev); + if (!display) + goto out; + + list_add_tail(&crtc->head, &display->crtcs); + + crtc->index = index; + + crtc->mode = kzalloc(sizeof(struct nouveau_hw_mode), GFP_KERNEL); + crtc->native_mode = kzalloc(sizeof(struct nouveau_hw_mode), GFP_KERNEL); + + nv50_fb_create(crtc); + nv50_lut_create(crtc); + nv50_cursor_create(crtc); + + /* set function pointers */ + crtc->validate_mode = nv50_crtc_validate_mode; + crtc->set_mode = nv50_crtc_set_mode; + crtc->execute_mode = nv50_crtc_execute_mode; + crtc->blank = nv50_crtc_blank; + crtc->set_dither = nv50_crtc_set_dither; + crtc->set_scale = nv50_crtc_set_scale; + crtc->set_clock = nv50_crtc_set_clock; + crtc->set_clock_mode = nv50_crtc_set_clock_mode; + crtc->destroy = nv50_crtc_destroy; + + return 0; + +out: + if (crtc->mode) + kfree(crtc->mode); + if (crtc->native_mode) + kfree(crtc->native_mode); + if (dev_priv->free_crtc) + dev_priv->free_crtc(crtc); + + return -EINVAL; +} diff --git a/linux-core/nv50_crtc.h b/linux-core/nv50_crtc.h new file mode 100644 index 00000000..5eb815a5 --- /dev/null +++ b/linux-core/nv50_crtc.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2008 Maarten Maathuis. + * All Rights Reserved. + * + * 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 (including the + * next paragraph) 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 OWNER(S) AND/OR ITS SUPPLIERS 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. + * + */ + +#ifndef __NV50_CRTC_H__ +#define __NV50_CRTC_H__ + +#include "nv50_display.h" + +struct nv50_cursor; +struct nv50_lut; +struct nv50_fb; + +struct nv50_crtc { + struct list_head head; + + struct drm_device *dev; + int index; + bool active; + + struct nouveau_hw_mode *mode; + struct nouveau_hw_mode *native_mode; + + bool use_native_mode; + bool use_dithering; + int scaling_mode; + + struct nv50_cursor *cursor; + struct nv50_lut *lut; + struct nv50_fb *fb; + + int (*validate_mode) (struct nv50_crtc *crtc, struct nouveau_hw_mode *mode); + int (*set_mode) (struct nv50_crtc *crtc, struct nouveau_hw_mode *mode); + int (*execute_mode) (struct nv50_crtc *crtc); + int (*blank) (struct nv50_crtc *crtc, bool blanked); + int (*set_dither) (struct nv50_crtc *crtc); + int (*set_scale) (struct nv50_crtc *crtc); + int (*set_clock) (struct nv50_crtc *crtc); + int (*set_clock_mode) (struct nv50_crtc *crtc); + int (*destroy) (struct nv50_crtc *crtc); +}; + +int nv50_crtc_create(struct drm_device *dev, int index); + +#endif /* __NV50_CRTC_H__ */ diff --git a/linux-core/nv50_cursor.c b/linux-core/nv50_cursor.c new file mode 100644 index 00000000..3d35b936 --- /dev/null +++ b/linux-core/nv50_cursor.c @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2008 Maarten Maathuis. + * All Rights Reserved. + * + * 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 (including the + * next paragraph) 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 OWNER(S) AND/OR ITS SUPPLIERS 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. + * + */ + +#include "nv50_cursor.h" +#include "nv50_crtc.h" +#include "nv50_display.h" + +static int nv50_cursor_enable(struct nv50_crtc *crtc) +{ + struct drm_nouveau_private *dev_priv = crtc->dev->dev_private; + + NV50_DEBUG("\n"); + + NV_WRITE(NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(crtc->index), 0x2000); + while(NV_READ(NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(crtc->index)) & NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS_MASK); + + NV_WRITE(NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(crtc->index), NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_ON); + while((NV_READ(NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(crtc->index)) & NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS_MASK) + != NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS_ACTIVE); + + crtc->cursor->enabled = true; + + return 0; +} + +static int nv50_cursor_disable(struct nv50_crtc *crtc) +{ + struct drm_nouveau_private *dev_priv = crtc->dev->dev_private; + + NV50_DEBUG("\n"); + + NV_WRITE(NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(crtc->index), 0); + while(NV_READ(NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(crtc->index)) & NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS_MASK); + + crtc->cursor->enabled = false; + + return 0; +} + +/* Calling update or changing the stored cursor state is left to the higher level ioctl's. */ +static int nv50_cursor_show(struct nv50_crtc *crtc) +{ + struct drm_nouveau_private *dev_priv = crtc->dev->dev_private; + uint32_t offset = crtc->index * 0x400; + + NV50_DEBUG("\n"); + + /* Better not show the cursor when we have none. */ + /* TODO: is cursor offset actually set? */ + if (!crtc->cursor->block) { + DRM_ERROR("No cursor available on crtc %d\n", crtc->index); + return -EINVAL; + } + + OUT_MODE(NV50_CRTC0_CURSOR_CTRL + offset, NV50_CRTC0_CURSOR_CTRL_SHOW); + + return 0; +} + +static int nv50_cursor_hide(struct nv50_crtc *crtc) +{ + struct drm_nouveau_private *dev_priv = crtc->dev->dev_private; + uint32_t offset = crtc->index * 0x400; + + NV50_DEBUG("\n"); + + OUT_MODE(NV50_CRTC0_CURSOR_CTRL + offset, NV50_CRTC0_CURSOR_CTRL_HIDE); + + return 0; +} + +static int nv50_cursor_set_pos(struct nv50_crtc *crtc, int x, int y) +{ + struct drm_nouveau_private *dev_priv = crtc->dev->dev_private; + + NV_WRITE(NV50_HW_CURSOR_POS(crtc->index), ((y & 0xFFFF) << 16) | (x & 0xFFFF)); + /* Needed to make the cursor move. */ + NV_WRITE(NV50_HW_CURSOR_POS_CTRL(crtc->index), 0); + + return 0; +} + +static int nv50_cursor_set_bo(struct nv50_crtc *crtc, drm_handle_t handle) +{ + struct mem_block *block = NULL; + struct drm_nouveau_private *dev_priv = crtc->dev->dev_private; + + NV50_DEBUG("\n"); + + block = find_block_by_handle(dev_priv->fb_heap, handle); + + if (block) { + bool first_time = false; + if (!crtc->cursor->block) + first_time = true; + + crtc->cursor->block = block; + + /* set the cursor offset cursor */ + if (first_time) { + OUT_MODE(NV50_CRTC0_CURSOR_OFFSET + crtc->index * 0x400, crtc->cursor->block->start >> 8); + if (crtc->cursor->visible) + crtc->cursor->show(crtc); + } + } else { + return -EINVAL; + } + + return 0; +} + +int nv50_cursor_create(struct nv50_crtc *crtc) +{ + NV50_DEBUG("\n"); + + if (!crtc) + return -EINVAL; + + crtc->cursor = kzalloc(sizeof(struct nv50_cursor), GFP_KERNEL); + + /* function pointers */ + crtc->cursor->show = nv50_cursor_show; + crtc->cursor->hide = nv50_cursor_hide; + crtc->cursor->set_pos = nv50_cursor_set_pos; + crtc->cursor->set_bo = nv50_cursor_set_bo; + crtc->cursor->enable = nv50_cursor_enable; + crtc->cursor->disable = nv50_cursor_disable; + + /* defaults */ + crtc->cursor->visible = true; /* won't happen until there is a cursor bo */ + + return 0; +} + +int nv50_cursor_destroy(struct nv50_crtc *crtc) +{ + int rval = 0; + + NV50_DEBUG("\n"); + + if (!crtc) + return -EINVAL; + + if (crtc->cursor->enabled) { + rval = crtc->cursor->disable(crtc); + if (rval != 0) + return rval; + } + + kfree(crtc->cursor); + crtc->cursor = NULL; + + return 0; +} diff --git a/linux-core/nv50_cursor.h b/linux-core/nv50_cursor.h new file mode 100644 index 00000000..a2e4632c --- /dev/null +++ b/linux-core/nv50_cursor.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2008 Maarten Maathuis. + * All Rights Reserved. + * + * 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 (including the + * next paragraph) 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 OWNER(S) AND/OR ITS SUPPLIERS 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. + * + */ + +#ifndef __NV50_CURSOR_H__ +#define __NV50_CURSOR_H__ + +#include "nv50_display.h" + +struct nv50_crtc; + +struct nv50_cursor { + struct mem_block *block; + int x, y; + bool visible; + bool enabled; + + int (*show) (struct nv50_crtc *crtc); + int (*hide) (struct nv50_crtc *crtc); + int (*set_pos) (struct nv50_crtc *crtc, int x, int y); + int (*set_bo) (struct nv50_crtc *crtc, drm_handle_t handle); + int (*enable) (struct nv50_crtc *crtc); + int (*disable) (struct nv50_crtc *crtc); +}; + +int nv50_cursor_create(struct nv50_crtc *crtc); +int nv50_cursor_destroy(struct nv50_crtc *crtc); + +#endif /* __NV50_CURSOR_H__ */ diff --git a/linux-core/nv50_dac.c b/linux-core/nv50_dac.c new file mode 100644 index 00000000..f827fed4 --- /dev/null +++ b/linux-core/nv50_dac.c @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2008 Maarten Maathuis. + * All Rights Reserved. + * + * 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 (including the + * next paragraph) 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 OWNER(S) AND/OR ITS SUPPLIERS 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. + * + */ + +#include "nv50_output.h" + +static int nv50_dac_validate_mode(struct nv50_output *output, struct nouveau_hw_mode *mode) +{ + NV50_DEBUG("\n"); + + if (mode->clock > 400000) + return MODE_CLOCK_HIGH; + + if (mode->clock < 25000) + return MODE_CLOCK_LOW; + + return MODE_OK; +} + +static int nv50_dac_execute_mode(struct nv50_output *output, bool disconnect) +{ + struct drm_nouveau_private *dev_priv = output->dev->dev_private; + struct nv50_crtc *crtc = output->crtc; + struct nouveau_hw_mode *desired_mode = NULL; + + uint32_t offset = nv50_output_or_offset(output) * 0x80; + + uint32_t mode_ctl = NV50_DAC_MODE_CTRL_OFF; + uint32_t mode_ctl2 = 0; + + NV50_DEBUG("or %d\n", nv50_output_or_offset(output)); + + if (disconnect) { + NV50_DEBUG("Disconnecting DAC\n"); + OUT_MODE(NV50_DAC0_MODE_CTRL + offset, mode_ctl); + return 0; + } + + desired_mode = (crtc->use_native_mode ? crtc->native_mode : + crtc->mode); + + if (crtc->index == 1) + mode_ctl |= NV50_DAC_MODE_CTRL_CRTC1; + else + mode_ctl |= NV50_DAC_MODE_CTRL_CRTC0; + + /* Lacking a working tv-out, this is not a 100% sure. */ + if (output->type == OUTPUT_DAC) { + mode_ctl |= 0x40; + } else if (output->type == OUTPUT_TV) { + mode_ctl |= 0x100; + } + + if (desired_mode->flags & V_NHSYNC) + mode_ctl2 |= NV50_DAC_MODE_CTRL2_NHSYNC; + + if (desired_mode->flags & V_NVSYNC) + mode_ctl2 |= NV50_DAC_MODE_CTRL2_NVSYNC; + + OUT_MODE(NV50_DAC0_MODE_CTRL + offset, mode_ctl); + OUT_MODE(NV50_DAC0_MODE_CTRL2 + offset, mode_ctl2); + + return 0; +} + +static int nv50_dac_set_clock_mode(struct nv50_output *output) +{ + struct drm_nouveau_private *dev_priv = output->dev->dev_private; + + NV50_DEBUG("or %d\n", nv50_output_or_offset(output)); + + NV_WRITE(NV50_PDISPLAY_DAC_CLK_CLK_CTRL2(nv50_output_or_offset(output)), 0); + + return 0; +} + +static int nv50_dac_destroy(struct nv50_output *output) +{ + struct drm_device *dev = output->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nv50_display *display = nv50_get_display(dev); + + NV50_DEBUG("\n"); + + if (!display || !output) + return -EINVAL; + + list_del(&output->head); + + kfree(output->native_mode); + if (dev_priv->free_output) + dev_priv->free_output(output); + + return 0; +} + +int nv50_dac_create(struct drm_device *dev, int dcb_entry) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nv50_output *output = NULL; + struct nv50_display *display = NULL; + struct dcb_entry *entry = NULL; + + NV50_DEBUG("\n"); + + /* This allows the public layer to do it's thing. */ + if (dev_priv->alloc_output) + output = dev_priv->alloc_output(dev); + + if (!output) + return -ENOMEM; + + output->dev = dev; + + display = nv50_get_display(dev); + if (!display) + goto out; + + entry = &dev_priv->dcb_table.entry[dcb_entry]; + if (!entry) + goto out; + + switch (entry->type) { + case DCB_OUTPUT_ANALOG: + output->type = OUTPUT_DAC; + DRM_INFO("Detected a DAC output\n"); + break; + default: + goto out; + } + + output->dcb_entry = dcb_entry; + output->bus = entry->bus; + + list_add_tail(&output->head, &display->outputs); + + output->native_mode = kzalloc(sizeof(struct nouveau_hw_mode), GFP_KERNEL); + + /* Set function pointers. */ + output->validate_mode = nv50_dac_validate_mode; + output->execute_mode = nv50_dac_execute_mode; + output->set_clock_mode = nv50_dac_set_clock_mode; + output->detect = NULL; /* TODO */ + output->destroy = nv50_dac_destroy; + + return 0; + +out: + if (output->native_mode) + kfree(output->native_mode); + if (dev_priv->free_output) + dev_priv->free_output(output); + return -EINVAL; +} + diff --git a/linux-core/nv50_display.c b/linux-core/nv50_display.c new file mode 100644 index 00000000..56ddeb97 --- /dev/null +++ b/linux-core/nv50_display.c @@ -0,0 +1,337 @@ +/* + * Copyright (C) 2008 Maarten Maathuis. + * All Rights Reserved. + * + * 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 (including the + * next paragraph) 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 OWNER(S) AND/OR ITS SUPPLIERS 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. + * + */ + +#include "nv50_display.h" +#include "nv50_crtc.h" +#include "nv50_output.h" +#include "nv50_connector.h" + +static int nv50_display_pre_init(struct nv50_display *display) +{ + struct drm_device *dev = display->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; + int i; + + NV50_DEBUG("\n"); + + NV_WRITE(0x00610184, NV_READ(0x00614004)); + /* + * I think the 0x006101XX range is some kind of main control area that enables things. + */ + /* CRTC? */ + NV_WRITE(0x00610190 + 0 * 0x10, NV_READ(0x00616100 + 0 * 0x800)); + NV_WRITE(0x00610190 + 1 * 0x10, NV_READ(0x00616100 + 1 * 0x800)); + NV_WRITE(0x00610194 + 0 * 0x10, NV_READ(0x00616104 + 0 * 0x800)); + NV_WRITE(0x00610194 + 1 * 0x10, NV_READ(0x00616104 + 1 * 0x800)); + NV_WRITE(0x00610198 + 0 * 0x10, NV_READ(0x00616108 + 0 * 0x800)); + NV_WRITE(0x00610198 + 1 * 0x10, NV_READ(0x00616108 + 1 * 0x800)); + NV_WRITE(0x0061019c + 0 * 0x10, NV_READ(0x0061610c + 0 * 0x800)); + NV_WRITE(0x0061019c + 1 * 0x10, NV_READ(0x0061610c + 1 * 0x800)); + /* DAC */ + NV_WRITE(0x006101d0 + 0 * 0x4, NV_READ(0x0061a000 + 0 * 0x800)); + NV_WRITE(0x006101d0 + 1 * 0x4, NV_READ(0x0061a000 + 1 * 0x800)); + NV_WRITE(0x006101d0 + 2 * 0x4, NV_READ(0x0061a000 + 2 * 0x800)); + /* SOR */ + NV_WRITE(0x006101e0 + 0 * 0x4, NV_READ(0x0061c000 + 0 * 0x800)); + NV_WRITE(0x006101e0 + 1 * 0x4, NV_READ(0x0061c000 + 1 * 0x800)); + /* Something not yet in use, tv-out maybe. */ + NV_WRITE(0x006101f0 + 0 * 0x4, NV_READ(0x0061e000 + 0 * 0x800)); + NV_WRITE(0x006101f0 + 1 * 0x4, NV_READ(0x0061e000 + 1 * 0x800)); + NV_WRITE(0x006101f0 + 2 * 0x4, NV_READ(0x0061e000 + 2 * 0x800)); + + for (i = 0; i < 3; i++) { + NV_WRITE(NV50_PDISPLAY_DAC_REGS_DPMS_CTRL(i), 0x00550000 | NV50_PDISPLAY_DAC_REGS_DPMS_CTRL_PENDING); + NV_WRITE(NV50_PDISPLAY_DAC_REGS_CLK_CTRL1(i), 0x00000001); + } + + display->preinit_done = TRUE; + + return 0; +} + +static int nv50_display_init(struct nv50_display *display) +{ + struct drm_device *dev = display->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; + uint32_t val; + + NV50_DEBUG("\n"); + + /* The precise purpose is unknown, i suspect it has something to do with text mode. */ + if (NV_READ(NV50_PDISPLAY_SUPERVISOR) & 0x100) { + NV_WRITE(NV50_PDISPLAY_SUPERVISOR, 0x100); + NV_WRITE(0x006194e8, NV_READ(0x006194e8) & ~1); + while (NV_READ(0x006194e8) & 2); + } + + /* taken from nv bug #12637 */ + NV_WRITE(NV50_PDISPLAY_UNK200_CTRL, 0x2b00); + do { + val = NV_READ(NV50_PDISPLAY_UNK200_CTRL); + if ((val & 0x9f0000) == 0x20000) + NV_WRITE(NV50_PDISPLAY_UNK200_CTRL, val | 0x800000); + + if ((val & 0x3f0000) == 0x30000) + NV_WRITE(NV50_PDISPLAY_UNK200_CTRL, val | 0x200000); + } while (val & 0x1e0000); + + NV_WRITE(NV50_PDISPLAY_CTRL_STATE, NV50_PDISPLAY_CTRL_STATE_ENABLE); + NV_WRITE(NV50_PDISPLAY_UNK200_CTRL, 0x1000b03); + while (!(NV_READ(NV50_PDISPLAY_UNK200_CTRL) & 0x40000000)); + + /* For the moment this is just a wrapper, which should be replaced with a real fifo at some point. */ + OUT_MODE(NV50_UNK84, 0); + OUT_MODE(NV50_UNK88, 0); + OUT_MODE(NV50_CRTC0_BLANK_CTRL, NV50_CRTC0_BLANK_CTRL_BLANK); + OUT_MODE(NV50_CRTC0_UNK800, 0); + OUT_MODE(NV50_CRTC0_DISPLAY_START, 0); + OUT_MODE(NV50_CRTC0_UNK82C, 0); + + /* enable clock change interrupts. */ + NV_WRITE(NV50_PDISPLAY_SUPERVISOR_INTR, NV_READ(NV50_PDISPLAY_SUPERVISOR_INTR) | 0x70); + + display->init_done = TRUE; + + return 0; +} + +static int nv50_display_disable(struct nv50_display *display) +{ + struct drm_device *dev = display->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nv50_crtc *crtc = NULL; + int i; + + NV50_DEBUG("\n"); + + list_for_each_entry(crtc, &display->crtcs, head) { + crtc->blank(crtc, TRUE); + } + + display->update(display); + + /* Almost like ack'ing a vblank interrupt, maybe in the spirit of cleaning up? */ + list_for_each_entry(crtc, &display->crtcs, head) { + if (crtc->active) { + uint32_t mask; + + if (crtc->index == 1) + mask = NV50_PDISPLAY_SUPERVISOR_CRTC1; + else + mask = NV50_PDISPLAY_SUPERVISOR_CRTC0; + + NV_WRITE(NV50_PDISPLAY_SUPERVISOR, mask); + while (!(NV_READ(NV50_PDISPLAY_SUPERVISOR) & mask)); + } + } + + NV_WRITE(NV50_PDISPLAY_UNK200_CTRL, 0); + NV_WRITE(NV50_PDISPLAY_CTRL_STATE, 0); + while ((NV_READ(NV50_PDISPLAY_UNK200_CTRL) & 0x1e0000) != 0); + + for (i = 0; i < 2; i++) { + while (NV_READ(NV50_PDISPLAY_SOR_REGS_DPMS_STATE(i)) & NV50_PDISPLAY_SOR_REGS_DPMS_STATE_WAIT); + } + + /* disable clock change interrupts. */ + NV_WRITE(NV50_PDISPLAY_SUPERVISOR_INTR, NV_READ(NV50_PDISPLAY_SUPERVISOR_INTR) & ~0x70); + + display->init_done = FALSE; + + return 0; +} + +static int nv50_display_update(struct nv50_display *display) +{ + struct drm_device *dev = display->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; + + NV50_DEBUG("\n"); + + OUT_MODE(NV50_UPDATE_DISPLAY, 0); + + return 0; +} + +int nv50_display_create(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nv50_display *display = kzalloc(sizeof(struct nv50_display), GFP_KERNEL); + int i, type, output_index, bus; + /* DAC0, DAC1, DAC2, SOR0, SOR1*/ + int or_counter[5] = {0, 0, 0, 0, 0}; + int i2c_index[5] = {0, 0, 0, 0, 0}; + uint32_t bus_mask = 0; + uint32_t bus_digital = 0, bus_analog = 0; + + NV50_DEBUG("\n"); + + INIT_LIST_HEAD(&display->crtcs); + INIT_LIST_HEAD(&display->outputs); + INIT_LIST_HEAD(&display->connectors); + + dev_priv->display_priv = display; + + for (i = 0; i < 2; i++) { + nv50_crtc_create(dev, i); + } + + /* we setup the outputs up from the BIOS table */ + for (i = 0 ; i < dev_priv->dcb_table.entries; i++) { + type = dev_priv->dcb_table.entry[i].type; + output_index = ffs(dev_priv->dcb_table.entry[i].or) - 1; + bus = dev_priv->dcb_table.entry[i].bus; + + switch (type) { + case DCB_OUTPUT_TMDS: + case DCB_OUTPUT_LVDS: + or_counter[output_index + 3] += 1; + i2c_index[output_index + 3] = dev_priv->dcb_table.entry[i].i2c_index; + bus_digital |= (1 << bus); + nv50_sor_create(dev, i); + break; + case DCB_OUTPUT_ANALOG: + or_counter[output_index] += 1; + i2c_index[output_index] = dev_priv->dcb_table.entry[i].i2c_index; + bus_analog |= (1 << bus); + nv50_dac_create(dev, i); + break; + default: + break; + } + + } + + /* setup the connectors based on the output tables. */ + for (i = 0 ; i < dev_priv->dcb_table.entries; i++) { + int connector_type = 0; + type = dev_priv->dcb_table.entry[i].type; + bus = dev_priv->dcb_table.entry[i].bus; + + /* already done? */ + if (bus_mask & (1 << bus)) + continue; + + /* only do it for supported outputs */ + if (type != DCB_OUTPUT_ANALOG && type != DCB_OUTPUT_TMDS + && type != DCB_OUTPUT_LVDS) + continue; + + switch (type) { + case DCB_OUTPUT_TMDS: + case DCB_OUTPUT_ANALOG: + if ((bus_digital & (1 << bus)) && (bus_analog & (1 << bus))) + connector_type = CONNECTOR_DVI_I; + else if (bus_digital & (1 << bus)) + connector_type = CONNECTOR_DVI_D; + else if (bus_analog & (1 << bus)) + connector_type = CONNECTOR_VGA; + break; + case DCB_OUTPUT_LVDS: + connector_type = CONNECTOR_LVDS; + break; + default: + connector_type = CONNECTOR_UNKNOWN; + break; + } + + if (connector_type == CONNECTOR_UNKNOWN) + continue; + + nv50_connector_create(dev, bus, dev_priv->dcb_table.entry[i].i2c_index, connector_type); + + bus_mask |= (1 << bus); + } + + display->dev = dev; + + /* function pointers */ + display->init = nv50_display_init; + display->pre_init = nv50_display_pre_init; + display->disable = nv50_display_disable; + display->update = nv50_display_update; + + return 0; +} + +int nv50_display_destroy(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nv50_display *display = nv50_get_display(dev); + struct nv50_crtc *crtc = NULL; + struct nv50_output *output = NULL; + struct nv50_connector *connector = NULL; + + NV50_DEBUG("\n"); + + if (display->init_done) + display->disable(display); + + list_for_each_entry(connector, &display->connectors, head) { + connector->destroy(connector); + } + + list_for_each_entry(output, &display->outputs, head) { + output->destroy(output); + } + + list_for_each_entry(crtc, &display->crtcs, head) { + crtc->destroy(crtc); + } + + kfree(display); + dev_priv->display_priv = NULL; + + return 0; +} + +/* This can be replaced with a real fifo in the future. */ +void nv50_display_command(struct drm_nouveau_private *dev_priv, uint32_t mthd, uint32_t val) +{ + uint32_t counter = 0; + +#if 1 + DRM_INFO("mthd 0x%03X val 0x%08X\n", mthd, val); +#endif + + NV_WRITE(NV50_PDISPLAY_CTRL_VAL, val); + NV_WRITE(NV50_PDISPLAY_CTRL_STATE, NV50_PDISPLAY_CTRL_STATE_PENDING | 0x10000 | mthd | NV50_PDISPLAY_CTRL_STATE_ENABLE); + + while (NV_READ(NV50_PDISPLAY_CTRL_STATE) & NV50_PDISPLAY_CTRL_STATE_PENDING) { + counter++; + if (counter > 25000) { + DRM_ERROR("You probably need a reboot now\n"); + break; + } + } +} + +struct nv50_display *nv50_get_display(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + + return (struct nv50_display *) dev_priv->display_priv; +} diff --git a/linux-core/nv50_display.h b/linux-core/nv50_display.h new file mode 100644 index 00000000..f20e67da --- /dev/null +++ b/linux-core/nv50_display.h @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2008 Maarten Maathuis. + * All Rights Reserved. + * + * 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 (including the + * next paragraph) 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 OWNER(S) AND/OR ITS SUPPLIERS 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. + * + */ + +#ifndef __NV50_DISPLAY_H__ +#define __NV50_DISPLAY_H__ + +#include "drmP.h" +#include "drm.h" +#include "nouveau_dma.h" +#include "nouveau_drv.h" +#include "nouveau_reg.h" +#include "nv50_display_commands.h" + +/* for convience, so you can see through the trees. */ +#define NV50_DEBUG DRM_ERROR + +struct nouveau_hw_mode { + unsigned int clock; + unsigned short hdisplay, hblank_start, hsync_start, hsync_end, hblank_end, htotal; + unsigned short vdisplay, vblank_start, vsync_start, vsync_end, vblank_end, vtotal; + + unsigned int flags; +}; + +struct nv50_crtc; +struct nv50_output; +struct nv50_connector; + +struct nv50_display { + struct drm_device *dev; + + bool preinit_done; + bool init_done; + + int last_crtc; /* crtc used for last mode set */ + + int (*pre_init) (struct nv50_display *display); + int (*init) (struct nv50_display *display); + int (*disable) (struct nv50_display *display); + int (*update) (struct nv50_display *display); + + struct list_head crtcs; + struct list_head outputs; + struct list_head connectors; +}; + +enum scaling_modes { + SCALE_PANEL, + SCALE_FULLSCREEN, + SCALE_ASPECT, + SCALE_NOSCALE, + SCALE_INVALID +}; + +void nv50_display_command(struct drm_nouveau_private *dev_priv, uint32_t mthd, uint32_t val); +struct nv50_display *nv50_get_display(struct drm_device *dev); +int nv50_display_create(struct drm_device *dev); +int nv50_display_destroy(struct drm_device *dev); + +#endif /* __NV50_DISPLAY_H__ */ diff --git a/linux-core/nv50_display_commands.h b/linux-core/nv50_display_commands.h new file mode 100644 index 00000000..97b3d3c1 --- /dev/null +++ b/linux-core/nv50_display_commands.h @@ -0,0 +1,196 @@ +/* + * Copyright (C) 2008 Maarten Maathuis. + * All Rights Reserved. + * + * 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 (including the + * next paragraph) 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 OWNER(S) AND/OR ITS SUPPLIERS 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. + * + */ + +/* copied from ddx definitions, until rules-ng can handle this */ + +#define NV50_UPDATE_DISPLAY 0x80 +#define NV50_UNK84 0x84 +#define NV50_UNK88 0x88 + +#define NV50_DAC0_MODE_CTRL 0x400 + #define NV50_DAC_MODE_CTRL_OFF (0 << 0) + #define NV50_DAC_MODE_CTRL_CRTC0 (1 << 0) + #define NV50_DAC_MODE_CTRL_CRTC1 (1 << 1) +#define NV50_DAC1_MODE_CTRL 0x480 +#define NV50_DAC2_MODE_CTRL 0x500 + +#define NV50_DAC0_MODE_CTRL2 0x404 + #define NV50_DAC_MODE_CTRL2_NHSYNC (1 << 0) + #define NV50_DAC_MODE_CTRL2_NVSYNC (2 << 0) +#define NV50_DAC1_MODE_CTRL2 0x484 +#define NV50_DAC2_MODE_CTRL2 0x504 + +#define NV50_SOR0_MODE_CTRL 0x600 + #define NV50_SOR_MODE_CTRL_OFF (0 << 0) + #define NV50_SOR_MODE_CTRL_CRTC0 (1 << 0) + #define NV50_SOR_MODE_CTRL_CRTC1 (1 << 1) + #define NV50_SOR_MODE_CTRL_LVDS (0 << 8) + #define NV50_SOR_MODE_CTRL_TMDS (1 << 8) + #define NV50_SOR_MODE_CTRL_TMDS_DUAL_LINK (4 << 8) + #define NV50_SOR_MODE_CTRL_NHSYNC (1 << 12) + #define NV50_SOR_MODE_CTRL_NVSYNC (2 << 12) +#define NV50_SOR1_MODE_CTRL 0x640 + +#define NV50_CRTC0_UNK800 0x800 +#define NV50_CRTC0_CLOCK 0x804 +#define NV50_CRTC0_INTERLACE 0x808 + +/* 0x810 is a reasonable guess, nothing more. */ +#define NV50_CRTC0_DISPLAY_START 0x810 +#define NV50_CRTC0_DISPLAY_TOTAL 0x814 +#define NV50_CRTC0_SYNC_DURATION 0x818 +#define NV50_CRTC0_SYNC_START_TO_BLANK_END 0x81C +#define NV50_CRTC0_MODE_UNK1 0x820 +#define NV50_CRTC0_MODE_UNK2 0x824 + +#define NV50_CRTC0_UNK82C 0x82C + +/* You can't have a palette in 8 bit mode (=OFF) */ +#define NV50_CRTC0_CLUT_MODE 0x840 + #define NV50_CRTC0_CLUT_MODE_BLANK 0x00000000 + #define NV50_CRTC0_CLUT_MODE_OFF 0x80000000 + #define NV50_CRTC0_CLUT_MODE_ON 0xC0000000 +#define NV50_CRTC0_CLUT_OFFSET 0x844 + +/* Anyone know what part of the chip is triggered here precisely? */ +#define NV84_CRTC0_BLANK_UNK1 0x85C + #define NV84_CRTC0_BLANK_UNK1_BLANK 0x0 + #define NV84_CRTC0_BLANK_UNK1_UNBLANK 0x1 + +#define NV50_CRTC0_FB_OFFSET 0x860 + +#define NV50_CRTC0_FB_SIZE 0x868 +#define NV50_CRTC0_FB_PITCH 0x86C + +#define NV50_CRTC0_DEPTH 0x870 + #define NV50_CRTC0_DEPTH_8BPP 0x1E00 + #define NV50_CRTC0_DEPTH_15BPP 0xE900 + #define NV50_CRTC0_DEPTH_16BPP 0xE800 + #define NV50_CRTC0_DEPTH_24BPP 0xCF00 + +/* I'm openminded to better interpretations. */ +/* This is an educated guess. */ +/* NV50 has RAMDAC and TMDS offchip, so it's unlikely to be that. */ +#define NV50_CRTC0_BLANK_CTRL 0x874 + #define NV50_CRTC0_BLANK_CTRL_BLANK 0x0 + #define NV50_CRTC0_BLANK_CTRL_UNBLANK 0x1 + +#define NV50_CRTC0_CURSOR_CTRL 0x880 + #define NV50_CRTC0_CURSOR_CTRL_SHOW 0x85000000 + #define NV50_CRTC0_CURSOR_CTRL_HIDE 0x05000000 + +#define NV50_CRTC0_CURSOR_OFFSET 0x884 + +/* Anyone know what part of the chip is triggered here precisely? */ +#define NV84_CRTC0_BLANK_UNK2 0x89C + #define NV84_CRTC0_BLANK_UNK2_BLANK 0x0 + #define NV84_CRTC0_BLANK_UNK2_UNBLANK 0x1 + +#define NV50_CRTC0_DITHERING_CTRL 0x8A0 + #define NV50_CRTC0_DITHERING_CTRL_ON 0x11 + #define NV50_CRTC0_DITHERING_CTRL_OFF 0x0 + +#define NV50_CRTC0_SCALE_CTRL 0x8A4 + #define NV50_CRTC0_SCALE_CTRL_SCALER_INACTIVE (0 << 0) + /* It doesn't seem to be needed, hence i wonder what it does precisely. */ + #define NV50_CRTC0_SCALE_CTRL_SCALER_ACTIVE (9 << 0) +#define NV50_CRTC0_COLOR_CTRL 0x8A8 + #define NV50_CRTC_COLOR_CTRL_MODE_COLOR (4 << 16) + +#define NV50_CRTC0_FB_POS 0x8C0 +#define NV50_CRTC0_REAL_RES 0x8C8 + +/* Added a macro, because the signed stuff can cause you problems very quickly. */ +#define NV50_CRTC0_SCALE_CENTER_OFFSET 0x8D4 + #define NV50_CRTC_SCALE_CENTER_OFFSET_VAL(x, y) ((((unsigned)y << 16) & 0xFFFF0000) | (((unsigned)x) & 0x0000FFFF)) +/* Both of these are needed, otherwise nothing happens. */ +#define NV50_CRTC0_SCALE_RES1 0x8D8 +#define NV50_CRTC0_SCALE_RES2 0x8DC + +#define NV50_CRTC1_UNK800 0xC00 +#define NV50_CRTC1_CLOCK 0xC04 +#define NV50_CRTC1_INTERLACE 0xC08 + +/* 0xC10 is a reasonable guess, nothing more. */ +#define NV50_CRTC1_DISPLAY_START 0xC10 +#define NV50_CRTC1_DISPLAY_TOTAL 0xC14 +#define NV50_CRTC1_SYNC_DURATION 0xC18 +#define NV50_CRTC1_SYNC_START_TO_BLANK_END 0xC1C +#define NV50_CRTC1_MODE_UNK1 0xC20 +#define NV50_CRTC1_MODE_UNK2 0xC24 + +#define NV50_CRTC1_CLUT_MODE 0xC40 + #define NV50_CRTC1_CLUT_MODE_BLANK 0x00000000 + #define NV50_CRTC1_CLUT_MODE_OFF 0x80000000 + #define NV50_CRTC1_CLUT_MODE_ON 0xC0000000 +#define NV50_CRTC1_CLUT_OFFSET 0xC44 + +/* Anyone know what part of the chip is triggered here precisely? */ +#define NV84_CRTC1_BLANK_UNK1 0xC5C + #define NV84_CRTC1_BLANK_UNK1_BLANK 0x0 + #define NV84_CRTC1_BLANK_UNK1_UNBLANK 0x1 + +#define NV50_CRTC1_FB_OFFSET 0xC60 + +#define NV50_CRTC1_FB_SIZE 0xC68 +#define NV50_CRTC1_FB_PITCH 0xC6C + +#define NV50_CRTC1_DEPTH 0xC70 + #define NV50_CRTC1_DEPTH_8BPP 0x1E00 + #define NV50_CRTC1_DEPTH_15BPP 0xE900 + #define NV50_CRTC1_DEPTH_16BPP 0xE800 + #define NV50_CRTC1_DEPTH_24BPP 0xCF00 + +/* I'm openminded to better interpretations. */ +#define NV50_CRTC1_BLANK_CTRL 0xC74 + #define NV50_CRTC1_BLANK_CTRL_BLANK 0x0 + #define NV50_CRTC1_BLANK_CTRL_UNBLANK 0x1 + +#define NV50_CRTC1_CURSOR_CTRL 0xC80 + #define NV50_CRTC1_CURSOR_CTRL_SHOW 0x85000000 + #define NV50_CRTC1_CURSOR_CTRL_HIDE 0x05000000 + +#define NV50_CRTC1_CURSOR_OFFSET 0xC84 + +/* Anyone know what part of the chip is triggered here precisely? */ +#define NV84_CRTC1_BLANK_UNK2 0xC9C + #define NV84_CRTC1_BLANK_UNK2_BLANK 0x0 + #define NV84_CRTC1_BLANK_UNK2_UNBLANK 0x1 + +#define NV50_CRTC1_DITHERING_CTRL 0xCA0 + #define NV50_CRTC1_DITHERING_CTRL_ON 0x11 + #define NV50_CRTC1_DITHERING_CTRL_OFF 0x0 + +#define NV50_CRTC1_SCALE_CTRL 0xCA4 +#define NV50_CRTC1_COLOR_CTRL 0xCA8 + +#define NV50_CRTC1_FB_POS 0xCC0 +#define NV50_CRTC1_REAL_RES 0xCC8 + +#define NV50_CRTC1_SCALE_CENTER_OFFSET 0xCD4 +/* Both of these are needed, otherwise nothing happens. */ +#define NV50_CRTC1_SCALE_RES1 0xCD8 +#define NV50_CRTC1_SCALE_RES2 0xCDC diff --git a/linux-core/nv50_fb.c b/linux-core/nv50_fb.c new file mode 100644 index 00000000..b44b48ab --- /dev/null +++ b/linux-core/nv50_fb.c @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2008 Maarten Maathuis. + * All Rights Reserved. + * + * 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 (including the + * next paragraph) 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 OWNER(S) AND/OR ITS SUPPLIERS 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. + * + */ + +#include "nv50_fb.h" +#include "nv50_lut.h" +#include "nv50_crtc.h" +#include "nv50_display.h" + +static int nv50_fb_bind(struct nv50_crtc *crtc, struct nv50_fb_info *info) +{ + int rval = 0; + + NV50_DEBUG("\n"); + + if (!crtc || !info) { + DRM_ERROR("crtc %p info %p\n",crtc, info); + return -EINVAL; + } + + if (!info->block || !info->width || !info->height || !info->depth || !info->bpp) { + DRM_ERROR("block %p width %d height %d depth %d bpp %d\n", info->block, info->width, info->height, info->depth, info->bpp); + return -EINVAL; + } + + crtc->fb->block = info->block; + crtc->fb->width = info->width; + crtc->fb->height = info->height; + + crtc->fb->y = info->x; + crtc->fb->x = info->y; + + crtc->fb->depth = info->depth; + crtc->fb->bpp = info->bpp; + + /* update lut if needed */ + if (crtc->fb->depth != crtc->lut->depth) { + int r_size = 0, g_size = 0, b_size = 0; + uint16_t *r_val, *g_val, *b_val; + int i; + + switch (crtc->fb->depth) { + case 15: + r_size = 32; + g_size = 32; + b_size = 32; + break; + case 16: + r_size = 32; + g_size = 64; + b_size = 32; + break; + case 24: + default: + r_size = 256; + g_size = 256; + b_size = 256; + break; + } + + r_val = kmalloc(r_size * sizeof(uint16_t), GFP_KERNEL); + g_val = kmalloc(g_size * sizeof(uint16_t), GFP_KERNEL); + b_val = kmalloc(b_size * sizeof(uint16_t), GFP_KERNEL); + + if (!r_val || !g_val || !b_val) + return -ENOMEM; + + /* Set the color indices. */ + for (i = 0; i < r_size; i++) { + r_val[i] = i << 8; + } + for (i = 0; i < g_size; i++) { + g_val[i] = i << 8; + } + for (i = 0; i < b_size; i++) { + b_val[i] = i << 8; + } + + rval = crtc->lut->set(crtc, r_val, g_val, b_val); + + /* free before returning */ + kfree(r_val); + kfree(g_val); + kfree(b_val); + + if (rval != 0) + return rval; + } + + return 0; +} + +int nv50_fb_create(struct nv50_crtc *crtc) +{ + if (!crtc) + return -EINVAL; + + crtc->fb = kzalloc(sizeof(struct nv50_fb), GFP_KERNEL); + + crtc->fb->bind = nv50_fb_bind; + + return 0; +} + +int nv50_fb_destroy(struct nv50_crtc *crtc) +{ + if (!crtc) + return -EINVAL; + + kfree(crtc->fb); + crtc->fb = NULL; + + return 0; +} diff --git a/linux-core/nv50_fb.h b/linux-core/nv50_fb.h new file mode 100644 index 00000000..6b286315 --- /dev/null +++ b/linux-core/nv50_fb.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2008 Maarten Maathuis. + * All Rights Reserved. + * + * 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 (including the + * next paragraph) 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 OWNER(S) AND/OR ITS SUPPLIERS 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. + * + */ + +#ifndef __NV50_FB_H__ +#define __NV50_FB_H__ + +#include "nv50_display.h" + +struct nv50_crtc; + +struct nv50_fb_info { + struct mem_block *block; + int width, height; + int bpp, depth; + int x,y; +}; + +struct nv50_fb { + struct mem_block *block; + int width, height; + int bpp, depth; + + int x,y; + + /* function points */ + int (*bind) (struct nv50_crtc *crtc, struct nv50_fb_info *info); +}; + +int nv50_fb_create(struct nv50_crtc *crtc); +int nv50_fb_destroy(struct nv50_crtc *crtc); + +#endif /* __NV50_FB_H__ */ diff --git a/linux-core/nv50_i2c.c b/linux-core/nv50_i2c.c new file mode 100644 index 00000000..cf55645b --- /dev/null +++ b/linux-core/nv50_i2c.c @@ -0,0 +1,356 @@ +/* + * Copyright (C) 2008 Maarten Maathuis. + * All Rights Reserved. + * + * 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 (including the + * next paragraph) 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 OWNER(S) AND/OR ITS SUPPLIERS 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. + * + */ + +/* This is largely a clone from xorg i2c functions, as i had serious trouble getting an i2c_bit_algo adaptor running. */ + +#include "nv50_i2c.h" + +static void nv50_i2c_set_bits(struct nv50_i2c_channel *chan, int clock_high, int data_high) +{ + struct drm_nouveau_private *dev_priv = chan->dev->dev_private; + + NV_WRITE(NV50_PCONNECTOR_I2C_PORT(chan->index), 4 | (data_high << 1) | clock_high); +} + +static void nv50_i2c_get_bits(struct nv50_i2c_channel *chan, int *clock_high, int *data_high) +{ + struct drm_nouveau_private *dev_priv = chan->dev->dev_private; + + uint32_t val = NV_READ(NV50_PCONNECTOR_I2C_PORT(chan->index)); + + if (val & 1) + *clock_high = 1; + else + *clock_high = 0; + + if (val & 2) + *data_high = 1; + else + *data_high = 0; +} + +static bool nv50_i2c_raise_clock(struct nv50_i2c_channel *chan, int data) +{ + int i, clock; + + nv50_i2c_set_bits(chan, 1, data); + udelay(2); + + for (i = 2200; i > 0; i -= 2) { + nv50_i2c_get_bits(chan, &clock, &data); + if (clock) + return TRUE; + udelay(2); + } + + printk("a timeout occured in nv50_i2c_raise_clock\n"); + + return FALSE; +} + +static bool nv50_i2c_start(struct nv50_i2c_channel *chan) +{ + if (!nv50_i2c_raise_clock(chan, 1)) + return FALSE; + + nv50_i2c_set_bits(chan, 1, 0); + udelay(5); + + nv50_i2c_set_bits(chan, 0, 0); + udelay(5); + + return TRUE; +} + +static void nv50_i2c_stop(struct nv50_i2c_channel *chan) +{ + nv50_i2c_set_bits(chan, 0, 0); + udelay(2); + + nv50_i2c_set_bits(chan, 1, 0); + udelay(5); + + nv50_i2c_set_bits(chan, 1, 1); + udelay(5); +} + +static bool nv50_i2c_write_bit(struct nv50_i2c_channel *chan, int data) +{ + bool rval; + + nv50_i2c_set_bits(chan, 0, data); + udelay(2); + + rval = nv50_i2c_raise_clock(chan, data); + udelay(5); + + nv50_i2c_set_bits(chan, 0, data); + udelay(5); + + return rval; +} + +static bool nv50_i2c_read_bit(struct nv50_i2c_channel *chan, int *data) +{ + bool rval; + int clock; + + rval = nv50_i2c_raise_clock(chan, 1); + udelay(5); + + nv50_i2c_get_bits(chan, &clock, data); + udelay(5); + + nv50_i2c_set_bits(chan, 0, 1); + udelay(5); + + return rval; +} + +static bool nv50_i2c_write_byte(struct nv50_i2c_channel *chan, uint8_t byte) +{ + bool rval; + int i, clock, data; + + for (i = 7; i >= 0; i--) + if (!nv50_i2c_write_bit(chan, (byte >> i) & 1)) + return FALSE; + + nv50_i2c_set_bits(chan, 0, 1); + udelay(5); + + rval = nv50_i2c_raise_clock(chan, 1); + + if (rval) { + for (i = 40; i > 0; i -= 2) { + udelay(2); + nv50_i2c_get_bits(chan, &clock, &data); + if (data == 0) + break; + } + + if (i <= 0) { + printk("a timeout occured in nv50_i2c_write_byte\n"); + rval = FALSE; + } + } + + nv50_i2c_set_bits(chan, 0, 1); + udelay(5); + + return rval; +} + +static bool nv50_i2c_read_byte(struct nv50_i2c_channel *chan, uint8_t *byte, bool last) +{ + int i, bit; + + nv50_i2c_set_bits(chan, 0, 1); + udelay(5); + + *byte = 0; + + for (i = 7; i >= 0; i--) { + if (nv50_i2c_read_bit(chan, &bit)) { + if (bit) + *byte |= (1 << i); + } else { + return FALSE; + } + } + + if (!nv50_i2c_write_bit(chan, last ? 1 : 0)) + return FALSE; + + return TRUE; +} + +/* only 7 bits addresses. */ +static bool nv50_i2c_address(struct nv50_i2c_channel *chan, uint8_t address, bool write) +{ + if (nv50_i2c_start(chan)) { + uint8_t real_addr = (address << 1); + if (!write) + real_addr |= 1; + + if (nv50_i2c_write_byte(chan, real_addr)) + return TRUE; + + /* failure, so issue stop */ + nv50_i2c_stop(chan); + } + + return FALSE; +} + +static bool nv50_i2c_read(struct nv50_i2c_channel *chan, uint8_t address, uint8_t *buffer, uint32_t length) +{ + int i, j; + bool rval, last; + + /* retries */ + for (i = 0; i < 4; i++) { + rval = nv50_i2c_address(chan, address, FALSE); + if (!rval) + return FALSE; + + for (j = 0; j < length; j++) { + last = false; + if (j == (length - 1)) + last = true; + rval = nv50_i2c_read_byte(chan, &buffer[j], last); + if (!rval) { + nv50_i2c_stop(chan); + break; + } + } + + nv50_i2c_stop(chan); + + /* done */ + if (rval) + break; + } + + if (!rval) + printk("nv50_i2c_read failed\n"); + + return rval; +} + +static bool nv50_i2c_write(struct nv50_i2c_channel *chan, uint8_t address, uint8_t *buffer, uint32_t length) +{ + int i, j; + bool rval; + + /* retries */ + for (i = 0; i < 4; i++) { + rval = nv50_i2c_address(chan, address, TRUE); + if (!rval) + return FALSE; + + for (j = 0; j < length; j++) { + rval = nv50_i2c_write_byte(chan, buffer[j]); + if (!rval) { + break; + } + } + + nv50_i2c_stop(chan); + + /* done */ + if (rval) + break; + } + + if (!rval) + printk("nv50_i2c_write failed\n"); + + return rval; +} + +static int nv50_i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num) +{ + struct nv50_i2c_channel *chan = i2c_get_adapdata(i2c_adap); + bool rval; + int i; + + for (i = 0; i < num; i++) { + if (msgs[i].flags & I2C_M_RD) { /* read */ + rval = nv50_i2c_read(chan, msgs[i].addr, msgs[i].buf, msgs[i].len); + } else { /* write */ + rval = nv50_i2c_write(chan, msgs[i].addr, msgs[i].buf, msgs[i].len); + } + + if (!rval) + break; + } + + if (rval) + return i; + else + return -EINVAL; +} + +static u32 nv50_i2c_functionality(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C; +} + +static const struct i2c_algorithm nv50_i2c_algo = { + .master_xfer = nv50_i2c_xfer, + .functionality = nv50_i2c_functionality, +}; + +static int nv50_i2c_register_bus(struct i2c_adapter *adap) +{ + adap->algo = &nv50_i2c_algo; + + adap->timeout = 40; + adap->retries = 4; + + return i2c_add_adapter(adap); +} + +#define I2C_HW_B_NOUVEAU 0x010030 +struct nv50_i2c_channel *nv50_i2c_channel_create(struct drm_device *dev, uint32_t index) +{ + struct nv50_i2c_channel *chan; + + chan = kzalloc(sizeof(struct nv50_i2c_channel), GFP_KERNEL); + + if (!chan) + goto out; + + DRM_INFO("Creating i2c bus with index %d\n", index); + + chan->dev = dev; + chan->index = index; + snprintf(chan->adapter.name, I2C_NAME_SIZE, "nv50 i2c %d", index); + chan->adapter.owner = THIS_MODULE; + chan->adapter.id = I2C_HW_B_NOUVEAU; + chan->adapter.dev.parent = &dev->pdev->dev; + + i2c_set_adapdata(&chan->adapter, chan); + + if (nv50_i2c_register_bus(&chan->adapter)) + goto out; + + return chan; + +out: + kfree(chan); + return NULL; +} + +void nv50_i2c_channel_destroy(struct nv50_i2c_channel *chan) +{ + if (!chan) + return; + + i2c_del_adapter(&chan->adapter); + kfree(chan); +} diff --git a/linux-core/nv50_i2c.h b/linux-core/nv50_i2c.h new file mode 100644 index 00000000..1740f8ec --- /dev/null +++ b/linux-core/nv50_i2c.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2008 Maarten Maathuis. + * All Rights Reserved. + * + * 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 (including the + * next paragraph) 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 OWNER(S) AND/OR ITS SUPPLIERS 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. + * + */ + +#ifndef __NV50_I2C_H__ +#define __NV50_I2C_H__ + +#include +#include +#include +#include "drmP.h" +#include "drm.h" +#include "nv50_display.h" + +struct nv50_i2c_channel { + struct drm_device *dev; + + uint32_t index; + struct i2c_adapter adapter; +}; + +struct nv50_i2c_channel *nv50_i2c_channel_create(struct drm_device *dev, uint32_t index); +void nv50_i2c_channel_destroy(struct nv50_i2c_channel *chan); + +#endif /* __NV50_I2C_H__ */ diff --git a/linux-core/nv50_kms_wrapper.c b/linux-core/nv50_kms_wrapper.c new file mode 100644 index 00000000..01d4bc9a --- /dev/null +++ b/linux-core/nv50_kms_wrapper.c @@ -0,0 +1,960 @@ +/* + * Copyright (C) 2008 Maarten Maathuis. + * All Rights Reserved. + * + * 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 (including the + * next paragraph) 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 OWNER(S) AND/OR ITS SUPPLIERS 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. + * + */ + +#include "nv50_kms_wrapper.h" +#include "drm_crtc_helper.h" /* be careful what you use from this */ + +/* This file serves as the interface between the common kernel modesetting code and the device dependent implementation. */ + +/* + * Get private functions. + */ + +struct nv50_kms_priv *nv50_get_kms_priv(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + return dev_priv->kms_priv; +} + +/* + * Allocation functions. + */ + +static void *nv50_kms_alloc_crtc(struct drm_device *dev) +{ + struct nv50_kms_priv *kms_priv = nv50_get_kms_priv(dev); + struct nv50_kms_crtc *crtc = kzalloc(sizeof(struct nv50_kms_crtc), GFP_KERNEL); + + list_add_tail(&crtc->head, &kms_priv->crtcs); + + return &(crtc->priv); +} + +static void *nv50_kms_alloc_output(struct drm_device *dev) +{ + struct nv50_kms_priv *kms_priv = nv50_get_kms_priv(dev); + struct nv50_kms_encoder *encoder = kzalloc(sizeof(struct nv50_kms_encoder), GFP_KERNEL); + + list_add_tail(&encoder->head, &kms_priv->encoders); + + return &(encoder->priv); +} + +static void *nv50_kms_alloc_connector(struct drm_device *dev) +{ + struct nv50_kms_priv *kms_priv = nv50_get_kms_priv(dev); + struct nv50_kms_connector *connector = kzalloc(sizeof(struct nv50_kms_connector), GFP_KERNEL); + + list_add_tail(&connector->head, &kms_priv->connectors); + + return &(connector->priv); +} + +static void nv50_kms_free_crtc(void *crtc) +{ + struct nv50_kms_crtc *kms_crtc = from_nv50_crtc(crtc); + + list_del(&kms_crtc->head); + + kfree(kms_crtc); +} + +static void nv50_kms_free_output(void *output) +{ + struct nv50_kms_encoder *kms_encoder = from_nv50_output(output); + + list_del(&kms_encoder->head); + + kfree(kms_encoder); +} + +static void nv50_kms_free_connector(void *connector) +{ + struct nv50_kms_connector *kms_connector = from_nv50_connector(connector); + + list_del(&kms_connector->head); + + kfree(kms_connector); +} + +/* + * Mode conversion functions. + */ + +static struct nouveau_hw_mode *nv50_kms_to_hw_mode(struct drm_display_mode *mode) +{ + struct nouveau_hw_mode *hw_mode = kzalloc(sizeof(struct nouveau_hw_mode), GFP_KERNEL); + + /* create hw values. */ + hw_mode->clock = mode->clock; + hw_mode->flags = hw_mode->flags; + + hw_mode->hdisplay = mode->hdisplay; + hw_mode->hsync_start = mode->hsync_start; + hw_mode->hsync_end = mode->hsync_end; + hw_mode->htotal = mode->htotal; + + hw_mode->hblank_start = mode->hdisplay + 1; + hw_mode->hblank_end = mode->htotal; + + hw_mode->vdisplay = mode->vdisplay; + hw_mode->vsync_start = mode->vsync_start; + hw_mode->vsync_end = mode->vsync_end; + hw_mode->vtotal = mode->vtotal; + + hw_mode->vblank_start = mode->vdisplay + 1; + hw_mode->vblank_end = mode->vtotal; + + return hw_mode; +} + +/* + * State mirroring functions. + */ + +static void nv50_kms_mirror_routing(struct drm_device *dev) +{ + struct nv50_display *display = nv50_get_display(dev); + struct nv50_crtc *crtc = NULL; + struct nv50_output *output = NULL; + struct nv50_connector *connector = NULL; + struct drm_connector *drm_connector = NULL; + + /* Wipe all previous connections. */ + list_for_each_entry(connector, &display->connectors, head) { + connector->output = NULL; + } + + list_for_each_entry(output, &display->outputs, head) { + output->crtc = NULL; + } + + list_for_each_entry(drm_connector, &dev->mode_config.connector_list, head) { + if (drm_connector->encoder) { + output = to_nv50_output(drm_connector->encoder); + connector = to_nv50_connector(drm_connector); + + /* hook up output to connector. */ + connector->output = output; + + if (drm_connector->encoder->crtc) { + crtc = to_nv50_crtc(drm_connector->encoder->crtc); + + /* hook up output to crtc. */ + output->crtc = crtc; + } + } + } +} + +/* + * FB functions. + */ + +static void nv50_kms_framebuffer_destroy(struct drm_framebuffer *drm_framebuffer) +{ + drm_framebuffer_cleanup(drm_framebuffer); + + kfree(drm_framebuffer); +} + +static const struct drm_framebuffer_funcs nv50_kms_fb_funcs = { + .destroy = nv50_kms_framebuffer_destroy, +}; + +/* + * Mode config functions. + */ + +static struct drm_framebuffer *nv50_kms_framebuffer_create(struct drm_device *dev, + struct drm_file *file_priv, struct drm_mode_fb_cmd *mode_cmd) +{ + struct drm_framebuffer *drm_framebuffer = kzalloc(sizeof(struct drm_framebuffer), GFP_KERNEL); + if (!drm_framebuffer) + return NULL; + + drm_framebuffer_init(dev, drm_framebuffer, &nv50_kms_fb_funcs); + drm_helper_mode_fill_fb_struct(drm_framebuffer, mode_cmd); + + return drm_framebuffer; +} + +static int nv50_kms_fb_changed(struct drm_device *dev) +{ + return 0; /* not needed until nouveaufb? */ +} + +static const struct drm_mode_config_funcs nv50_kms_mode_funcs = { + .resize_fb = NULL, + .fb_create = nv50_kms_framebuffer_create, + .fb_changed = nv50_kms_fb_changed, +}; + +/* + * CRTC functions. + */ + +static int nv50_kms_crtc_cursor_set(struct drm_crtc *drm_crtc, uint32_t buffer_handle, + uint32_t width, uint32_t height) +{ + struct nv50_crtc *crtc = to_nv50_crtc(drm_crtc); + struct nv50_display *display = nv50_get_display(crtc->dev); + int rval; + + if (width != 64 || height != 64) + return -EINVAL; + + rval = crtc->cursor->set_bo(crtc, (drm_handle_t) buffer_handle); + + if (rval != 0) + return rval; + + /* in case this triggers any other cursor changes */ + display->update(display); + + return 0; +} + +static int nv50_kms_crtc_cursor_move(struct drm_crtc *drm_crtc, int x, int y) +{ + struct nv50_crtc *crtc = to_nv50_crtc(drm_crtc); + + return crtc->cursor->set_pos(crtc, x, y); +} + +void nv50_kms_crtc_gamma_set(struct drm_crtc *drm_crtc, u16 *r, u16 *g, u16 *b, + uint32_t size) +{ + struct nv50_crtc *crtc = to_nv50_crtc(drm_crtc); + + if (size != 256) + return; + + crtc->lut->set(crtc, (uint16_t *)r, (uint16_t *)g, (uint16_t *)b); +} + +int nv50_kms_crtc_set_config(struct drm_mode_set *set) +{ + int rval = 0, i; + uint32_t crtc_mask = 0; + struct drm_device *dev = NULL; + struct drm_nouveau_private *dev_priv = NULL; + struct nv50_display *display = NULL; + struct drm_connector *drm_connector = NULL; + struct drm_encoder *drm_encoder = NULL; + struct drm_crtc *drm_crtc = NULL; + + struct nv50_crtc *crtc = NULL; + struct nv50_output *output = NULL; + struct nv50_connector *connector = NULL; + struct nouveau_hw_mode *hw_mode = NULL; + struct nv50_fb_info fb_info; + + NV50_DEBUG("\n"); + + /* + * Initial approach is very simple, always set a mode. + * Always bail out completely if something is wrong. + * Later this could be extended to be more smart. + */ + + /* Sanity checking */ + if (!set) { + NV50_DEBUG("Sanity check failed\n"); + goto out; + } + + if (!set->crtc || !set->fb || !set->mode || !set->connectors) { + NV50_DEBUG("Sanity check failed\n"); + goto out; + } + + /* Basic variable setting */ + dev = set->crtc->dev; + dev_priv = dev->dev_private; + display = nv50_get_display(dev); + crtc = to_nv50_crtc(set->crtc); + + /* Mode validation */ + hw_mode = nv50_kms_to_hw_mode(set->mode); + + rval = crtc->validate_mode(crtc, hw_mode); + + if (rval != MODE_OK) { + NV50_DEBUG("Mode not ok\n"); + goto out; + } + + for (i = 0; i < set->num_connectors; i++) { + drm_connector = set->connectors[i]; + if (!drm_connector) { + NV50_DEBUG("No connector\n"); + goto out; + } + connector = to_nv50_connector(drm_connector); + + output = connector->to_output(connector, connector->digital); + if (!output) { + NV50_DEBUG("No output\n"); + goto out; + } + + rval = output->validate_mode(output, hw_mode); + if (rval != MODE_OK) { + NV50_DEBUG("Mode not ok\n"); + goto out; + } + } + + /* Validation done, move on to cleaning of existing structures. */ + + /* find encoders that use this crtc. */ + list_for_each_entry(drm_encoder, &dev->mode_config.encoder_list, head) { + if (drm_encoder->crtc == set->crtc) { + /* find the connector that goes with it */ + list_for_each_entry(drm_connector, &dev->mode_config.connector_list, head) { + if (drm_connector->encoder == drm_encoder) { + drm_connector->encoder = NULL; + break; + } + } + drm_encoder->crtc = NULL; + } + } + + /* now find if our desired encoders or connectors are in use already. */ + for (i = 0; i < set->num_connectors; i++) { + drm_connector = set->connectors[i]; + if (!drm_connector) { + NV50_DEBUG("No connector\n"); + goto out; + } + + if (!drm_connector->encoder) + continue; + + drm_encoder = drm_connector->encoder; + drm_connector->encoder = NULL; + + if (!drm_encoder->crtc) + continue; + + drm_crtc = drm_encoder->crtc; + drm_encoder->crtc = NULL; + + crtc = to_nv50_crtc(drm_crtc); + crtc->active = false; + drm_crtc->enabled = false; + } + + /* set framebuffer */ + set->crtc->fb = set->fb; + + /* Time to wire up the public encoder, the private one will be handled later. */ + for (i = 0; i < set->num_connectors; i++) { + drm_connector = set->connectors[i]; + if (!drm_connector) { + NV50_DEBUG("No connector\n"); + goto out; + } + + output = connector->to_output(connector, connector->digital); + if (!output) { + NV50_DEBUG("No output\n"); + goto out; + } + + /* find the encoder public structure that matches out output structure. */ + drm_encoder = to_nv50_kms_encoder(output); + + if (!drm_encoder) { + NV50_DEBUG("No encoder\n"); + goto out; + } + + + drm_encoder->crtc = set->crtc; + drm_connector->encoder = drm_encoder; + } + + /* mirror everything to the private structs */ + nv50_kms_mirror_routing(dev); + + /* set private framebuffer */ + crtc = to_nv50_crtc(set->crtc); + fb_info.block = find_block_by_handle(dev_priv->fb_heap, set->fb->mm_handle); + fb_info.width = set->fb->width; + fb_info.height = set->fb->height; + fb_info.depth = set->fb->depth; + fb_info.bpp = set->fb->bits_per_pixel; + fb_info.x = set->x; + fb_info.y = set->y; + + rval = crtc->fb->bind(crtc, &fb_info); + if (rval != 0) { + NV50_DEBUG("fb_bind failed\n"); + goto out; + } + + if (!crtc->cursor->enabled) { + rval = crtc->cursor->enable(crtc); + if (rval != 0) { + NV50_DEBUG("cursor_enable failed\n"); + goto out; + } + } + + /* modeset time, finally */ + + /* disconnect unused outputs */ + list_for_each_entry(output, &display->outputs, head) { + if (output->crtc) + crtc_mask |= 1 << output->crtc->index; + else + output->execute_mode(output, TRUE); + } + + rval = crtc->set_mode(crtc, hw_mode); + if (rval != 0) { + NV50_DEBUG("crtc mode set failed\n"); + goto out; + } + + /* find native mode. */ + list_for_each_entry(output, &display->outputs, head) { + if (output->crtc != crtc) + continue; + + *crtc->native_mode = *output->native_mode; + list_for_each_entry(connector, &display->connectors, head) { + if (connector->output != output) + continue; + + crtc->scaling_mode = connector->scaling_mode; + break; + } + + if (crtc->scaling_mode == SCALE_PANEL) + crtc->use_native_mode = false; + else + crtc->use_native_mode = true; + + break; /* no use in finding more than one mode */ + } + + rval = crtc->execute_mode(crtc); + if (rval != 0) { + NV50_DEBUG("crtc execute mode failed\n"); + goto out; + } + + list_for_each_entry(output, &display->outputs, head) { + if (output->crtc != crtc) + continue; + + rval = output->execute_mode(output, FALSE); + if (rval != 0) { + NV50_DEBUG("output execute mode failed\n"); + goto out; + } + } + + rval = crtc->set_scale(crtc); + if (rval != 0) { + NV50_DEBUG("crtc set scale failed\n"); + goto out; + } + + /* next line changes crtc, so putting it here is important */ + display->last_crtc = crtc->index; + + /* blank any unused crtcs */ + list_for_each_entry(crtc, &display->crtcs, head) { + if (!(crtc_mask & (1 << crtc->index))) + crtc->blank(crtc, TRUE); + } + + display->update(display); + + kfree(hw_mode); + + return 0; + +out: + display->update(display); + + kfree(hw_mode); + + if (rval != 0) + return rval; + else + return -EINVAL; +} + +static void nv50_kms_crtc_destroy(struct drm_crtc *drm_crtc) +{ + struct nv50_crtc *crtc = to_nv50_crtc(drm_crtc); + + drm_crtc_cleanup(drm_crtc); + + /* this will even destroy the public structure. */ + crtc->destroy(crtc); +} + +static const struct drm_crtc_funcs nv50_kms_crtc_funcs = { + .save = NULL, + .restore = NULL, + .cursor_set = nv50_kms_crtc_cursor_set, + .cursor_move = nv50_kms_crtc_cursor_move, + .gamma_set = nv50_kms_crtc_gamma_set, + .set_config = nv50_kms_crtc_set_config, + .destroy = nv50_kms_crtc_destroy, +}; + +static int nv50_kms_crtcs_init(struct drm_device *dev) +{ + struct nv50_display *display = nv50_get_display(dev); + struct nv50_crtc *crtc = NULL; + + /* + * This may look a bit confusing, but: + * The internal structure is already allocated and so is the public one. + * Just a matter of getting to the memory and register it. + */ + list_for_each_entry(crtc, &display->crtcs, head) { + struct drm_crtc *drm_crtc = to_nv50_kms_crtc(crtc); + + drm_crtc_init(dev, drm_crtc, &nv50_kms_crtc_funcs); + } + + return 0; +} + +/* + * Encoder functions + */ + +static void nv50_kms_encoder_destroy(struct drm_encoder *drm_encoder) +{ + struct nv50_output *output = to_nv50_output(drm_encoder); + + drm_encoder_cleanup(drm_encoder); + + /* this will even destroy the public structure. */ + output->destroy(output); +} + +static const struct drm_encoder_funcs nv50_kms_encoder_funcs = { + .destroy = nv50_kms_encoder_destroy, +}; + +static int nv50_kms_encoders_init(struct drm_device *dev) +{ + struct nv50_display *display = nv50_get_display(dev); + struct nv50_output *output = NULL; + + list_for_each_entry(output, &display->outputs, head) { + struct drm_encoder *drm_encoder = to_nv50_kms_encoder(output); + uint32_t type = DRM_MODE_ENCODER_NONE; + + switch (output->type) { + case OUTPUT_DAC: + type = DRM_MODE_ENCODER_DAC; + break; + case OUTPUT_TMDS: + type = DRM_MODE_ENCODER_TMDS; + break; + case OUTPUT_LVDS: + type = DRM_MODE_ENCODER_LVDS; + break; + case OUTPUT_TV: + type = DRM_MODE_ENCODER_TVDAC; + break; + default: + type = DRM_MODE_ENCODER_NONE; + break; + } + + if (type == DRM_MODE_ENCODER_NONE) { + DRM_ERROR("DRM_MODE_ENCODER_NONE encountered\n"); + continue; + } + + drm_encoder_init(dev, drm_encoder, &nv50_kms_encoder_funcs, type); + + /* I've never seen possible crtc's restricted. */ + drm_encoder->possible_crtcs = 3; + drm_encoder->possible_clones = 0; + } + + return 0; +} + +/* + * Connector functions + */ + +void nv50_kms_connector_detect_all(struct drm_device *dev) +{ + struct drm_connector *drm_connector = NULL; + enum drm_connector_status old, new; + bool notify = false; + + list_for_each_entry(drm_connector, &dev->mode_config.connector_list, head) { + old = drm_connector->status; + new = drm_connector->funcs->detect(drm_connector); + + if (new != old) { + notify = true; + drm_connector->funcs->fill_modes(drm_connector, 0, 0); + } + } + + /* I think this is the hook that notifies of changes. */ + if (notify) + dev->mode_config.funcs->fb_changed(dev); +} + +static enum drm_connector_status nv50_kms_connector_detect(struct drm_connector *drm_connector) +{ + struct nv50_connector *connector = to_nv50_connector(drm_connector); + bool connected; + + connected = connector->detect(connector); + + if (connected) + drm_connector->status = connector_status_connected; + else + drm_connector->status = connector_status_disconnected; + + return drm_connector->status; +} + +static void nv50_kms_connector_destroy(struct drm_connector *drm_connector) +{ + struct nv50_connector *connector = to_nv50_connector(drm_connector); + + drm_sysfs_connector_remove(drm_connector); + drm_connector_cleanup(drm_connector); + + /* this will even destroy the public structure. */ + connector->destroy(connector); +} + +/* + * Detailed mode info for a standard 640x480@60Hz monitor + */ +static struct drm_display_mode std_mode[] = { + /*{ DRM_MODE("640x480", DRM_MODE_TYPE_DEFAULT, 25200, 640, 656, + 752, 800, 0, 480, 490, 492, 525, 0, + V_NHSYNC | V_NVSYNC) },*/ /* 640x480@60Hz */ + { DRM_MODE("1280x1024", DRM_MODE_TYPE_DEFAULT, 135000, 1280, 1296, + 1440, 1688, 0, 1024, 1025, 1028, 1066, 0, + V_PHSYNC | V_PVSYNC) }, /* 1280x1024@75Hz */ +}; + +static void nv50_kms_connector_fill_modes(struct drm_connector *drm_connector, uint32_t maxX, uint32_t maxY) +{ + struct nv50_connector *connector = to_nv50_connector(drm_connector); + int ret = 0; + bool connected; + struct drm_display_mode *mode, *t; + struct edid *edid = NULL; + + DRM_DEBUG("%s\n", drm_get_connector_name(drm_connector)); + /* set all modes to the unverified state */ + list_for_each_entry_safe(mode, t, &drm_connector->modes, head) + mode->status = MODE_UNVERIFIED; + + connected = connector->detect(connector); + + if (connected) + drm_connector->status = connector_status_connected; + else + drm_connector->status = connector_status_disconnected; + + if (!connected) { + DRM_DEBUG("%s is disconnected\n", drm_get_connector_name(drm_connector)); + /* TODO set EDID to NULL */ + return; + } + + /* Not all connnectors have an i2c channel. */ + if (connector->i2c_chan) + edid = (struct edid *) drm_do_probe_ddc_edid(&connector->i2c_chan->adapter); + + if (edid) { + drm_mode_connector_update_edid_property(drm_connector, edid); + ret = drm_add_edid_modes(drm_connector, edid); + connector->digital = edid->digital; /* cache */ + } + + if (ret) /* number of modes > 1 */ + drm_mode_connector_list_update(drm_connector); + + if (maxX && maxY) + drm_mode_validate_size(drm_connector->dev, &drm_connector->modes, maxX, maxY, 0); + + list_for_each_entry_safe(mode, t, &drm_connector->modes, head) { + if (mode->status == MODE_OK) { + struct nouveau_hw_mode *hw_mode = nv50_kms_to_hw_mode(mode); + struct nv50_output *output = connector->to_output(connector, connector->digital); + + mode->status = output->validate_mode(output, hw_mode); + /* find native mode, TODO: also check if we actually found one */ + if (mode->status == MODE_OK) { + if (mode->type & DRM_MODE_TYPE_PREFERRED) + *output->native_mode = *hw_mode; + } + kfree(hw_mode); + } + } + + /* revalidate now that we have native mode */ + list_for_each_entry_safe(mode, t, &drm_connector->modes, head) { + if (mode->status == MODE_OK) { + struct nouveau_hw_mode *hw_mode = nv50_kms_to_hw_mode(mode); + struct nv50_output *output = connector->to_output(connector, connector->digital); + + mode->status = output->validate_mode(output, hw_mode); + kfree(hw_mode); + } + } + + drm_mode_prune_invalid(drm_connector->dev, &drm_connector->modes, TRUE); + + if (list_empty(&drm_connector->modes)) { + struct drm_display_mode *stdmode; + struct nouveau_hw_mode *hw_mode; + struct nv50_output *output; + + DRM_DEBUG("No valid modes on %s\n", drm_get_connector_name(drm_connector)); + + /* Should we do this here ??? + * When no valid EDID modes are available we end up + * here and bailed in the past, now we add a standard + * 640x480@60Hz mode and carry on. + */ + stdmode = drm_mode_duplicate(drm_connector->dev, &std_mode[0]); + drm_mode_probed_add(drm_connector, stdmode); + drm_mode_list_concat(&drm_connector->probed_modes, + &drm_connector->modes); + + /* also add it as native mode */ + hw_mode = nv50_kms_to_hw_mode(mode); + output = connector->to_output(connector, connector->digital); + + if (hw_mode) + *output->native_mode = *hw_mode; + + DRM_DEBUG("Adding standard 640x480 @ 60Hz to %s\n", + drm_get_connector_name(drm_connector)); + } + + drm_mode_sort(&drm_connector->modes); + + DRM_DEBUG("Probed modes for %s\n", drm_get_connector_name(drm_connector)); + + list_for_each_entry_safe(mode, t, &drm_connector->modes, head) { + mode->vrefresh = drm_mode_vrefresh(mode); + + /* is this needed, as it's unused by the driver? */ + drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V); + drm_mode_debug_printmodeline(mode); + } +} + +static const struct drm_connector_funcs nv50_kms_connector_funcs = { + .save = NULL, + .restore = NULL, + .detect = nv50_kms_connector_detect, + .destroy = nv50_kms_connector_destroy, + .fill_modes = nv50_kms_connector_fill_modes, +}; + +static int nv50_kms_connectors_init(struct drm_device *dev) +{ + struct nv50_display *display = nv50_get_display(dev); + struct nv50_connector *connector = NULL; + int i; + + list_for_each_entry(connector, &display->connectors, head) { + struct drm_connector *drm_connector = to_nv50_kms_connector(connector); + uint32_t type = DRM_MODE_CONNECTOR_Unknown; + + switch (connector->type) { + case CONNECTOR_VGA: + type = DRM_MODE_CONNECTOR_VGA; + break; + case CONNECTOR_DVI_D: + type = DRM_MODE_CONNECTOR_DVID; + break; + case CONNECTOR_DVI_I: + type = DRM_MODE_CONNECTOR_DVII; + break; + case CONNECTOR_LVDS: + type = DRM_MODE_CONNECTOR_LVDS; + break; + case CONNECTOR_TV: + type = DRM_MODE_CONNECTOR_SVIDEO; + break; + default: + type = DRM_MODE_CONNECTOR_Unknown; + break; + } + + if (type == DRM_MODE_CONNECTOR_Unknown) { + DRM_ERROR("DRM_MODE_CONNECTOR_Unknown encountered\n"); + continue; + } + + /* It should be allowed sometimes, but let's be safe for the moment. */ + drm_connector->interlace_allowed = false; + drm_connector->doublescan_allowed = false; + + drm_connector_init(dev, drm_connector, &nv50_kms_connector_funcs, type); + + /* attach encoders, possibilities are analog + digital */ + for (i = 0; i < 2; i++) { + struct drm_encoder *drm_encoder = NULL; + struct nv50_output *output = connector->to_output(connector, i); + if (!output) + continue; + + drm_encoder = to_nv50_kms_encoder(output); + if (!drm_encoder) { + DRM_ERROR("No struct drm_connector to match struct nv50_output\n"); + continue; + } + + drm_mode_connector_attach_encoder(drm_connector, drm_encoder); + } + + drm_sysfs_connector_add(drm_connector); + } + + return 0; +} + +/* + * Main functions + */ + +int nv50_kms_init(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nv50_kms_priv *kms_priv = kzalloc(sizeof(struct nv50_kms_priv), GFP_KERNEL); + struct nv50_display *display = NULL; + int rval = 0; + + dev_priv->kms_priv = kms_priv; + + /* function pointers */ + /* an allocation interface that deals with the outside world, without polluting the core. */ + dev_priv->alloc_crtc = nv50_kms_alloc_crtc; + dev_priv->alloc_output = nv50_kms_alloc_output; + dev_priv->alloc_connector = nv50_kms_alloc_connector; + + dev_priv->free_crtc = nv50_kms_free_crtc; + dev_priv->free_output = nv50_kms_free_output; + dev_priv->free_connector = nv50_kms_free_connector; + + /* bios is needed for tables. */ + rval = nouveau_parse_bios(dev); + if (rval != 0) + goto out; + + /* init basic kernel modesetting */ + drm_mode_config_init(dev); + + dev->mode_config.min_width = 0; + dev->mode_config.min_height = 0; + + dev->mode_config.funcs = (void *)&nv50_kms_mode_funcs; + + dev->mode_config.max_width = 8192; + dev->mode_config.max_height = 8192; + + dev->mode_config.fb_base = dev_priv->fb_phys; + + /* init kms lists */ + INIT_LIST_HEAD(&kms_priv->crtcs); + INIT_LIST_HEAD(&kms_priv->encoders); + INIT_LIST_HEAD(&kms_priv->connectors); + + /* init the internal core, must be done first. */ + rval = nv50_display_create(dev); + if (rval != 0) + goto out; + + display = nv50_get_display(dev); + if (!display) { + rval = -EINVAL; + goto out; + } + + /* pre-init now */ + rval = display->pre_init(display); + if (rval != 0) + goto out; + + /* init external layer */ + rval = nv50_kms_crtcs_init(dev); + if (rval != 0) + goto out; + + rval = nv50_kms_encoders_init(dev); + if (rval != 0) + goto out; + + rval = nv50_kms_connectors_init(dev); + if (rval != 0) + goto out; + + /* init now, this'll kill the textmode */ + rval = display->init(display); + if (rval != 0) + goto out; + + /* process cmdbuffer */ + display->update(display); + + return 0; + +out: + kfree(kms_priv); + dev_priv->kms_priv = NULL; + + return rval; +} + +int nv50_kms_destroy(struct drm_device *dev) +{ + drm_mode_config_cleanup(dev); + + return 0; +} + diff --git a/linux-core/nv50_kms_wrapper.h b/linux-core/nv50_kms_wrapper.h new file mode 100644 index 00000000..3847d510 --- /dev/null +++ b/linux-core/nv50_kms_wrapper.h @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2008 Maarten Maathuis. + * All Rights Reserved. + * + * 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 (including the + * next paragraph) 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 OWNER(S) AND/OR ITS SUPPLIERS 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. + * + */ + +#ifndef __NV50_KMS_WRAPPER_H__ +#define __NV50_KMS_WRAPPER_H__ + +#include "drmP.h" +#include "drm.h" + +#include "nv50_display.h" +#include "nv50_crtc.h" +#include "nv50_cursor.h" +#include "nv50_lut.h" +#include "nv50_fb.h" +#include "nv50_output.h" +#include "nv50_connector.h" + +#include "drm_crtc.h" +#include "drm_edid.h" + +/* Link internal modesetting structure to interface. */ + +struct nv50_kms_crtc { + struct list_head head; + + struct nv50_crtc priv; + struct drm_crtc pub; +}; + +struct nv50_kms_encoder { + struct list_head head; + + struct nv50_output priv; + struct drm_encoder pub; +}; + +struct nv50_kms_connector { + struct list_head head; + + struct nv50_connector priv; + struct drm_connector pub; +}; + +struct nv50_kms_priv { + struct list_head crtcs; + struct list_head encoders; + struct list_head connectors; +}; + +/* Get private functions. */ +#define from_nv50_kms_crtc(x) container_of(x, struct nv50_kms_crtc, pub) +#define from_nv50_crtc(x) container_of(x, struct nv50_kms_crtc, priv) +#define from_nv50_kms_encoder(x) container_of(x, struct nv50_kms_encoder, pub) +#define from_nv50_output(x) container_of(x, struct nv50_kms_encoder, priv) +#define from_nv50_kms_connector(x) container_of(x, struct nv50_kms_connector, pub) +#define from_nv50_connector(x) container_of(x, struct nv50_kms_connector, priv) + +#define to_nv50_crtc(x) (&(from_nv50_kms_crtc(x)->priv)) +#define to_nv50_kms_crtc(x) (&(from_nv50_crtc(x)->pub)) +#define to_nv50_output(x) (&(from_nv50_kms_encoder(x)->priv)) +#define to_nv50_kms_encoder(x) (&(from_nv50_output(x)->pub)) +#define to_nv50_connector(x) (&(from_nv50_kms_connector(x)->priv)) +#define to_nv50_kms_connector(x) (&(from_nv50_connector(x)->pub)) + +struct nv50_kms_priv *nv50_get_kms_priv(struct drm_device *dev); +void nv50_kms_connector_detect_all(struct drm_device *dev); + +int nv50_kms_init(struct drm_device *dev); +int nv50_kms_destroy(struct drm_device *dev); + +#endif /* __NV50_KMS_WRAPPER_H__ */ diff --git a/linux-core/nv50_lut.c b/linux-core/nv50_lut.c new file mode 100644 index 00000000..570900ba --- /dev/null +++ b/linux-core/nv50_lut.c @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2008 Maarten Maathuis. + * All Rights Reserved. + * + * 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 (including the + * next paragraph) 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 OWNER(S) AND/OR ITS SUPPLIERS 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. + * + */ + +#include "nv50_lut.h" +#include "nv50_fb.h" +#include "nv50_crtc.h" +#include "nv50_display.h" + +static int nv50_lut_alloc(struct nv50_crtc *crtc) +{ + struct mem_block *block; + struct drm_file *file_priv = kzalloc(sizeof(struct drm_file), GFP_KERNEL); + uint32_t flags = NOUVEAU_MEM_INTERNAL | NOUVEAU_MEM_FB | NOUVEAU_MEM_MAPPED; + + NV50_DEBUG("\n"); + + /* Any file_priv should do as it's pointer is used as identification. */ + block = nouveau_mem_alloc(crtc->dev, 0, 4096, flags, file_priv); + + if (!block) + return -ENOMEM; + + crtc->lut->block = block; + + return 0; +} + +static int nv50_lut_free(struct nv50_crtc *crtc) +{ + struct drm_file *file_priv = crtc->lut->block->file_priv; + + NV50_DEBUG("\n"); + + nouveau_mem_free(crtc->dev, crtc->lut->block); + + kfree(file_priv); + + return 0; +} + +#define NV50_LUT_INDEX(val, w) ((val << (8 - w)) | (val >> ((w << 1) - 8))) +static int nv50_lut_set(struct nv50_crtc *crtc, uint16_t *red, uint16_t *green, uint16_t *blue) +{ + uint32_t index = 0, i; + struct drm_nouveau_private *dev_priv = crtc->dev->dev_private; + void __iomem *lut = NULL; + + NV50_DEBUG("\n"); + + if (!crtc->lut || !crtc->lut->block) { + DRM_ERROR("Something wrong with the LUT\n"); + return -EINVAL; + } + + /* 16 bits, red, green, blue, unused, total of 64 bits per index */ + /* maybe switch to ioremap_wc once it becomes available. */ + lut = ioremap(dev_priv->fb_phys + crtc->lut->block->start, crtc->lut->block->size); + if (!lut) { + DRM_ERROR("ioremap failed on LUT\n"); + return -EINVAL; + } + + /* 10 bits lut, with 14 bits values. */ + switch (crtc->fb->depth) { + case 15: + /* R5G5B5 */ + for (i = 0; i < 32; i++) { + index = NV50_LUT_INDEX(i, 5); + writew(red[i] >> 2, lut + 8*index + 0); + writew(green[i] >> 2, lut + 8*index + 2); + writew(blue[i] >> 2, lut + 8*index + 4); + } + break; + case 16: + /* R5G6B5 */ + for (i = 0; i < 32; i++) { + index = NV50_LUT_INDEX(i, 5); + writew(red[i] >> 2, lut + 8*index + 0); + writew(blue[i] >> 2, lut + 8*index + 4); + } + + /* Green has an extra bit. */ + for (i = 0; i < 64; i++) { + index = NV50_LUT_INDEX(i, 6); + writew(green[i] >> 2, lut + 8*index + 2); + } + break; + default: + /* R8G8B8 */ + for (i = 0; i < 256; i++) { + writew(red[i] >> 2, lut + 8*i + 0); + writew(green[i] >> 2, lut + 8*i + 2); + writew(blue[i] >> 2, lut + 8*i + 4); + } + break; + } + + crtc->lut->depth = crtc->fb->depth; + + /* Cleaning time. */ + iounmap(lut); + + return 0; +} + +int nv50_lut_create(struct nv50_crtc *crtc) +{ + int rval = 0; + + NV50_DEBUG("\n"); + + if (!crtc) + return -EINVAL; + + crtc->lut = kzalloc(sizeof(struct nv50_lut), GFP_KERNEL); + + rval = nv50_lut_alloc(crtc); + if (rval != 0) + return rval; + + /* lut will be inited when fb is bound */ + crtc->lut->depth = 0; + + /* function pointers */ + crtc->lut->set = nv50_lut_set; + + return 0; +} + +int nv50_lut_destroy(struct nv50_crtc *crtc) +{ + int rval = 0; + + NV50_DEBUG("\n"); + + if (!crtc) + return -EINVAL; + + rval = nv50_lut_free(crtc); + + kfree(crtc->lut); + crtc->lut = NULL; + + if (rval != 0) + return rval; + + return 0; +} diff --git a/linux-core/nv50_lut.h b/linux-core/nv50_lut.h new file mode 100644 index 00000000..06704830 --- /dev/null +++ b/linux-core/nv50_lut.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2008 Maarten Maathuis. + * All Rights Reserved. + * + * 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 (including the + * next paragraph) 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 OWNER(S) AND/OR ITS SUPPLIERS 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. + * + */ + +#ifndef __NV50_LUT_H__ +#define __NV50_LUT_H__ + +#include "nv50_display.h" + +struct nv50_crtc; + +struct nv50_lut { + struct mem_block *block; + + int depth; /* check against fb to see if it needs to be reuploaded */ + + int (*set) (struct nv50_crtc *crtc, uint16_t *red, uint16_t *green, uint16_t *blue); +}; + +int nv50_lut_create(struct nv50_crtc *crtc); +int nv50_lut_destroy(struct nv50_crtc *crtc); + +#endif /* __NV50_LUT_H__ */ diff --git a/linux-core/nv50_output.c b/linux-core/nv50_output.c new file mode 100644 index 00000000..de0017b9 --- /dev/null +++ b/linux-core/nv50_output.c @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2008 Maarten Maathuis. + * All Rights Reserved. + * + * 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 (including the + * next paragraph) 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 OWNER(S) AND/OR ITS SUPPLIERS 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. + * + */ + +#include "nv50_output.h" + +int nv50_output_or_offset(struct nv50_output *output) +{ + struct drm_nouveau_private *dev_priv = output->dev->dev_private; + return ffs(dev_priv->dcb_table.entry[output->dcb_entry].or) - 1; +} diff --git a/linux-core/nv50_output.h b/linux-core/nv50_output.h new file mode 100644 index 00000000..bdee2826 --- /dev/null +++ b/linux-core/nv50_output.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2008 Maarten Maathuis. + * All Rights Reserved. + * + * 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 (including the + * next paragraph) 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 OWNER(S) AND/OR ITS SUPPLIERS 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. + * + */ + +#ifndef __NV50_OUTPUT_H__ +#define __NV50_OUTPUT_H__ + +#include "nv50_crtc.h" + +#define OUTPUT_UNKNOWN 0 +#define OUTPUT_DAC 1 +#define OUTPUT_TMDS 2 +#define OUTPUT_LVDS 3 +#define OUTPUT_TV 4 + +struct nv50_output { + struct list_head head; + + struct drm_device *dev; + int bus; + int dcb_entry; + int type; + + struct nv50_crtc *crtc; + struct nouveau_hw_mode *native_mode; + + int (*validate_mode) (struct nv50_output *output, struct nouveau_hw_mode *mode); + int (*execute_mode) (struct nv50_output *output, bool disconnect); + int (*set_clock_mode) (struct nv50_output *output); + bool (*detect) (struct nv50_output *output); + int (*destroy) (struct nv50_output *output); +}; + +int nv50_output_or_offset(struct nv50_output *output); +int nv50_sor_create(struct drm_device *dev, int dcb_entry); +int nv50_dac_create(struct drm_device *dev, int dcb_entry); + +#endif /* __NV50_OUTPUT_H__ */ diff --git a/linux-core/nv50_sor.c b/linux-core/nv50_sor.c new file mode 100644 index 00000000..430c1e83 --- /dev/null +++ b/linux-core/nv50_sor.c @@ -0,0 +1,204 @@ +/* + * Copyright (C) 2008 Maarten Maathuis. + * All Rights Reserved. + * + * 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 (including the + * next paragraph) 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 OWNER(S) AND/OR ITS SUPPLIERS 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. + * + */ + +#include "nv50_output.h" + +static int nv50_sor_validate_mode(struct nv50_output *output, struct nouveau_hw_mode *mode) +{ + NV50_DEBUG("\n"); + + if (mode->clock > 165000) /* no dual link until we figure it out completely */ + return MODE_CLOCK_HIGH; + + if (mode->clock < 25000) + return MODE_CLOCK_LOW; + + if (output->native_mode->hdisplay > 0 && output->native_mode->vdisplay > 0) { + if (mode->hdisplay > output->native_mode->hdisplay || mode->vdisplay > output->native_mode->vdisplay) + return MODE_PANEL; + } + + return MODE_OK; +} + +static int nv50_sor_execute_mode(struct nv50_output *output, bool disconnect) +{ + struct drm_nouveau_private *dev_priv = output->dev->dev_private; + struct nv50_crtc *crtc = output->crtc; + struct nouveau_hw_mode *desired_mode = NULL; + + uint32_t offset = nv50_output_or_offset(output) * 0x40; + + uint32_t mode_ctl = NV50_SOR_MODE_CTRL_OFF; + + NV50_DEBUG("or %d\n", nv50_output_or_offset(output)); + + if (disconnect) { + NV50_DEBUG("Disconnecting SOR\n"); + OUT_MODE(NV50_SOR0_MODE_CTRL + offset, mode_ctl); + return 0; + } + + desired_mode = (crtc->use_native_mode ? crtc->native_mode : crtc->mode); + + if (output->type == OUTPUT_LVDS) { + mode_ctl |= NV50_SOR_MODE_CTRL_LVDS; + } else { + mode_ctl |= NV50_SOR_MODE_CTRL_TMDS; + if (desired_mode->clock > 165000) + mode_ctl |= NV50_SOR_MODE_CTRL_TMDS_DUAL_LINK; + } + + if (crtc->index == 1) + mode_ctl |= NV50_SOR_MODE_CTRL_CRTC1; + else + mode_ctl |= NV50_SOR_MODE_CTRL_CRTC0; + + if (desired_mode->flags & V_NHSYNC) + mode_ctl |= NV50_SOR_MODE_CTRL_NHSYNC; + + if (desired_mode->flags & V_NVSYNC) + mode_ctl |= NV50_SOR_MODE_CTRL_NVSYNC; + + /* TODO: DPMS ?????? */ + + OUT_MODE(NV50_SOR0_MODE_CTRL + offset, mode_ctl); + + return 0; +} + +static int nv50_sor_set_clock_mode(struct nv50_output *output) +{ + struct drm_nouveau_private *dev_priv = output->dev->dev_private; + struct nv50_crtc *crtc = output->crtc; + + uint32_t limit = 165000; + struct nouveau_hw_mode *hw_mode; + + NV50_DEBUG("or %d\n", nv50_output_or_offset(output)); + + if (crtc->use_native_mode) + hw_mode = crtc->native_mode; + else + hw_mode = crtc->mode; + + /* 0x70000 was a late addition to nv, mentioned as fixing tmds initialisation on certain gpu's. */ + /* I presume it's some kind of clock setting, but what precisely i do not know. */ + NV_WRITE(NV50_PDISPLAY_SOR_CLK_CLK_CTRL2(nv50_output_or_offset(output)), 0x70000 | ((hw_mode->clock > limit) ? 0x101 : 0)); + + return 0; +} + +static int nv50_sor_destroy(struct nv50_output *output) +{ + struct drm_device *dev = output->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nv50_display *display = nv50_get_display(dev); + + NV50_DEBUG("\n"); + + if (!display || !output) + return -EINVAL; + + list_del(&output->head); + + kfree(output->native_mode); + if (dev_priv->free_output) + dev_priv->free_output(output); + + return 0; +} + +int nv50_sor_create(struct drm_device *dev, int dcb_entry) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nv50_output *output = NULL; + struct nv50_display *display = NULL; + struct dcb_entry *entry = NULL; + + NV50_DEBUG("\n"); + + /* This allows the public layer to do it's thing. */ + if (dev_priv->alloc_output) + output = dev_priv->alloc_output(dev); + + if (!output) + return -ENOMEM; + + output->dev = dev; + + display = nv50_get_display(dev); + if (!display) + goto out; + + entry = &dev_priv->dcb_table.entry[dcb_entry]; + if (!entry) + goto out; + + switch (entry->type) { + case DCB_OUTPUT_TMDS: + output->type = OUTPUT_TMDS; + DRM_INFO("Detected a TMDS output\n"); + break; + case DCB_OUTPUT_LVDS: + output->type = OUTPUT_LVDS; + DRM_INFO("Detected a LVDS output\n"); + break; + default: + goto out; + } + + output->dcb_entry = dcb_entry; + output->bus = entry->bus; + + list_add_tail(&output->head, &display->outputs); + + output->native_mode = kzalloc(sizeof(struct nouveau_hw_mode), GFP_KERNEL); + + /* Set function pointers. */ + output->validate_mode = nv50_sor_validate_mode; + output->execute_mode = nv50_sor_execute_mode; + output->set_clock_mode = nv50_sor_set_clock_mode; + output->detect = NULL; + output->destroy = nv50_sor_destroy; + + /* Some default state, unknown what it precisely means. */ + if (output->type == OUTPUT_TMDS) { + NV_WRITE(NV50_PDISPLAY_SOR_REGS_UNK_00C(nv50_output_or_offset(output)), 0x03010700); + NV_WRITE(NV50_PDISPLAY_SOR_REGS_UNK_010(nv50_output_or_offset(output)), 0x0000152f); + NV_WRITE(NV50_PDISPLAY_SOR_REGS_UNK_014(nv50_output_or_offset(output)), 0x00000000); + NV_WRITE(NV50_PDISPLAY_SOR_REGS_UNK_018(nv50_output_or_offset(output)), 0x00245af8); + } + + return 0; + +out: + if (output->native_mode) + kfree(output->native_mode); + if (dev_priv->free_output) + dev_priv->free_output(output); + return -EINVAL; +} diff --git a/shared-core/nouveau_dma.h b/shared-core/nouveau_dma.h index ce3c58cb..07652c2b 100644 --- a/shared-core/nouveau_dma.h +++ b/shared-core/nouveau_dma.h @@ -93,4 +93,9 @@ typedef enum { } \ } while(0) +/* This should allow easy switching to a real fifo in the future. */ +#define OUT_MODE(mthd, val) do { \ + nv50_display_command(dev_priv, mthd, val); \ +} while(0) + #endif diff --git a/shared-core/nouveau_drv.h b/shared-core/nouveau_drv.h index a51e552c..20aa6b86 100644 --- a/shared-core/nouveau_drv.h +++ b/shared-core/nouveau_drv.h @@ -41,6 +41,9 @@ #include "nouveau_drm.h" #include "nouveau_reg.h" +#include "nouveau_bios.h" + +#define MAX_NUM_DCB_ENTRIES 16 struct mem_block { struct mem_block *next; @@ -310,6 +313,28 @@ struct drm_nouveau_private { struct nouveau_config config; struct list_head gpuobj_list; + + void *display_priv; /* internal modesetting */ + void *kms_priv; /* related to public interface */ + + /* Hook these up to the "public interface" to accomodate a certain allocation style. */ + /* This is to avoid polluting the internal interface. */ + void *(*alloc_crtc) (struct drm_device *dev); + void *(*alloc_output) (struct drm_device *dev); + void *(*alloc_connector) (struct drm_device *dev); + + void (*free_crtc) (void *crtc); + void (*free_output) (void *output); + void (*free_connector) (void *connector); + + struct bios bios; + + struct { + int entries; + struct dcb_entry entry[MAX_NUM_DCB_ENTRIES]; + unsigned char i2c_read[MAX_NUM_DCB_ENTRIES]; + unsigned char i2c_write[MAX_NUM_DCB_ENTRIES]; + } dcb_table; }; #define NOUVEAU_CHECK_INITIALISED_WITH_RETURN do { \ @@ -353,6 +378,7 @@ extern struct mem_block *nouveau_mem_alloc_block(struct mem_block *, struct drm_file *); extern void nouveau_mem_takedown(struct mem_block **heap); extern void nouveau_mem_free_block(struct mem_block *); +extern struct mem_block* find_block_by_handle(struct mem_block *heap, drm_handle_t handle); extern uint64_t nouveau_mem_fb_amount(struct drm_device *); extern void nouveau_mem_release(struct drm_file *, struct mem_block *heap); extern int nouveau_ioctl_mem_alloc(struct drm_device *, void *data, diff --git a/shared-core/nouveau_irq.c b/shared-core/nouveau_irq.c index 2a3d8a0b..e68b755f 100644 --- a/shared-core/nouveau_irq.c +++ b/shared-core/nouveau_irq.c @@ -37,6 +37,11 @@ #include "nouveau_reg.h" #include "nouveau_swmthd.h" +/* needed for interrupt based vpll changes */ +#include "nv50_display.h" +#include "nv50_crtc.h" +#include "nv50_output.h" + void nouveau_irq_preinstall(struct drm_device *dev) { @@ -503,11 +508,82 @@ static void nouveau_nv50_display_irq_handler(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; - uint32_t val = NV_READ(NV50_DISPLAY_SUPERVISOR); + uint32_t val = NV_READ(NV50_PDISPLAY_SUPERVISOR); DRM_INFO("NV50_DISPLAY_INTR - 0x%08X\n", val); - NV_WRITE(NV50_DISPLAY_SUPERVISOR, val); + /* vblank interrupts */ + if (val & NV50_PDISPLAY_SUPERVISOR_CRTCn) { + NV_WRITE(NV50_PDISPLAY_SUPERVISOR, val & NV50_PDISPLAY_SUPERVISOR_CRTCn); + val &= ~NV50_PDISPLAY_SUPERVISOR_CRTCn; + } + + /* clock setting amongst other things. */ + if (val & NV50_PDISPLAY_SUPERVISOR_CLK_MASK) { + uint32_t state = (val & NV50_PDISPLAY_SUPERVISOR_CLK_MASK) >> NV50_PDISPLAY_SUPERVISOR_CLK_MASK__SHIFT; + + NV50_DEBUG("state %d\n", state); + + /* Set pll */ + if (state == 2) { + struct nv50_display *display = nv50_get_display(dev); + struct nv50_output *output = NULL; + struct nv50_crtc *crtc = NULL; + int crtc_index; + + uint32_t unk30 = NV_READ(NV50_PDISPLAY_UNK30_CTRL); + + for (crtc_index = 0; crtc_index < 2; crtc_index++) { + bool clock_change = false; + bool clock_ack = false; + + if (crtc_index == 0 && (unk30 & NV50_PDISPLAY_UNK30_CTRL_UPDATE_VCLK0)) + clock_change = true; + + if (crtc_index == 1 && (unk30 & NV50_PDISPLAY_UNK30_CTRL_UPDATE_VCLK1)) + clock_change = true; + + if (clock_change) + clock_ack = true; + + if (display->last_crtc == crtc_index) + clock_ack = true; + + list_for_each_entry(crtc, &display->crtcs, head) { + if (crtc->index == crtc_index) + break; + } + + if (clock_change) + crtc->set_clock(crtc); + + NV50_DEBUG("index %d clock_change %d clock_ack %d\n", crtc_index, clock_change, clock_ack); + + if (!clock_ack) + continue; + + crtc->set_clock_mode(crtc); + + list_for_each_entry(output, &display->outputs, head) { + if (!output->crtc) + continue; + + if (output->crtc == crtc) + output->set_clock_mode(output); + } + } + } + + NV_WRITE(NV50_PDISPLAY_UNK30_CTRL, NV50_PDISPLAY_UNK30_CTRL_PENDING); + NV_WRITE(NV50_PDISPLAY_SUPERVISOR, val & NV50_PDISPLAY_SUPERVISOR_CLK_MASK); + + val &= ~NV50_PDISPLAY_SUPERVISOR_CLK_MASK; + } + + if (val) + DRM_ERROR("unsupported NV50_DISPLAY_INTR - 0x%08X\n", val); + + NV_WRITE(NV50_PDISPLAY_SUPERVISOR, val); } static void diff --git a/shared-core/nouveau_mem.c b/shared-core/nouveau_mem.c index 2cf8807d..810eaf9e 100644 --- a/shared-core/nouveau_mem.c +++ b/shared-core/nouveau_mem.c @@ -108,6 +108,17 @@ static struct mem_block *find_block(struct mem_block *heap, uint64_t start) return NULL; } +struct mem_block *find_block_by_handle(struct mem_block *heap, drm_handle_t handle) +{ + struct mem_block *p; + + list_for_each(p, heap) + if (p->map_handle == handle) + return p; + + return NULL; +} + void nouveau_mem_free_block(struct mem_block *p) { p->file_priv = NULL; diff --git a/shared-core/nouveau_reg.h b/shared-core/nouveau_reg.h index 1ae0177c..8cf7f889 100644 --- a/shared-core/nouveau_reg.h +++ b/shared-core/nouveau_reg.h @@ -116,6 +116,9 @@ #define NV04_PBUS_PCI_NV_1 0x00001804 #define NV04_PBUS_PCI_NV_19 0x0000184C +#define NV04_PBUS_PCI_NV_20 0x00001850 +# define NV04_PBUS_PCI_NV_20_ROM_SHADOW_DISABLED (0 << 0) +# define NV04_PBUS_PCI_NV_20_ROM_SHADOW_ENABLED (1 << 0) #define NV04_PTIMER_INTR_0 0x00009100 #define NV04_PTIMER_INTR_EN_0 0x00009140 @@ -542,6 +545,8 @@ /* This name is a partial guess. */ #define NV50_DISPLAY_SUPERVISOR 0x00610024 +#define NV04_PRAMIN 0x00700000 + /* Fifo commands. These are not regs, neither masks */ #define NV03_FIFO_CMD_JUMP 0x20000000 #define NV03_FIFO_CMD_JUMP_OFFSET_MASK 0x1ffffffc @@ -591,3 +596,296 @@ #define NV40_RAMFC_UNK_48 0x48 #define NV40_RAMFC_UNK_4C 0x4C #define NV40_RAMFC_UNK_50 0x50 + +/* This is a partial import from rules-ng, a few things may be duplicated. + * Eventually we should completely import everything from rules-ng. + * For the moment check rules-ng for docs. + */ + +#define NV50_PMC 0x00000000 +#define NV50_PMC__LEN 0x1 +#define NV50_PMC__ESIZE 0x2000 +# define NV50_PMC_BOOT_0 0x00000000 +# define NV50_PMC_BOOT_0_REVISION 0x000000ff +# define NV50_PMC_BOOT_0_REVISION__SHIFT 0 +# define NV50_PMC_BOOT_0_ARCH 0x0ff00000 +# define NV50_PMC_BOOT_0_ARCH__SHIFT 20 +# define NV50_PMC_INTR_0 0x00000100 +# define NV50_PMC_INTR_0_PFIFO (1<<8) +# define NV50_PMC_INTR_0_PGRAPH (1<<12) +# define NV50_PMC_INTR_0_PTIMER (1<<20) +# define NV50_PMC_INTR_0_HOTPLUG (1<<21) +# define NV50_PMC_INTR_0_DISPLAY (1<<26) +# define NV50_PMC_INTR_EN_0 0x00000140 +# define NV50_PMC_INTR_EN_0_MASTER (1<<0) +# define NV50_PMC_INTR_EN_0_MASTER_DISABLED (0<<0) +# define NV50_PMC_INTR_EN_0_MASTER_ENABLED (1<<0) +# define NV50_PMC_ENABLE 0x00000200 +# define NV50_PMC_ENABLE_PFIFO (1<<8) +# define NV50_PMC_ENABLE_PGRAPH (1<<12) + +#define NV50_PCONNECTOR 0x0000e000 +#define NV50_PCONNECTOR__LEN 0x1 +#define NV50_PCONNECTOR__ESIZE 0x1000 +# define NV50_PCONNECTOR_HOTPLUG_INTR 0x0000e050 +# define NV50_PCONNECTOR_HOTPLUG_INTR_PLUG_I2C0 (1<<0) +# define NV50_PCONNECTOR_HOTPLUG_INTR_PLUG_I2C1 (1<<1) +# define NV50_PCONNECTOR_HOTPLUG_INTR_PLUG_I2C2 (1<<2) +# define NV50_PCONNECTOR_HOTPLUG_INTR_PLUG_I2C3 (1<<3) +# define NV50_PCONNECTOR_HOTPLUG_INTR_PLUG_I2C4 (1<<4) +# define NV50_PCONNECTOR_HOTPLUG_INTR_PLUG_I2C5 (1<<5) +# define NV50_PCONNECTOR_HOTPLUG_INTR_PLUG_I2C6 (1<<6) +# define NV50_PCONNECTOR_HOTPLUG_INTR_PLUG_I2C7 (1<<7) +# define NV50_PCONNECTOR_HOTPLUG_INTR_PLUG_I2C8 (1<<8) +# define NV50_PCONNECTOR_HOTPLUG_INTR_PLUG_I2C9 (1<<9) +# define NV50_PCONNECTOR_HOTPLUG_INTR_PLUG_I2C10 (1<<10) +# define NV50_PCONNECTOR_HOTPLUG_INTR_PLUG_I2C11 (1<<11) +# define NV50_PCONNECTOR_HOTPLUG_INTR_PLUG_I2C12 (1<<12) +# define NV50_PCONNECTOR_HOTPLUG_INTR_PLUG_I2C13 (1<<13) +# define NV50_PCONNECTOR_HOTPLUG_INTR_PLUG_I2C14 (1<<14) +# define NV50_PCONNECTOR_HOTPLUG_INTR_PLUG_I2C15 (1<<15) +# define NV50_PCONNECTOR_HOTPLUG_INTR_UNPLUG_I2C0 (1<<16) +# define NV50_PCONNECTOR_HOTPLUG_INTR_UNPLUG_I2C1 (1<<17) +# define NV50_PCONNECTOR_HOTPLUG_INTR_UNPLUG_I2C2 (1<<18) +# define NV50_PCONNECTOR_HOTPLUG_INTR_UNPLUG_I2C3 (1<<19) +# define NV50_PCONNECTOR_HOTPLUG_INTR_UNPLUG_I2C4 (1<<20) +# define NV50_PCONNECTOR_HOTPLUG_INTR_UNPLUG_I2C5 (1<<21) +# define NV50_PCONNECTOR_HOTPLUG_INTR_UNPLUG_I2C6 (1<<22) +# define NV50_PCONNECTOR_HOTPLUG_INTR_UNPLUG_I2C7 (1<<23) +# define NV50_PCONNECTOR_HOTPLUG_INTR_UNPLUG_I2C8 (1<<24) +# define NV50_PCONNECTOR_HOTPLUG_INTR_UNPLUG_I2C9 (1<<25) +# define NV50_PCONNECTOR_HOTPLUG_INTR_UNPLUG_I2C10 (1<<26) +# define NV50_PCONNECTOR_HOTPLUG_INTR_UNPLUG_I2C11 (1<<27) +# define NV50_PCONNECTOR_HOTPLUG_INTR_UNPLUG_I2C12 (1<<28) +# define NV50_PCONNECTOR_HOTPLUG_INTR_UNPLUG_I2C13 (1<<29) +# define NV50_PCONNECTOR_HOTPLUG_INTR_UNPLUG_I2C14 (1<<30) +# define NV50_PCONNECTOR_HOTPLUG_INTR_UNPLUG_I2C15 (1<<31) +# define NV50_PCONNECTOR_HOTPLUG_CTRL 0x0000e054 +# define NV50_PCONNECTOR_HOTPLUG_CTRL_PLUG_I2C0 (1<<0) +# define NV50_PCONNECTOR_HOTPLUG_CTRL_PLUG_I2C1 (1<<1) +# define NV50_PCONNECTOR_HOTPLUG_CTRL_PLUG_I2C2 (1<<2) +# define NV50_PCONNECTOR_HOTPLUG_CTRL_PLUG_I2C3 (1<<3) +# define NV50_PCONNECTOR_HOTPLUG_CTRL_PLUG_I2C4 (1<<4) +# define NV50_PCONNECTOR_HOTPLUG_CTRL_PLUG_I2C5 (1<<5) +# define NV50_PCONNECTOR_HOTPLUG_CTRL_PLUG_I2C6 (1<<6) +# define NV50_PCONNECTOR_HOTPLUG_CTRL_PLUG_I2C7 (1<<7) +# define NV50_PCONNECTOR_HOTPLUG_CTRL_PLUG_I2C8 (1<<8) +# define NV50_PCONNECTOR_HOTPLUG_CTRL_PLUG_I2C9 (1<<9) +# define NV50_PCONNECTOR_HOTPLUG_CTRL_PLUG_I2C10 (1<<10) +# define NV50_PCONNECTOR_HOTPLUG_CTRL_PLUG_I2C11 (1<<11) +# define NV50_PCONNECTOR_HOTPLUG_CTRL_PLUG_I2C12 (1<<12) +# define NV50_PCONNECTOR_HOTPLUG_CTRL_PLUG_I2C13 (1<<13) +# define NV50_PCONNECTOR_HOTPLUG_CTRL_PLUG_I2C14 (1<<14) +# define NV50_PCONNECTOR_HOTPLUG_CTRL_PLUG_I2C15 (1<<15) +# define NV50_PCONNECTOR_HOTPLUG_CTRL_UNPLUG_I2C0 (1<<16) +# define NV50_PCONNECTOR_HOTPLUG_CTRL_UNPLUG_I2C1 (1<<17) +# define NV50_PCONNECTOR_HOTPLUG_CTRL_UNPLUG_I2C2 (1<<18) +# define NV50_PCONNECTOR_HOTPLUG_CTRL_UNPLUG_I2C3 (1<<19) +# define NV50_PCONNECTOR_HOTPLUG_CTRL_UNPLUG_I2C4 (1<<20) +# define NV50_PCONNECTOR_HOTPLUG_CTRL_UNPLUG_I2C5 (1<<21) +# define NV50_PCONNECTOR_HOTPLUG_CTRL_UNPLUG_I2C6 (1<<22) +# define NV50_PCONNECTOR_HOTPLUG_CTRL_UNPLUG_I2C7 (1<<23) +# define NV50_PCONNECTOR_HOTPLUG_CTRL_UNPLUG_I2C8 (1<<24) +# define NV50_PCONNECTOR_HOTPLUG_CTRL_UNPLUG_I2C9 (1<<25) +# define NV50_PCONNECTOR_HOTPLUG_CTRL_UNPLUG_I2C10 (1<<26) +# define NV50_PCONNECTOR_HOTPLUG_CTRL_UNPLUG_I2C11 (1<<27) +# define NV50_PCONNECTOR_HOTPLUG_CTRL_UNPLUG_I2C12 (1<<28) +# define NV50_PCONNECTOR_HOTPLUG_CTRL_UNPLUG_I2C13 (1<<29) +# define NV50_PCONNECTOR_HOTPLUG_CTRL_UNPLUG_I2C14 (1<<30) +# define NV50_PCONNECTOR_HOTPLUG_CTRL_UNPLUG_I2C15 (1<<31) +# define NV50_PCONNECTOR_HOTPLUG_STATE1 0x0000e104 +# define NV50_PCONNECTOR_HOTPLUG_STATE1_PIN_CONNECTED_I2C0 (1<<2) +# define NV50_PCONNECTOR_HOTPLUG_STATE1_PIN_CONNECTED_I2C1 (1<<6) +# define NV50_PCONNECTOR_HOTPLUG_STATE1_PIN_CONNECTED_I2C2 (1<<10) +# define NV50_PCONNECTOR_HOTPLUG_STATE1_PIN_CONNECTED_I2C3 (1<<14) +# define NV50_PCONNECTOR_HOTPLUG_STATE1_PIN_CONNECTED_I2C4 (1<<18) +# define NV50_PCONNECTOR_HOTPLUG_STATE1_PIN_CONNECTED_I2C5 (1<<22) +# define NV50_PCONNECTOR_HOTPLUG_STATE1_PIN_CONNECTED_I2C6 (1<<26) +# define NV50_PCONNECTOR_HOTPLUG_STATE1_PIN_CONNECTED_I2C7 (1<<30) +# define NV50_PCONNECTOR_HOTPLUG_STATE2 0x0000e108 +# define NV50_PCONNECTOR_HOTPLUG_STATE2_PIN_CONNECTED_I2C8 (1<<2) +# define NV50_PCONNECTOR_HOTPLUG_STATE2_PIN_CONNECTED_I2C9 (1<<6) +# define NV50_PCONNECTOR_HOTPLUG_STATE2_PIN_CONNECTED_I2C10 (1<<10) +# define NV50_PCONNECTOR_HOTPLUG_STATE2_PIN_CONNECTED_I2C11 (1<<14) +# define NV50_PCONNECTOR_HOTPLUG_STATE2_PIN_CONNECTED_I2C12 (1<<18) +# define NV50_PCONNECTOR_HOTPLUG_STATE2_PIN_CONNECTED_I2C13 (1<<22) +# define NV50_PCONNECTOR_HOTPLUG_STATE2_PIN_CONNECTED_I2C14 (1<<26) +# define NV50_PCONNECTOR_HOTPLUG_STATE2_PIN_CONNECTED_I2C15 (1<<30) +# define NV50_PCONNECTOR_I2C 0x0000e138 +# define NV50_PCONNECTOR_I2C__LEN 0x10 +# define NV50_PCONNECTOR_I2C__ESIZE 0x18 +# define NV50_PCONNECTOR_I2C_PORT(i) (0x0000e138+(i)*0x18) + + +#define NV50_PBUS 0x00088000 +#define NV50_PBUS__LEN 0x1 +#define NV50_PBUS__ESIZE 0x1000 +# define NV50_PBUS_PCI_ID 0x00088000 +# define NV50_PBUS_PCI_ID_VENDOR_ID 0x0000ffff +# define NV50_PBUS_PCI_ID_VENDOR_ID__SHIFT 0 +# define NV50_PBUS_PCI_ID_DEVICE_ID 0xffff0000 +# define NV50_PBUS_PCI_ID_DEVICE_ID__SHIFT 16 + +#define NV50_PFB 0x00100000 +#define NV50_PFB__LEN 0x1 +#define NV50_PFB__ESIZE 0x1000 + +#define NV50_PEXTDEV 0x00101000 +#define NV50_PEXTDEV__LEN 0x1 +#define NV50_PEXTDEV__ESIZE 0x1000 + +#define NV50_PROM 0x00300000 +#define NV50_PROM__LEN 0x1 +#define NV50_PROM__ESIZE 0x10000 + +#define NV50_PGRAPH 0x00400000 +#define NV50_PGRAPH__LEN 0x1 +#define NV50_PGRAPH__ESIZE 0x10000 + +#define NV50_PDISPLAY 0x00610000 +#define NV50_PDISPLAY__LEN 0x1 +#define NV50_PDISPLAY__ESIZE 0x10000 +# define NV50_PDISPLAY_SUPERVISOR 0x00610024 +# define NV50_PDISPLAY_SUPERVISOR_CRTCn 0x0000000c +# define NV50_PDISPLAY_SUPERVISOR_CRTCn__SHIFT 2 +# define NV50_PDISPLAY_SUPERVISOR_CRTC0 (1<<2) +# define NV50_PDISPLAY_SUPERVISOR_CRTC1 (1<<3) +# define NV50_PDISPLAY_SUPERVISOR_CLK_MASK 0x00000070 +# define NV50_PDISPLAY_SUPERVISOR_CLK_MASK__SHIFT 4 +# define NV50_PDISPLAY_SUPERVISOR_CLK_UPDATE (1<<5) +# define NV50_PDISPLAY_SUPERVISOR_INTR 0x0061002c +# define NV50_PDISPLAY_SUPERVISOR_INTR_VBLANK_CRTC0 (1<<2) +# define NV50_PDISPLAY_SUPERVISOR_INTR_VBLANK_CRTC1 (1<<3) +# define NV50_PDISPLAY_SUPERVISOR_INTR_UNK1 (1<<4) +# define NV50_PDISPLAY_SUPERVISOR_INTR_CLK_UPDATE (1<<5) +# define NV50_PDISPLAY_SUPERVISOR_INTR_UNK4 (1<<6) +# define NV50_PDISPLAY_UNK30_CTRL 0x00610030 +# define NV50_PDISPLAY_UNK30_CTRL_UPDATE_VCLK0 (1<<9) +# define NV50_PDISPLAY_UNK30_CTRL_UPDATE_VCLK1 (1<<10) +# define NV50_PDISPLAY_UNK30_CTRL_PENDING (1<<31) +# define NV50_PDISPLAY_UNK50_CTRL 0x00610050 +# define NV50_PDISPLAY_UNK50_CTRL_CRTC0_ACTIVE (1<<1) +# define NV50_PDISPLAY_UNK50_CTRL_CRTC0_ACTIVE_MASK 0x00000003 +# define NV50_PDISPLAY_UNK50_CTRL_CRTC0_ACTIVE_MASK__SHIFT 0 +# define NV50_PDISPLAY_UNK50_CTRL_CRTC1_ACTIVE (1<<9) +# define NV50_PDISPLAY_UNK50_CTRL_CRTC1_ACTIVE_MASK 0x00000300 +# define NV50_PDISPLAY_UNK50_CTRL_CRTC1_ACTIVE_MASK__SHIFT 8 +# define NV50_PDISPLAY_UNK200_CTRL 0x00610200 +# define NV50_PDISPLAY_CURSOR 0x00610270 +# define NV50_PDISPLAY_CURSOR__LEN 0x2 +# define NV50_PDISPLAY_CURSOR__ESIZE 0x10 +# define NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i) (0x00610270+(i)*0x10) +# define NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_ON (1<<0) +# define NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS_MASK 0x00030000 +# define NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS_MASK__SHIFT 16 +# define NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS_ACTIVE (1<<16) + +# define NV50_PDISPLAY_CTRL_STATE 0x00610300 +# define NV50_PDISPLAY_CTRL_STATE_ENABLE (1<<0) +# define NV50_PDISPLAY_CTRL_STATE_PENDING (1<<31) +# define NV50_PDISPLAY_CTRL_VAL 0x00610304 +# define NV50_PDISPLAY_UNK_380 0x00610380 +# define NV50_PDISPLAY_RAM_AMOUNT 0x00610384 +# define NV50_PDISPLAY_UNK_388 0x00610388 +# define NV50_PDISPLAY_UNK_38C 0x0061038c +# define NV50_PDISPLAY_CRTC_VAL 0x00610a00 +# define NV50_PDISPLAY_CRTC_VAL__LEN 0x2 +# define NV50_PDISPLAY_CRTC_VAL_UNK_900(i,j) (0x00610a18+(i)*0x540+(j)*0x4) +# define NV50_PDISPLAY_CRTC_VAL_CLUT_MODE(i,j) (0x00610a24+(i)*0x540+(j)*0x4) +# define NV50_PDISPLAY_CRTC_VAL_INTERLACE(i,j) (0x00610a48+(i)*0x540+(j)*0x4) +# define NV50_PDISPLAY_CRTC_VAL_SCALE_CTRL(i,j) (0x00610a50+(i)*0x540+(j)*0x4) +# define NV50_PDISPLAY_CRTC_VAL_CURSOR_CTRL(i,j) (0x00610a58+(i)*0x540+(j)*0x4) +# define NV50_PDISPLAY_CRTC_VAL_UNK_904(i,j) (0x00610ab8+(i)*0x540+(j)*0x4) +# define NV50_PDISPLAY_CRTC_VAL_DEPTH(i,j) (0x00610ac8+(i)*0x540+(j)*0x4) +# define NV50_PDISPLAY_CRTC_VAL_CLOCK(i,j) (0x00610ad0+(i)*0x540+(j)*0x4) +# define NV50_PDISPLAY_CRTC_VAL_COLOR_CTRL(i,j) (0x00610ae0+(i)*0x540+(j)*0x4) +# define NV50_PDISPLAY_CRTC_VAL_SYNC_START_TO_BLANK_END(i,j) (0x00610ae8+(i)*0x540+(j)*0x4) +# define NV50_PDISPLAY_CRTC_VAL_MODE_UNK1(i,j) (0x00610af0+(i)*0x540+(j)*0x4) +# define NV50_PDISPLAY_CRTC_VAL_DISPLAY_TOTAL(i,j) (0x00610af8+(i)*0x540+(j)*0x4) +# define NV50_PDISPLAY_CRTC_VAL_SYNC_DURATION(i,j) (0x00610b00+(i)*0x540+(j)*0x4) +# define NV50_PDISPLAY_CRTC_VAL_MODE_UNK2(i,j) (0x00610b08+(i)*0x540+(j)*0x4) +# define NV50_PDISPLAY_CRTC_VAL_UNK_828(i,j) (0x00610b10+(i)*0x540+(j)*0x4) +# define NV50_PDISPLAY_CRTC_VAL_FB_SIZE(i,j) (0x00610b18+(i)*0x540+(j)*0x4) +# define NV50_PDISPLAY_CRTC_VAL_FB_PITCH(i,j) (0x00610b20+(i)*0x540+(j)*0x4) +# define NV50_PDISPLAY_CRTC_VAL_FB_PITCH_LINEAR_FB (1<<20) +# define NV50_PDISPLAY_CRTC_VAL_FB_POS(i,j) (0x00610b28+(i)*0x540+(j)*0x4) +# define NV50_PDISPLAY_CRTC_VAL_SCALE_CENTER_OFFSET(i,j) (0x00610b38+(i)*0x540+(j)*0x4) +# define NV50_PDISPLAY_CRTC_VAL_REAL_RES(i,j) (0x00610b40+(i)*0x540+(j)*0x4) +# define NV50_PDISPLAY_CRTC_VAL_SCALE_RES1(i,j) (0x00610b48+(i)*0x540+(j)*0x4) +# define NV50_PDISPLAY_CRTC_VAL_SCALE_RES2(i,j) (0x00610b50+(i)*0x540+(j)*0x4) + + +# define NV50_PDISPLAY_DAC_VAL_MODE_CTRL(i,j) (0x00610b58+(i)*0x8+(j)*0x4) + + +# define NV50_PDISPLAY_SOR_VAL_MODE_CTRL(i,j) (0x00610b70+(i)*0x8+(j)*0x4) + + +# define NV50_PDISPLAY_DAC_VAL_MODE_CTRL2(i,j) (0x00610bdc+(i)*0x8+(j)*0x4) + + +# define NV50_PDISPLAY_CRTC_CLK 0x00614000 +# define NV50_PDISPLAY_CRTC_CLK__LEN 0x2 +# define NV50_PDISPLAY_CRTC_CLK_CLK_CTRL1(i) (0x00614100+(i)*0x800) +# define NV50_PDISPLAY_CRTC_CLK_CLK_CTRL1_CONNECTED 0x00000600 +# define NV50_PDISPLAY_CRTC_CLK_CLK_CTRL1_CONNECTED__SHIFT 9 +# define NV50_PDISPLAY_CRTC_CLK_VPLL_A(i) (0x00614104+(i)*0x800) +# define NV50_PDISPLAY_CRTC_CLK_VPLL_B(i) (0x00614108+(i)*0x800) +# define NV50_PDISPLAY_CRTC_CLK_CLK_CTRL2(i) (0x00614200+(i)*0x800) + +# define NV50_PDISPLAY_DAC_CLK 0x00614000 +# define NV50_PDISPLAY_DAC_CLK__LEN 0x3 +# define NV50_PDISPLAY_DAC_CLK_CLK_CTRL2(i) (0x00614280+(i)*0x800) + +# define NV50_PDISPLAY_SOR_CLK 0x00614000 +# define NV50_PDISPLAY_SOR_CLK__LEN 0x3 +# define NV50_PDISPLAY_SOR_CLK_CLK_CTRL2(i) (0x00614300+(i)*0x800) + +# define NV50_PDISPLAY_DAC_REGS 0x0061a000 +# define NV50_PDISPLAY_DAC_REGS__LEN 0x3 +# define NV50_PDISPLAY_DAC_REGS__ESIZE 0x800 +# define NV50_PDISPLAY_DAC_REGS_DPMS_CTRL(i) (0x0061a004+(i)*0x800) +# define NV50_PDISPLAY_DAC_REGS_DPMS_CTRL_HSYNC_OFF (1<<0) +# define NV50_PDISPLAY_DAC_REGS_DPMS_CTRL_VSYNC_OFF (1<<2) +# define NV50_PDISPLAY_DAC_REGS_DPMS_CTRL_BLANKED (1<<4) +# define NV50_PDISPLAY_DAC_REGS_DPMS_CTRL_OFF (1<<6) +# define NV50_PDISPLAY_DAC_REGS_DPMS_CTRL_PENDING (1<<31) +# define NV50_PDISPLAY_DAC_REGS_LOAD_CTRL(i) (0x0061a00c+(i)*0x800) +# define NV50_PDISPLAY_DAC_REGS_LOAD_CTRL_ACTIVE (1<<20) +# define NV50_PDISPLAY_DAC_REGS_LOAD_CTRL_PRESENT 0x38000000 +# define NV50_PDISPLAY_DAC_REGS_LOAD_CTRL_PRESENT__SHIFT 29 +# define NV50_PDISPLAY_DAC_REGS_LOAD_CTRL_DONE (1<<31) +# define NV50_PDISPLAY_DAC_REGS_CLK_CTRL1(i) (0x0061a010+(i)*0x800) +# define NV50_PDISPLAY_DAC_REGS_CLK_CTRL1_CONNECTED 0x00000600 +# define NV50_PDISPLAY_DAC_REGS_CLK_CTRL1_CONNECTED__SHIFT 9 + +# define NV50_PDISPLAY_SOR_REGS 0x0061c000 +# define NV50_PDISPLAY_SOR_REGS__LEN 0x2 +# define NV50_PDISPLAY_SOR_REGS__ESIZE 0x800 +# define NV50_PDISPLAY_SOR_REGS_DPMS_CTRL(i) (0x0061c004+(i)*0x800) +# define NV50_PDISPLAY_SOR_REGS_DPMS_CTRL_ON (1<<0) +# define NV50_PDISPLAY_SOR_REGS_DPMS_CTRL_PENDING (1<<31) +# define NV50_PDISPLAY_SOR_REGS_CLK_CTRL1(i) (0x0061c008+(i)*0x800) +# define NV50_PDISPLAY_SOR_REGS_CLK_CTRL1_CONNECTED 0x00000600 +# define NV50_PDISPLAY_SOR_REGS_CLK_CTRL1_CONNECTED__SHIFT 9 +# define NV50_PDISPLAY_SOR_REGS_UNK_00C(i) (0x0061c00c+(i)*0x800) +# define NV50_PDISPLAY_SOR_REGS_UNK_010(i) (0x0061c010+(i)*0x800) +# define NV50_PDISPLAY_SOR_REGS_UNK_014(i) (0x0061c014+(i)*0x800) +# define NV50_PDISPLAY_SOR_REGS_UNK_018(i) (0x0061c018+(i)*0x800) +# define NV50_PDISPLAY_SOR_REGS_DPMS_STATE(i) (0x0061c030+(i)*0x800) +# define NV50_PDISPLAY_SOR_REGS_DPMS_STATE_ACTIVE 0x00030000 +# define NV50_PDISPLAY_SOR_REGS_DPMS_STATE_ACTIVE__SHIFT 16 +# define NV50_PDISPLAY_SOR_REGS_DPMS_STATE_BLANKED (1<<19) +# define NV50_PDISPLAY_SOR_REGS_DPMS_STATE_WAIT (1<<28) + + +#define NV50_UNK640000 0x00640000 +#define NV50_UNK640000__LEN 0x6 +#define NV50_UNK640000__ESIZE 0x1000 +# define NV50_UNK640000_UNK_000(i) (0x00640000+(i)*0x1000) + +#define NV50_HW_CURSOR 0x00647000 +#define NV50_HW_CURSOR__LEN 0x2 +#define NV50_HW_CURSOR__ESIZE 0x1000 +# define NV50_HW_CURSOR_POS_CTRL(i) (0x00647080+(i)*0x1000) +# define NV50_HW_CURSOR_POS(i) (0x00647084+(i)*0x1000) diff --git a/shared-core/nouveau_state.c b/shared-core/nouveau_state.c index d9c6efe7..82591c64 100644 --- a/shared-core/nouveau_state.c +++ b/shared-core/nouveau_state.c @@ -27,6 +27,7 @@ #include "drm_sarea.h" #include "nouveau_drv.h" #include "nouveau_drm.h" +#include "nv50_kms_wrapper.h" static int nouveau_init_card_mappings(struct drm_device *dev) { @@ -362,6 +363,13 @@ nouveau_card_init(struct drm_device *dev) if (ret) return ret; dev_priv->init_state = NOUVEAU_CARD_INIT_DONE; + + if (drm_core_check_feature(dev, DRIVER_MODESET)) + if (dev_priv->card_type >= NV_50) { + nv50_kms_init(dev); + nv50_kms_connector_detect_all(dev); + } + return 0; } @@ -410,8 +418,7 @@ void nouveau_preclose(struct drm_device *dev, struct drm_file *file_priv) nouveau_mem_release(file_priv,dev_priv->pci_heap); } -/* first module load, setup the mmio/fb mapping */ -int nouveau_firstopen(struct drm_device *dev) +int nouveau_setup_mappings(struct drm_device *dev) { #if defined(__powerpc__) struct drm_nouveau_private *dev_priv = dev->dev_private; @@ -457,6 +464,16 @@ int nouveau_firstopen(struct drm_device *dev) return 0; } +/* first module load, setup the mmio/fb mapping */ +/* KMS: we need mmio at load time, not when the first drm client opens. */ +int nouveau_firstopen(struct drm_device *dev) +{ + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return 0; + + return nouveau_setup_mappings(dev); +} + #define NV40_CHIPSET_MASK 0x00000baf #define NV44_CHIPSET_MASK 0x00005450 @@ -549,10 +566,23 @@ int nouveau_load(struct drm_device *dev, unsigned long flags) dev->dev_private = (void *)dev_priv; + /* init card now, otherwise bad things happen */ + if (drm_core_check_feature(dev, DRIVER_MODESET)) { + int rval = 0; + + rval = nouveau_setup_mappings(dev); + if (rval != 0) + return rval; + + rval = nouveau_card_init(dev); + if (rval != 0) + return rval; + } + return 0; } -void nouveau_lastclose(struct drm_device *dev) +void nouveau_close(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; @@ -568,8 +598,22 @@ void nouveau_lastclose(struct drm_device *dev) } } +/* KMS: we need mmio at load time, not when the first drm client opens. */ +void nouveau_lastclose(struct drm_device *dev) +{ + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return; + + nouveau_close(dev); +} + int nouveau_unload(struct drm_device *dev) { + if (drm_core_check_feature(dev, DRIVER_MODESET)) { + nv50_kms_destroy(dev); + nouveau_close(dev); + } + drm_free(dev->dev_private, sizeof(*dev->dev_private), DRM_MEM_DRIVER); dev->dev_private = NULL; return 0; -- cgit v1.2.3 From 3809209349ccf12aa71c7848f0b21d77fa0a5f03 Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Sun, 22 Jun 2008 17:01:30 +0200 Subject: Undo something i didn't want to change. - I made it consistent with recent kernel fb code (maybe this is older bugged code?) - Still i don't use this and i should leave it to others. --- linux-core/drm_edid.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/linux-core/drm_edid.c b/linux-core/drm_edid.c index 812e64a6..22c6e3bf 100644 --- a/linux-core/drm_edid.c +++ b/linux-core/drm_edid.c @@ -601,15 +601,15 @@ static unsigned char *drm_ddc_read(struct i2c_adapter *adapter) * Then set clock & data low */ algo_data->setscl(algo_data->data, 1); - //udelay(550); /* startup delay */ - //algo_data->setscl(algo_data->data, 0); - //algo_data->setsda(algo_data->data, 0); + udelay(550); /* startup delay */ + algo_data->setscl(algo_data->data, 0); + algo_data->setsda(algo_data->data, 0); for (i = 0; i < 3; i++) { /* For some old monitors we need the * following process to initialize/stop DDC */ - algo_data->setsda(algo_data->data, 1); + algo_data->setsda(algo_data->data, 0); msleep(13); algo_data->setscl(algo_data->data, 1); @@ -644,7 +644,6 @@ static unsigned char *drm_ddc_read(struct i2c_adapter *adapter) algo_data->setsda(algo_data->data, 1); msleep(15); algo_data->setscl(algo_data->data, 0); - algo_data->setsda(algo_data->data, 0); if (edid) break; } -- cgit v1.2.3 From e67cd7dda9d7d6d82f4026f246d07bf4c4021a57 Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Sun, 22 Jun 2008 18:47:51 +0200 Subject: NV50: A few minor added safeties + cleanup. --- linux-core/nouveau_bios.c | 2 ++ linux-core/nv50_crtc.c | 12 ++++++++++-- linux-core/nv50_cursor.c | 2 ++ linux-core/nv50_dac.c | 16 +++++++++++++--- linux-core/nv50_display.c | 3 +++ linux-core/nv50_fb.c | 3 +++ linux-core/nv50_kms_wrapper.c | 26 ++++++++++++++++++++------ linux-core/nv50_kms_wrapper.h | 6 +++--- linux-core/nv50_lut.c | 6 ++++++ linux-core/nv50_sor.c | 16 +++++++++++++--- 10 files changed, 75 insertions(+), 17 deletions(-) diff --git a/linux-core/nouveau_bios.c b/linux-core/nouveau_bios.c index 83647418..3e7fe23f 100644 --- a/linux-core/nouveau_bios.c +++ b/linux-core/nouveau_bios.c @@ -532,6 +532,8 @@ int nouveau_parse_bios(struct drm_device *dev) int offset; dev_priv->bios.data = kzalloc(NV50_PROM__ESIZE, GFP_KERNEL); + if (!dev_priv->bios.data) + return -ENOMEM; if (!nv_shadow_bios(dev, dev_priv->bios.data)) return -EINVAL; diff --git a/linux-core/nv50_crtc.c b/linux-core/nv50_crtc.c index 974f5202..f34e7279 100644 --- a/linux-core/nv50_crtc.c +++ b/linux-core/nv50_crtc.c @@ -463,6 +463,7 @@ int nv50_crtc_create(struct drm_device *dev, int index) struct drm_nouveau_private *dev_priv = dev->dev_private; struct nv50_crtc *crtc = NULL; struct nv50_display *display = NULL; + int rval = 0; NV50_DEBUG("\n"); @@ -476,8 +477,10 @@ int nv50_crtc_create(struct drm_device *dev, int index) crtc->dev = dev; display = nv50_get_display(dev); - if (!display) + if (!display) { + rval = -EINVAL; goto out; + } list_add_tail(&crtc->head, &display->crtcs); @@ -486,6 +489,11 @@ int nv50_crtc_create(struct drm_device *dev, int index) crtc->mode = kzalloc(sizeof(struct nouveau_hw_mode), GFP_KERNEL); crtc->native_mode = kzalloc(sizeof(struct nouveau_hw_mode), GFP_KERNEL); + if (!crtc->mode || crtc->native_mode) { + rval = -ENOMEM; + goto out; + } + nv50_fb_create(crtc); nv50_lut_create(crtc); nv50_cursor_create(crtc); @@ -511,5 +519,5 @@ out: if (dev_priv->free_crtc) dev_priv->free_crtc(crtc); - return -EINVAL; + return rval; } diff --git a/linux-core/nv50_cursor.c b/linux-core/nv50_cursor.c index 3d35b936..4196df6b 100644 --- a/linux-core/nv50_cursor.c +++ b/linux-core/nv50_cursor.c @@ -140,6 +140,8 @@ int nv50_cursor_create(struct nv50_crtc *crtc) return -EINVAL; crtc->cursor = kzalloc(sizeof(struct nv50_cursor), GFP_KERNEL); + if (!crtc->cursor) + return -ENOMEM; /* function pointers */ crtc->cursor->show = nv50_cursor_show; diff --git a/linux-core/nv50_dac.c b/linux-core/nv50_dac.c index f827fed4..b237241e 100644 --- a/linux-core/nv50_dac.c +++ b/linux-core/nv50_dac.c @@ -122,6 +122,7 @@ int nv50_dac_create(struct drm_device *dev, int dcb_entry) struct nv50_output *output = NULL; struct nv50_display *display = NULL; struct dcb_entry *entry = NULL; + int rval = 0; NV50_DEBUG("\n"); @@ -135,12 +136,16 @@ int nv50_dac_create(struct drm_device *dev, int dcb_entry) output->dev = dev; display = nv50_get_display(dev); - if (!display) + if (!display) { + rval = -EINVAL; goto out; + } entry = &dev_priv->dcb_table.entry[dcb_entry]; - if (!entry) + if (!entry) { + rval = -EINVAL; goto out; + } switch (entry->type) { case DCB_OUTPUT_ANALOG: @@ -148,6 +153,7 @@ int nv50_dac_create(struct drm_device *dev, int dcb_entry) DRM_INFO("Detected a DAC output\n"); break; default: + rval = -EINVAL; goto out; } @@ -157,6 +163,10 @@ int nv50_dac_create(struct drm_device *dev, int dcb_entry) list_add_tail(&output->head, &display->outputs); output->native_mode = kzalloc(sizeof(struct nouveau_hw_mode), GFP_KERNEL); + if (!output->native_mode) { + rval = -ENOMEM; + goto out; + } /* Set function pointers. */ output->validate_mode = nv50_dac_validate_mode; @@ -172,6 +182,6 @@ out: kfree(output->native_mode); if (dev_priv->free_output) dev_priv->free_output(output); - return -EINVAL; + return rval; } diff --git a/linux-core/nv50_display.c b/linux-core/nv50_display.c index 56ddeb97..05ff72f8 100644 --- a/linux-core/nv50_display.c +++ b/linux-core/nv50_display.c @@ -189,6 +189,9 @@ int nv50_display_create(struct drm_device *dev) NV50_DEBUG("\n"); + if (!display) + return -ENOMEM; + INIT_LIST_HEAD(&display->crtcs); INIT_LIST_HEAD(&display->outputs); INIT_LIST_HEAD(&display->connectors); diff --git a/linux-core/nv50_fb.c b/linux-core/nv50_fb.c index b44b48ab..f57a9fad 100644 --- a/linux-core/nv50_fb.c +++ b/linux-core/nv50_fb.c @@ -119,6 +119,9 @@ int nv50_fb_create(struct nv50_crtc *crtc) crtc->fb = kzalloc(sizeof(struct nv50_fb), GFP_KERNEL); + if (!crtc->fb) + return -ENOMEM; + crtc->fb->bind = nv50_fb_bind; return 0; diff --git a/linux-core/nv50_kms_wrapper.c b/linux-core/nv50_kms_wrapper.c index 01d4bc9a..a63cb7df 100644 --- a/linux-core/nv50_kms_wrapper.c +++ b/linux-core/nv50_kms_wrapper.c @@ -48,7 +48,10 @@ static void *nv50_kms_alloc_crtc(struct drm_device *dev) struct nv50_kms_priv *kms_priv = nv50_get_kms_priv(dev); struct nv50_kms_crtc *crtc = kzalloc(sizeof(struct nv50_kms_crtc), GFP_KERNEL); - list_add_tail(&crtc->head, &kms_priv->crtcs); + if (!crtc) + return NULL; + + list_add_tail(&crtc->item, &kms_priv->crtcs); return &(crtc->priv); } @@ -58,7 +61,10 @@ static void *nv50_kms_alloc_output(struct drm_device *dev) struct nv50_kms_priv *kms_priv = nv50_get_kms_priv(dev); struct nv50_kms_encoder *encoder = kzalloc(sizeof(struct nv50_kms_encoder), GFP_KERNEL); - list_add_tail(&encoder->head, &kms_priv->encoders); + if (!encoder) + return NULL; + + list_add_tail(&encoder->item, &kms_priv->encoders); return &(encoder->priv); } @@ -68,7 +74,10 @@ static void *nv50_kms_alloc_connector(struct drm_device *dev) struct nv50_kms_priv *kms_priv = nv50_get_kms_priv(dev); struct nv50_kms_connector *connector = kzalloc(sizeof(struct nv50_kms_connector), GFP_KERNEL); - list_add_tail(&connector->head, &kms_priv->connectors); + if (!connector) + return NULL; + + list_add_tail(&connector->item, &kms_priv->connectors); return &(connector->priv); } @@ -77,7 +86,7 @@ static void nv50_kms_free_crtc(void *crtc) { struct nv50_kms_crtc *kms_crtc = from_nv50_crtc(crtc); - list_del(&kms_crtc->head); + list_del(&kms_crtc->item); kfree(kms_crtc); } @@ -86,7 +95,7 @@ static void nv50_kms_free_output(void *output) { struct nv50_kms_encoder *kms_encoder = from_nv50_output(output); - list_del(&kms_encoder->head); + list_del(&kms_encoder->item); kfree(kms_encoder); } @@ -95,7 +104,7 @@ static void nv50_kms_free_connector(void *connector) { struct nv50_kms_connector *kms_connector = from_nv50_connector(connector); - list_del(&kms_connector->head); + list_del(&kms_connector->item); kfree(kms_connector); } @@ -107,6 +116,8 @@ static void nv50_kms_free_connector(void *connector) static struct nouveau_hw_mode *nv50_kms_to_hw_mode(struct drm_display_mode *mode) { struct nouveau_hw_mode *hw_mode = kzalloc(sizeof(struct nouveau_hw_mode), GFP_KERNEL); + if (!hw_mode) + return NULL; /* create hw values. */ hw_mode->clock = mode->clock; @@ -870,6 +881,9 @@ int nv50_kms_init(struct drm_device *dev) struct nv50_display *display = NULL; int rval = 0; + if (!kms_priv) + return -ENOMEM; + dev_priv->kms_priv = kms_priv; /* function pointers */ diff --git a/linux-core/nv50_kms_wrapper.h b/linux-core/nv50_kms_wrapper.h index 3847d510..f224f1bb 100644 --- a/linux-core/nv50_kms_wrapper.h +++ b/linux-core/nv50_kms_wrapper.h @@ -44,21 +44,21 @@ /* Link internal modesetting structure to interface. */ struct nv50_kms_crtc { - struct list_head head; + struct list_head item; struct nv50_crtc priv; struct drm_crtc pub; }; struct nv50_kms_encoder { - struct list_head head; + struct list_head item; struct nv50_output priv; struct drm_encoder pub; }; struct nv50_kms_connector { - struct list_head head; + struct list_head item; struct nv50_connector priv; struct drm_connector pub; diff --git a/linux-core/nv50_lut.c b/linux-core/nv50_lut.c index 570900ba..cb52f27f 100644 --- a/linux-core/nv50_lut.c +++ b/linux-core/nv50_lut.c @@ -37,6 +37,9 @@ static int nv50_lut_alloc(struct nv50_crtc *crtc) NV50_DEBUG("\n"); + if (!file_priv) + return -ENOMEM; + /* Any file_priv should do as it's pointer is used as identification. */ block = nouveau_mem_alloc(crtc->dev, 0, 4096, flags, file_priv); @@ -137,6 +140,9 @@ int nv50_lut_create(struct nv50_crtc *crtc) crtc->lut = kzalloc(sizeof(struct nv50_lut), GFP_KERNEL); + if (!crtc->lut) + return -ENOMEM; + rval = nv50_lut_alloc(crtc); if (rval != 0) return rval; diff --git a/linux-core/nv50_sor.c b/linux-core/nv50_sor.c index 430c1e83..49f29fd3 100644 --- a/linux-core/nv50_sor.c +++ b/linux-core/nv50_sor.c @@ -138,6 +138,7 @@ int nv50_sor_create(struct drm_device *dev, int dcb_entry) struct nv50_output *output = NULL; struct nv50_display *display = NULL; struct dcb_entry *entry = NULL; + int rval = 0; NV50_DEBUG("\n"); @@ -151,12 +152,16 @@ int nv50_sor_create(struct drm_device *dev, int dcb_entry) output->dev = dev; display = nv50_get_display(dev); - if (!display) + if (!display) { + rval = -EINVAL; goto out; + } entry = &dev_priv->dcb_table.entry[dcb_entry]; - if (!entry) + if (!entry) { + rval = -EINVAL; goto out; + } switch (entry->type) { case DCB_OUTPUT_TMDS: @@ -168,6 +173,7 @@ int nv50_sor_create(struct drm_device *dev, int dcb_entry) DRM_INFO("Detected a LVDS output\n"); break; default: + rval = -EINVAL; goto out; } @@ -177,6 +183,10 @@ int nv50_sor_create(struct drm_device *dev, int dcb_entry) list_add_tail(&output->head, &display->outputs); output->native_mode = kzalloc(sizeof(struct nouveau_hw_mode), GFP_KERNEL); + if (!output->native_mode) { + rval = -ENOMEM; + goto out; + } /* Set function pointers. */ output->validate_mode = nv50_sor_validate_mode; @@ -200,5 +210,5 @@ out: kfree(output->native_mode); if (dev_priv->free_output) dev_priv->free_output(output); - return -EINVAL; + return rval; } -- cgit v1.2.3 From 7c9551a464e168279224139b70a439f985b601c9 Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Sun, 22 Jun 2008 18:58:04 +0200 Subject: fix typo --- linux-core/nv50_crtc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-core/nv50_crtc.c b/linux-core/nv50_crtc.c index f34e7279..887d6ec2 100644 --- a/linux-core/nv50_crtc.c +++ b/linux-core/nv50_crtc.c @@ -489,7 +489,7 @@ int nv50_crtc_create(struct drm_device *dev, int index) crtc->mode = kzalloc(sizeof(struct nouveau_hw_mode), GFP_KERNEL); crtc->native_mode = kzalloc(sizeof(struct nouveau_hw_mode), GFP_KERNEL); - if (!crtc->mode || crtc->native_mode) { + if (!crtc->mode || !crtc->native_mode) { rval = -ENOMEM; goto out; } -- cgit v1.2.3 From b0b0f374432ecf84b5115130caa4697d6d1ca789 Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Sun, 22 Jun 2008 19:04:22 +0200 Subject: NV50: Fix a few more possible leaks. --- linux-core/nv50_lut.c | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/linux-core/nv50_lut.c b/linux-core/nv50_lut.c index cb52f27f..5cdf6b5d 100644 --- a/linux-core/nv50_lut.c +++ b/linux-core/nv50_lut.c @@ -34,6 +34,7 @@ static int nv50_lut_alloc(struct nv50_crtc *crtc) struct mem_block *block; struct drm_file *file_priv = kzalloc(sizeof(struct drm_file), GFP_KERNEL); uint32_t flags = NOUVEAU_MEM_INTERNAL | NOUVEAU_MEM_FB | NOUVEAU_MEM_MAPPED; + int rval = 0; NV50_DEBUG("\n"); @@ -43,12 +44,20 @@ static int nv50_lut_alloc(struct nv50_crtc *crtc) /* Any file_priv should do as it's pointer is used as identification. */ block = nouveau_mem_alloc(crtc->dev, 0, 4096, flags, file_priv); - if (!block) - return -ENOMEM; + if (!block) { + rval = -ENOMEM; + goto out; + } crtc->lut->block = block; return 0; + +out: + if (file_priv) + kfree(file_priv); + + return rval; } static int nv50_lut_free(struct nv50_crtc *crtc) @@ -144,8 +153,9 @@ int nv50_lut_create(struct nv50_crtc *crtc) return -ENOMEM; rval = nv50_lut_alloc(crtc); - if (rval != 0) - return rval; + if (rval != 0) { + goto out; + } /* lut will be inited when fb is bound */ crtc->lut->depth = 0; @@ -154,6 +164,12 @@ int nv50_lut_create(struct nv50_crtc *crtc) crtc->lut->set = nv50_lut_set; return 0; + +out: + if (crtc->lut) + kfree(crtc->lut); + + return rval; } int nv50_lut_destroy(struct nv50_crtc *crtc) -- cgit v1.2.3 From 30f153a7c2a9bc69e615b7fff3fb060af0e3ed83 Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Sun, 22 Jun 2008 19:31:55 +0200 Subject: nouveau: disable KMS for pre-NV50 even when specifically enabled --- shared-core/nouveau_state.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/shared-core/nouveau_state.c b/shared-core/nouveau_state.c index 82591c64..9f8fc43d 100644 --- a/shared-core/nouveau_state.c +++ b/shared-core/nouveau_state.c @@ -557,6 +557,10 @@ int nouveau_load(struct drm_device *dev, unsigned long flags) return -EINVAL; } + /* For those who think they want to be funny. */ + if (dev_priv->card_type < NV_50) + dev->driver->driver_features &= ~DRIVER_MODESET; + /* Special flags */ if (dev->pci_device == 0x01a0) { dev_priv->flags |= NV_NFORCE; -- cgit v1.2.3 From 0a45f150669eaa2737d7485c9b68ea4c483f3048 Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Mon, 23 Jun 2008 20:33:32 +0200 Subject: NV50: Improve set_config and fix some minor bugs. --- linux-core/nv50_crtc.c | 47 ++--- linux-core/nv50_crtc.h | 1 + linux-core/nv50_display.c | 12 ++ linux-core/nv50_fb.c | 7 +- linux-core/nv50_fb.h | 2 + linux-core/nv50_kms_wrapper.c | 427 ++++++++++++++++++++++++++---------------- linux-core/nv50_sor.c | 4 + 7 files changed, 317 insertions(+), 183 deletions(-) diff --git a/linux-core/nv50_crtc.c b/linux-core/nv50_crtc.c index 887d6ec2..0bcf3058 100644 --- a/linux-core/nv50_crtc.c +++ b/linux-core/nv50_crtc.c @@ -72,7 +72,6 @@ static int nv50_crtc_execute_mode(struct nv50_crtc *crtc) uint32_t hsync_dur, vsync_dur, hsync_start_to_end, vsync_start_to_end; uint32_t hunk1, vunk1, vunk2a, vunk2b; uint32_t offset = crtc->index * 0x400; - uint32_t pitch; NV50_DEBUG("index %d\n", crtc->index); NV50_DEBUG("%s native mode\n", crtc->use_native_mode ? "using" : "not using"); @@ -119,12 +118,31 @@ static int nv50_crtc_execute_mode(struct nv50_crtc *crtc) if (hw_mode->flags & V_INTERLACE) { OUT_MODE(NV50_CRTC0_MODE_UNK2 + offset, (vunk2b - 1) << 16 | (vunk2a - 1)); } + + crtc->set_fb(crtc); + crtc->set_dither(crtc); + + /* This is the actual resolution of the mode. */ + OUT_MODE(NV50_CRTC0_REAL_RES + offset, (crtc->mode->vdisplay << 16) | crtc->mode->hdisplay); + OUT_MODE(NV50_CRTC0_SCALE_CENTER_OFFSET + offset, NV50_CRTC_SCALE_CENTER_OFFSET_VAL(0,0)); + + /* Maybe move this as well? */ + crtc->blank(crtc, FALSE); + + return 0; +} + +static int nv50_crtc_set_fb(struct nv50_crtc *crtc) +{ + struct drm_nouveau_private *dev_priv = crtc->dev->dev_private; + uint32_t offset = crtc->index * 0x400; + + NV50_DEBUG("\n"); + OUT_MODE(NV50_CRTC0_FB_SIZE + offset, crtc->fb->height << 16 | crtc->fb->width); /* I suspect this flag indicates a linear fb. */ - pitch = ((crtc->fb->width + 63) & ~63) * (crtc->fb->bpp)/8; - NV50_DEBUG("fb_pitch %d\n", pitch); - OUT_MODE(NV50_CRTC0_FB_PITCH + offset, pitch | 0x100000); + OUT_MODE(NV50_CRTC0_FB_PITCH + offset, crtc->fb->pitch | 0x100000); switch (crtc->fb->depth) { case 8: @@ -140,15 +158,9 @@ static int nv50_crtc_execute_mode(struct nv50_crtc *crtc) OUT_MODE(NV50_CRTC0_DEPTH + offset, NV50_CRTC0_DEPTH_24BPP); break; } - crtc->set_dither(crtc); + OUT_MODE(NV50_CRTC0_COLOR_CTRL + offset, NV50_CRTC_COLOR_CTRL_MODE_COLOR); OUT_MODE(NV50_CRTC0_FB_POS + offset, (crtc->fb->y << 16) | (crtc->fb->x)); - /* This is the actual resolution of the mode. */ - OUT_MODE(NV50_CRTC0_REAL_RES + offset, (crtc->mode->vdisplay << 16) | crtc->mode->hdisplay); - OUT_MODE(NV50_CRTC0_SCALE_CENTER_OFFSET + offset, NV50_CRTC_SCALE_CENTER_OFFSET_VAL(0,0)); - - /* Maybe move this as well? */ - crtc->blank(crtc, FALSE); return 0; } @@ -178,20 +190,8 @@ static int nv50_crtc_blank(struct nv50_crtc *crtc, bool blanked) if (dev_priv->chipset != 0x50) OUT_MODE(NV84_CRTC0_BLANK_UNK2 + offset, NV84_CRTC0_BLANK_UNK2_BLANK); } else { - uint32_t ram_amount; - OUT_MODE(NV50_CRTC0_FB_OFFSET + offset, crtc->fb->block->start >> 8); OUT_MODE(0x864 + offset, 0); - /* maybe this needs to be moved. */ - NV_WRITE(NV50_PDISPLAY_UNK_380, 0); - /* RAM is clamped to 256 MiB. */ - ram_amount = nouveau_mem_fb_amount(crtc->dev); - NV50_DEBUG("ram_amount %d\n", ram_amount); - if (ram_amount > 256*1024*1024) - ram_amount = 256*1024*1024; - NV_WRITE(NV50_PDISPLAY_RAM_AMOUNT, ram_amount - 1); - NV_WRITE(NV50_PDISPLAY_UNK_388, 0x150000); - NV_WRITE(NV50_PDISPLAY_UNK_38C, 0); if (crtc->cursor->block) OUT_MODE(NV50_CRTC0_CURSOR_OFFSET + offset, crtc->cursor->block->start >> 8); else @@ -502,6 +502,7 @@ int nv50_crtc_create(struct drm_device *dev, int index) crtc->validate_mode = nv50_crtc_validate_mode; crtc->set_mode = nv50_crtc_set_mode; crtc->execute_mode = nv50_crtc_execute_mode; + crtc->set_fb = nv50_crtc_set_fb; crtc->blank = nv50_crtc_blank; crtc->set_dither = nv50_crtc_set_dither; crtc->set_scale = nv50_crtc_set_scale; diff --git a/linux-core/nv50_crtc.h b/linux-core/nv50_crtc.h index 5eb815a5..0eadc3d4 100644 --- a/linux-core/nv50_crtc.h +++ b/linux-core/nv50_crtc.h @@ -54,6 +54,7 @@ struct nv50_crtc { int (*validate_mode) (struct nv50_crtc *crtc, struct nouveau_hw_mode *mode); int (*set_mode) (struct nv50_crtc *crtc, struct nouveau_hw_mode *mode); int (*execute_mode) (struct nv50_crtc *crtc); + int (*set_fb) (struct nv50_crtc *crtc); int (*blank) (struct nv50_crtc *crtc, bool blanked); int (*set_dither) (struct nv50_crtc *crtc); int (*set_scale) (struct nv50_crtc *crtc); diff --git a/linux-core/nv50_display.c b/linux-core/nv50_display.c index 05ff72f8..0c82ff8f 100644 --- a/linux-core/nv50_display.c +++ b/linux-core/nv50_display.c @@ -34,6 +34,7 @@ static int nv50_display_pre_init(struct nv50_display *display) struct drm_device *dev = display->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; int i; + uint32_t ram_amount; NV50_DEBUG("\n"); @@ -67,6 +68,17 @@ static int nv50_display_pre_init(struct nv50_display *display) NV_WRITE(NV50_PDISPLAY_DAC_REGS_CLK_CTRL1(i), 0x00000001); } + /* This used to be in crtc unblank, but seems out of place there. */ + NV_WRITE(NV50_PDISPLAY_UNK_380, 0); + /* RAM is clamped to 256 MiB. */ + ram_amount = nouveau_mem_fb_amount(display->dev); + NV50_DEBUG("ram_amount %d\n", ram_amount); + if (ram_amount > 256*1024*1024) + ram_amount = 256*1024*1024; + NV_WRITE(NV50_PDISPLAY_RAM_AMOUNT, ram_amount - 1); + NV_WRITE(NV50_PDISPLAY_UNK_388, 0x150000); + NV_WRITE(NV50_PDISPLAY_UNK_38C, 0); + display->preinit_done = TRUE; return 0; diff --git a/linux-core/nv50_fb.c b/linux-core/nv50_fb.c index f57a9fad..153899da 100644 --- a/linux-core/nv50_fb.c +++ b/linux-core/nv50_fb.c @@ -40,8 +40,9 @@ static int nv50_fb_bind(struct nv50_crtc *crtc, struct nv50_fb_info *info) return -EINVAL; } - if (!info->block || !info->width || !info->height || !info->depth || !info->bpp) { - DRM_ERROR("block %p width %d height %d depth %d bpp %d\n", info->block, info->width, info->height, info->depth, info->bpp); + if (!info->block || !info->width || !info->height || !info->depth || !info->bpp || !info->pitch) { + DRM_ERROR("block %p width %d height %d depth %d bpp %d pitch %d\n", info->block, info->width, + info->height, info->depth, info->bpp, info->pitch); return -EINVAL; } @@ -55,6 +56,8 @@ static int nv50_fb_bind(struct nv50_crtc *crtc, struct nv50_fb_info *info) crtc->fb->depth = info->depth; crtc->fb->bpp = info->bpp; + crtc->fb->pitch = info->pitch; + /* update lut if needed */ if (crtc->fb->depth != crtc->lut->depth) { int r_size = 0, g_size = 0, b_size = 0; diff --git a/linux-core/nv50_fb.h b/linux-core/nv50_fb.h index 6b286315..3051dc5c 100644 --- a/linux-core/nv50_fb.h +++ b/linux-core/nv50_fb.h @@ -35,6 +35,7 @@ struct nv50_fb_info { struct mem_block *block; int width, height; int bpp, depth; + int pitch; int x,y; }; @@ -42,6 +43,7 @@ struct nv50_fb { struct mem_block *block; int width, height; int bpp, depth; + int pitch; int x,y; diff --git a/linux-core/nv50_kms_wrapper.c b/linux-core/nv50_kms_wrapper.c index a63cb7df..e93a2668 100644 --- a/linux-core/nv50_kms_wrapper.c +++ b/linux-core/nv50_kms_wrapper.c @@ -284,12 +284,17 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) struct nouveau_hw_mode *hw_mode = NULL; struct nv50_fb_info fb_info; + bool blank = false; + bool switch_fb = false; + bool modeset = false; + NV50_DEBUG("\n"); /* - * Initial approach is very simple, always set a mode. - * Always bail out completely if something is wrong. - * Later this could be extended to be more smart. + * Supported operations: + * - Switch mode. + * - Switch framebuffer. + * - Blank screen. */ /* Sanity checking */ @@ -298,138 +303,200 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) goto out; } - if (!set->crtc || !set->fb || !set->mode || !set->connectors) { + if (!set->crtc || !set->connectors) { NV50_DEBUG("Sanity check failed\n"); goto out; } + if (set->mode) { + if (set->fb) { + if (!drm_mode_equal(set->mode, &set->crtc->mode)) + modeset = true; + + if (set->fb != set->crtc->fb) + switch_fb = true; + + if (set->x != set->crtc->x || set->y != set->crtc->y) + switch_fb = true; + } + } else { + blank = true; + } + + if (!modeset && !switch_fb && !blank) { + DRM_ERROR("There is nothing to do, bad input.\n"); + goto out; + } + /* Basic variable setting */ dev = set->crtc->dev; dev_priv = dev->dev_private; display = nv50_get_display(dev); crtc = to_nv50_crtc(set->crtc); - /* Mode validation */ - hw_mode = nv50_kms_to_hw_mode(set->mode); - - rval = crtc->validate_mode(crtc, hw_mode); - - if (rval != MODE_OK) { - NV50_DEBUG("Mode not ok\n"); - goto out; - } + /** + * Wiring up the encoders and connectors. + */ - for (i = 0; i < set->num_connectors; i++) { - drm_connector = set->connectors[i]; - if (!drm_connector) { - NV50_DEBUG("No connector\n"); - goto out; - } - connector = to_nv50_connector(drm_connector); + if (modeset) { + /* Mode validation */ + hw_mode = nv50_kms_to_hw_mode(set->mode); - output = connector->to_output(connector, connector->digital); - if (!output) { - NV50_DEBUG("No output\n"); - goto out; - } + rval = crtc->validate_mode(crtc, hw_mode); - rval = output->validate_mode(output, hw_mode); if (rval != MODE_OK) { NV50_DEBUG("Mode not ok\n"); goto out; } - } - /* Validation done, move on to cleaning of existing structures. */ + for (i = 0; i < set->num_connectors; i++) { + drm_connector = set->connectors[i]; + if (!drm_connector) { + NV50_DEBUG("No connector\n"); + goto out; + } + connector = to_nv50_connector(drm_connector); - /* find encoders that use this crtc. */ - list_for_each_entry(drm_encoder, &dev->mode_config.encoder_list, head) { - if (drm_encoder->crtc == set->crtc) { - /* find the connector that goes with it */ - list_for_each_entry(drm_connector, &dev->mode_config.connector_list, head) { - if (drm_connector->encoder == drm_encoder) { - drm_connector->encoder = NULL; - break; - } + output = connector->to_output(connector, connector->digital); + if (!output) { + NV50_DEBUG("No output\n"); + goto out; } - drm_encoder->crtc = NULL; - } - } - /* now find if our desired encoders or connectors are in use already. */ - for (i = 0; i < set->num_connectors; i++) { - drm_connector = set->connectors[i]; - if (!drm_connector) { - NV50_DEBUG("No connector\n"); - goto out; + rval = output->validate_mode(output, hw_mode); + if (rval != MODE_OK) { + NV50_DEBUG("Mode not ok\n"); + goto out; + } } - if (!drm_connector->encoder) - continue; + /* Validation done, move on to cleaning of existing structures. */ + + /* find encoders that use this crtc. */ + list_for_each_entry(drm_encoder, &dev->mode_config.encoder_list, head) { + if (drm_encoder->crtc == set->crtc) { + /* find the connector that goes with it */ + list_for_each_entry(drm_connector, &dev->mode_config.connector_list, head) { + if (drm_connector->encoder == drm_encoder) { + drm_connector->encoder = NULL; + break; + } + } + drm_encoder->crtc = NULL; + } + } - drm_encoder = drm_connector->encoder; - drm_connector->encoder = NULL; + /* now find if our desired encoders or connectors are in use already. */ + for (i = 0; i < set->num_connectors; i++) { + drm_connector = set->connectors[i]; + if (!drm_connector) { + NV50_DEBUG("No connector\n"); + goto out; + } - if (!drm_encoder->crtc) - continue; + if (!drm_connector->encoder) + continue; - drm_crtc = drm_encoder->crtc; - drm_encoder->crtc = NULL; + drm_encoder = drm_connector->encoder; + drm_connector->encoder = NULL; - crtc = to_nv50_crtc(drm_crtc); - crtc->active = false; - drm_crtc->enabled = false; - } + if (!drm_encoder->crtc) + continue; - /* set framebuffer */ - set->crtc->fb = set->fb; + drm_crtc = drm_encoder->crtc; + drm_encoder->crtc = NULL; - /* Time to wire up the public encoder, the private one will be handled later. */ - for (i = 0; i < set->num_connectors; i++) { - drm_connector = set->connectors[i]; - if (!drm_connector) { - NV50_DEBUG("No connector\n"); - goto out; + crtc = to_nv50_crtc(drm_crtc); + crtc->active = false; + drm_crtc->enabled = false; } - output = connector->to_output(connector, connector->digital); - if (!output) { - NV50_DEBUG("No output\n"); - goto out; - } + /* Time to wire up the public encoder, the private one will be handled later. */ + for (i = 0; i < set->num_connectors; i++) { + drm_connector = set->connectors[i]; + if (!drm_connector) { + NV50_DEBUG("No connector\n"); + goto out; + } - /* find the encoder public structure that matches out output structure. */ - drm_encoder = to_nv50_kms_encoder(output); + output = connector->to_output(connector, connector->digital); + if (!output) { + NV50_DEBUG("No output\n"); + goto out; + } - if (!drm_encoder) { - NV50_DEBUG("No encoder\n"); - goto out; + /* find the encoder public structure that matches out output structure. */ + drm_encoder = to_nv50_kms_encoder(output); + + if (!drm_encoder) { + NV50_DEBUG("No encoder\n"); + goto out; + } + + drm_encoder->crtc = set->crtc; + drm_connector->encoder = drm_encoder; } + } + + /** + * Unwire encoders and connectors, etc. + */ + if (blank) { + crtc = to_nv50_crtc(drm_crtc); - drm_encoder->crtc = set->crtc; - drm_connector->encoder = drm_encoder; + crtc->active = false; + set->crtc->enabled = false; + + /* find encoders that use this crtc. */ + list_for_each_entry(drm_encoder, &dev->mode_config.encoder_list, head) { + if (drm_encoder->crtc == set->crtc) { + /* find the connector that goes with it */ + list_for_each_entry(drm_connector, &dev->mode_config.connector_list, head) { + if (drm_connector->encoder == drm_encoder) { + drm_connector->encoder = NULL; + break; + } + } + drm_encoder->crtc = NULL; + } + } } + /** + * All state should now be updated, now onto the real work. + */ + /* mirror everything to the private structs */ nv50_kms_mirror_routing(dev); - /* set private framebuffer */ - crtc = to_nv50_crtc(set->crtc); - fb_info.block = find_block_by_handle(dev_priv->fb_heap, set->fb->mm_handle); - fb_info.width = set->fb->width; - fb_info.height = set->fb->height; - fb_info.depth = set->fb->depth; - fb_info.bpp = set->fb->bits_per_pixel; - fb_info.x = set->x; - fb_info.y = set->y; - - rval = crtc->fb->bind(crtc, &fb_info); - if (rval != 0) { - NV50_DEBUG("fb_bind failed\n"); - goto out; + /** + * Bind framebuffer. + */ + + if (switch_fb) { + /* set framebuffer */ + set->crtc->fb = set->fb; + + /* set private framebuffer */ + crtc = to_nv50_crtc(set->crtc); + fb_info.block = find_block_by_handle(dev_priv->fb_heap, set->fb->mm_handle); + fb_info.width = set->fb->width; + fb_info.height = set->fb->height; + fb_info.depth = set->fb->depth; + fb_info.bpp = set->fb->bits_per_pixel; + fb_info.pitch = set->fb->pitch; + fb_info.x = set->x; + fb_info.y = set->y; + + rval = crtc->fb->bind(crtc, &fb_info); + if (rval != 0) { + NV50_DEBUG("fb_bind failed\n"); + goto out; + } } + /* this is !cursor_show */ if (!crtc->cursor->enabled) { rval = crtc->cursor->enable(crtc); if (rval != 0) { @@ -438,74 +505,119 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) } } - /* modeset time, finally */ + /** + * Blanking. + */ - /* disconnect unused outputs */ - list_for_each_entry(output, &display->outputs, head) { - if (output->crtc) - crtc_mask |= 1 << output->crtc->index; - else - output->execute_mode(output, TRUE); - } + if (blank) { + crtc = to_nv50_crtc(set->crtc); - rval = crtc->set_mode(crtc, hw_mode); - if (rval != 0) { - NV50_DEBUG("crtc mode set failed\n"); - goto out; + rval = crtc->blank(crtc, TRUE); + if (rval != 0) { + DRM_ERROR("blanking failed\n"); + goto out; + } } - /* find native mode. */ - list_for_each_entry(output, &display->outputs, head) { - if (output->crtc != crtc) - continue; + /** + * Change framebuffer, without changing mode. + */ - *crtc->native_mode = *output->native_mode; - list_for_each_entry(connector, &display->connectors, head) { - if (connector->output != output) - continue; + if (switch_fb && !modeset) { + crtc = to_nv50_crtc(set->crtc); - crtc->scaling_mode = connector->scaling_mode; - break; + rval = crtc->blank(crtc, TRUE); + if (rval != 0) { + DRM_ERROR("blanking failed\n"); + goto out; } - if (crtc->scaling_mode == SCALE_PANEL) - crtc->use_native_mode = false; - else - crtc->use_native_mode = true; + rval = crtc->set_fb(crtc); + if (rval != 0) { + DRM_ERROR("set_fb failed\n"); + goto out; + } - break; /* no use in finding more than one mode */ + /* this also sets the fb offset */ + rval = crtc->blank(crtc, FALSE); + if (rval != 0) { + DRM_ERROR("unblanking failed\n"); + goto out; + } } - rval = crtc->execute_mode(crtc); - if (rval != 0) { - NV50_DEBUG("crtc execute mode failed\n"); - goto out; - } + /** + * Normal modesetting. + */ - list_for_each_entry(output, &display->outputs, head) { - if (output->crtc != crtc) - continue; + if (modeset) { + /* disconnect unused outputs */ + list_for_each_entry(output, &display->outputs, head) { + if (output->crtc) + crtc_mask |= 1 << output->crtc->index; + else + output->execute_mode(output, TRUE); + } - rval = output->execute_mode(output, FALSE); + rval = crtc->set_mode(crtc, hw_mode); if (rval != 0) { - NV50_DEBUG("output execute mode failed\n"); + NV50_DEBUG("crtc mode set failed\n"); goto out; } - } - rval = crtc->set_scale(crtc); - if (rval != 0) { - NV50_DEBUG("crtc set scale failed\n"); - goto out; - } + /* find native mode. */ + list_for_each_entry(output, &display->outputs, head) { + if (output->crtc != crtc) + continue; - /* next line changes crtc, so putting it here is important */ - display->last_crtc = crtc->index; + *crtc->native_mode = *output->native_mode; + list_for_each_entry(connector, &display->connectors, head) { + if (connector->output != output) + continue; - /* blank any unused crtcs */ - list_for_each_entry(crtc, &display->crtcs, head) { - if (!(crtc_mask & (1 << crtc->index))) - crtc->blank(crtc, TRUE); + crtc->scaling_mode = connector->scaling_mode; + break; + } + + if (crtc->scaling_mode == SCALE_PANEL) + crtc->use_native_mode = false; + else + crtc->use_native_mode = true; + + break; /* no use in finding more than one mode */ + } + + rval = crtc->execute_mode(crtc); + if (rval != 0) { + NV50_DEBUG("crtc execute mode failed\n"); + goto out; + } + + list_for_each_entry(output, &display->outputs, head) { + if (output->crtc != crtc) + continue; + + rval = output->execute_mode(output, FALSE); + if (rval != 0) { + NV50_DEBUG("output execute mode failed\n"); + goto out; + } + } + + rval = crtc->set_scale(crtc); + if (rval != 0) { + NV50_DEBUG("crtc set scale failed\n"); + goto out; + } + + /* next line changes crtc, so putting it here is important */ + display->last_crtc = crtc->index; + + /* blank any unused crtcs */ + list_for_each_entry(crtc, &display->crtcs, head) { + if (!(crtc_mask & (1 << crtc->index))) + crtc->blank(crtc, TRUE); + } } display->update(display); @@ -631,36 +743,35 @@ static int nv50_kms_encoders_init(struct drm_device *dev) void nv50_kms_connector_detect_all(struct drm_device *dev) { struct drm_connector *drm_connector = NULL; - enum drm_connector_status old, new; - bool notify = false; list_for_each_entry(drm_connector, &dev->mode_config.connector_list, head) { - old = drm_connector->status; - new = drm_connector->funcs->detect(drm_connector); - - if (new != old) { - notify = true; - drm_connector->funcs->fill_modes(drm_connector, 0, 0); - } + drm_connector->funcs->detect(drm_connector); } - - /* I think this is the hook that notifies of changes. */ - if (notify) - dev->mode_config.funcs->fb_changed(dev); } static enum drm_connector_status nv50_kms_connector_detect(struct drm_connector *drm_connector) { struct nv50_connector *connector = to_nv50_connector(drm_connector); + struct drm_device *dev = drm_connector->dev; bool connected; + int old_status; connected = connector->detect(connector); + old_status = drm_connector->status; + if (connected) drm_connector->status = connector_status_connected; else drm_connector->status = connector_status_disconnected; + /* update our modes whenever there is reason to */ + if (old_status != drm_connector->status) { + drm_connector->funcs->fill_modes(drm_connector, 0, 0); + /* notify fb of changes */ + dev->mode_config.funcs->fb_changed(dev); + } + return drm_connector->status; } @@ -695,7 +806,7 @@ static void nv50_kms_connector_fill_modes(struct drm_connector *drm_connector, u struct drm_display_mode *mode, *t; struct edid *edid = NULL; - DRM_DEBUG("%s\n", drm_get_connector_name(drm_connector)); + NV50_DEBUG("%s\n", drm_get_connector_name(drm_connector)); /* set all modes to the unverified state */ list_for_each_entry_safe(mode, t, &drm_connector->modes, head) mode->status = MODE_UNVERIFIED; @@ -708,7 +819,7 @@ static void nv50_kms_connector_fill_modes(struct drm_connector *drm_connector, u drm_connector->status = connector_status_disconnected; if (!connected) { - DRM_DEBUG("%s is disconnected\n", drm_get_connector_name(drm_connector)); + NV50_DEBUG("%s is disconnected\n", drm_get_connector_name(drm_connector)); /* TODO set EDID to NULL */ return; } @@ -762,7 +873,7 @@ static void nv50_kms_connector_fill_modes(struct drm_connector *drm_connector, u struct nouveau_hw_mode *hw_mode; struct nv50_output *output; - DRM_DEBUG("No valid modes on %s\n", drm_get_connector_name(drm_connector)); + NV50_DEBUG("No valid modes on %s\n", drm_get_connector_name(drm_connector)); /* Should we do this here ??? * When no valid EDID modes are available we end up @@ -787,7 +898,7 @@ static void nv50_kms_connector_fill_modes(struct drm_connector *drm_connector, u drm_mode_sort(&drm_connector->modes); - DRM_DEBUG("Probed modes for %s\n", drm_get_connector_name(drm_connector)); + NV50_DEBUG("Probed modes for %s\n", drm_get_connector_name(drm_connector)); list_for_each_entry_safe(mode, t, &drm_connector->modes, head) { mode->vrefresh = drm_mode_vrefresh(mode); diff --git a/linux-core/nv50_sor.c b/linux-core/nv50_sor.c index 49f29fd3..75909c82 100644 --- a/linux-core/nv50_sor.c +++ b/linux-core/nv50_sor.c @@ -100,6 +100,10 @@ static int nv50_sor_set_clock_mode(struct nv50_output *output) NV50_DEBUG("or %d\n", nv50_output_or_offset(output)); + /* We don't yet know what to do, if anything at all. */ + if (output->type == OUTPUT_LVDS) + return 0; + if (crtc->use_native_mode) hw_mode = crtc->native_mode; else -- cgit v1.2.3 From f9dad8cc22994e0e4671d14b3ee721e4b5777a68 Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Mon, 23 Jun 2008 21:15:54 +0200 Subject: libdrm: check for allocation failure --- libdrm/xf86drmMode.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libdrm/xf86drmMode.c b/libdrm/xf86drmMode.c index a393f965..df865415 100644 --- a/libdrm/xf86drmMode.c +++ b/libdrm/xf86drmMode.c @@ -419,6 +419,9 @@ drmModeConnectorPtr drmModeGetConnector(int fd, uint32_t connector_id) r->connector_type = conn.connector_type; r->connector_type_id = conn.connector_type_id; + if (!r->props || !r->prop_values || !r->modes || !r->encoders) + goto err_allocs; + err_allocs: drmFree(U642VOID(conn.prop_values_ptr)); drmFree(U642VOID(conn.props_ptr)); -- cgit v1.2.3 From 246b41fea462a3b1669c0e3f9fe7f6077a479832 Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Mon, 23 Jun 2008 22:59:17 +0200 Subject: [modesetting-101] update mode count after fill_modes. - This avoids returning with a mode count of 0, thus not allocating space for the 2nd ioctl. --- linux-core/drm_crtc.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index c8cfaef4..aab936c2 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -1018,9 +1018,6 @@ int drm_mode_getconnector(struct drm_device *dev, } connector = obj_to_connector(obj); - list_for_each_entry(mode, &connector->modes, head) - mode_count++; - for (i = 0; i < DRM_CONNECTOR_MAX_PROPERTY; i++) { if (connector->property_ids[i] != 0) { props_count++; @@ -1037,6 +1034,10 @@ int drm_mode_getconnector(struct drm_device *dev, connector->funcs->fill_modes(connector, dev->mode_config.max_width, dev->mode_config.max_height); } + /* delayed so we get modes regardless of pre-fill_modes state */ + list_for_each_entry(mode, &connector->modes, head) + mode_count++; + out_resp->generation = dev->mode_config.current_generation; out_resp->connector_type = connector->connector_type; out_resp->connector_type_id = connector->connector_type_id; @@ -1049,6 +1050,7 @@ int drm_mode_getconnector(struct drm_device *dev, else out_resp->encoder = 0; + /* this ioctl is called twice, once to determine how much space is needed, and the 2nd time to fill it */ if ((out_resp->count_modes >= mode_count) && mode_count) { copied = 0; mode_ptr = (struct drm_mode_modeinfo *)(unsigned long)out_resp->modes_ptr; @@ -1060,7 +1062,6 @@ int drm_mode_getconnector(struct drm_device *dev, goto out; } copied++; - } } out_resp->count_modes = mode_count; -- cgit v1.2.3 From 5072a2911e134bb3fec06a6d7011a92e714a9953 Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Tue, 24 Jun 2008 00:00:02 +0200 Subject: NV50: fix some misc bugs --- linux-core/nv50_kms_wrapper.c | 55 ++++++++++++++++++++++++++----------------- 1 file changed, 33 insertions(+), 22 deletions(-) diff --git a/linux-core/nv50_kms_wrapper.c b/linux-core/nv50_kms_wrapper.c index e93a2668..739704b5 100644 --- a/linux-core/nv50_kms_wrapper.c +++ b/linux-core/nv50_kms_wrapper.c @@ -303,7 +303,7 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) goto out; } - if (!set->crtc || !set->connectors) { + if (!set->crtc) { NV50_DEBUG("Sanity check failed\n"); goto out; } @@ -323,6 +323,11 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) blank = true; } + if (!set->connectors && modeset) { + NV50_DEBUG("Sanity check failed\n"); + goto out; + } + if (!modeset && !switch_fb && !blank) { DRM_ERROR("There is nothing to do, bad input.\n"); goto out; @@ -439,28 +444,15 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) } /** - * Unwire encoders and connectors, etc. + * Disable crtc. */ if (blank) { - crtc = to_nv50_crtc(drm_crtc); + crtc = to_nv50_crtc(set->crtc); + /* keeping the encoders and connectors attached, so they can be tracked */ crtc->active = false; set->crtc->enabled = false; - - /* find encoders that use this crtc. */ - list_for_each_entry(drm_encoder, &dev->mode_config.encoder_list, head) { - if (drm_encoder->crtc == set->crtc) { - /* find the connector that goes with it */ - list_for_each_entry(drm_connector, &dev->mode_config.connector_list, head) { - if (drm_connector->encoder == drm_encoder) { - drm_connector->encoder = NULL; - break; - } - } - drm_encoder->crtc = NULL; - } - } } /** @@ -517,13 +509,26 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) DRM_ERROR("blanking failed\n"); goto out; } + + /* detach any outputs that are currently running on this crtc */ + list_for_each_entry(drm_encoder, &dev->mode_config.encoder_list, head) { + if (drm_encoder->crtc == set->crtc) { + output = to_nv50_output(drm_encoder); + + rval = output->execute_mode(output, TRUE); + if (rval != 0) { + DRM_ERROR("detaching output failed\n"); + goto out; + } + } + } } /** * Change framebuffer, without changing mode. */ - if (switch_fb && !modeset) { + if (switch_fb && !modeset && !blank) { crtc = to_nv50_crtc(set->crtc); rval = crtc->blank(crtc, TRUE); @@ -553,10 +558,15 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) if (modeset) { /* disconnect unused outputs */ list_for_each_entry(output, &display->outputs, head) { - if (output->crtc) + if (output->crtc) { crtc_mask |= 1 << output->crtc->index; - else - output->execute_mode(output, TRUE); + } else { + rval = output->execute_mode(output, TRUE); + if (rval != 0) { + DRM_ERROR("detaching output failed\n"); + goto out; + } + } } rval = crtc->set_mode(crtc, hw_mode); @@ -627,7 +637,8 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) return 0; out: - display->update(display); + if (display) + display->update(display); kfree(hw_mode); -- cgit v1.2.3 From e7582cfff6cb561d8bdfcd640d6843cdbb6b3391 Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Tue, 24 Jun 2008 09:41:13 +0200 Subject: NV50: These are actually errors. --- linux-core/nv50_kms_wrapper.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/linux-core/nv50_kms_wrapper.c b/linux-core/nv50_kms_wrapper.c index 739704b5..529a9055 100644 --- a/linux-core/nv50_kms_wrapper.c +++ b/linux-core/nv50_kms_wrapper.c @@ -299,12 +299,12 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) /* Sanity checking */ if (!set) { - NV50_DEBUG("Sanity check failed\n"); + DRM_ERROR("Sanity check failed\n"); goto out; } if (!set->crtc) { - NV50_DEBUG("Sanity check failed\n"); + DRM_ERROR("Sanity check failed\n"); goto out; } @@ -324,7 +324,7 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) } if (!set->connectors && modeset) { - NV50_DEBUG("Sanity check failed\n"); + DRM_ERROR("Sanity check failed\n"); goto out; } @@ -350,27 +350,27 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) rval = crtc->validate_mode(crtc, hw_mode); if (rval != MODE_OK) { - NV50_DEBUG("Mode not ok\n"); + DRM_ERROR("Mode not ok\n"); goto out; } for (i = 0; i < set->num_connectors; i++) { drm_connector = set->connectors[i]; if (!drm_connector) { - NV50_DEBUG("No connector\n"); + DRM_ERROR("No connector\n"); goto out; } connector = to_nv50_connector(drm_connector); output = connector->to_output(connector, connector->digital); if (!output) { - NV50_DEBUG("No output\n"); + DRM_ERROR("No output\n"); goto out; } rval = output->validate_mode(output, hw_mode); if (rval != MODE_OK) { - NV50_DEBUG("Mode not ok\n"); + DRM_ERROR("Mode not ok\n"); goto out; } } @@ -395,7 +395,7 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) for (i = 0; i < set->num_connectors; i++) { drm_connector = set->connectors[i]; if (!drm_connector) { - NV50_DEBUG("No connector\n"); + DRM_ERROR("No connector\n"); goto out; } @@ -420,13 +420,13 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) for (i = 0; i < set->num_connectors; i++) { drm_connector = set->connectors[i]; if (!drm_connector) { - NV50_DEBUG("No connector\n"); + DRM_ERROR("No connector\n"); goto out; } output = connector->to_output(connector, connector->digital); if (!output) { - NV50_DEBUG("No output\n"); + DRM_ERROR("No output\n"); goto out; } @@ -434,7 +434,7 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) drm_encoder = to_nv50_kms_encoder(output); if (!drm_encoder) { - NV50_DEBUG("No encoder\n"); + DRM_ERROR("No encoder\n"); goto out; } @@ -483,7 +483,7 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) rval = crtc->fb->bind(crtc, &fb_info); if (rval != 0) { - NV50_DEBUG("fb_bind failed\n"); + DRM_ERROR("fb_bind failed\n"); goto out; } } @@ -492,7 +492,7 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) if (!crtc->cursor->enabled) { rval = crtc->cursor->enable(crtc); if (rval != 0) { - NV50_DEBUG("cursor_enable failed\n"); + DRM_ERROR("cursor_enable failed\n"); goto out; } } @@ -571,7 +571,7 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) rval = crtc->set_mode(crtc, hw_mode); if (rval != 0) { - NV50_DEBUG("crtc mode set failed\n"); + DRM_ERROR("crtc mode set failed\n"); goto out; } @@ -599,7 +599,7 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) rval = crtc->execute_mode(crtc); if (rval != 0) { - NV50_DEBUG("crtc execute mode failed\n"); + DRM_ERROR("crtc execute mode failed\n"); goto out; } @@ -609,14 +609,14 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) rval = output->execute_mode(output, FALSE); if (rval != 0) { - NV50_DEBUG("output execute mode failed\n"); + DRM_ERROR("output execute mode failed\n"); goto out; } } rval = crtc->set_scale(crtc); if (rval != 0) { - NV50_DEBUG("crtc set scale failed\n"); + DRM_ERROR("crtc set scale failed\n"); goto out; } -- cgit v1.2.3 From 315fef7ee44f9ca565f158a6a84fd29b34e69fd8 Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Tue, 24 Jun 2008 10:16:52 +0200 Subject: NV50: fix cursor hide/show --- linux-core/nv50_cursor.c | 4 +--- linux-core/nv50_kms_wrapper.c | 21 ++++++++++++++++++--- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/linux-core/nv50_cursor.c b/linux-core/nv50_cursor.c index 4196df6b..47ae11bb 100644 --- a/linux-core/nv50_cursor.c +++ b/linux-core/nv50_cursor.c @@ -126,6 +126,7 @@ static int nv50_cursor_set_bo(struct nv50_crtc *crtc, drm_handle_t handle) crtc->cursor->show(crtc); } } else { + DRM_ERROR("Unable to find cursor bo with handle 0x%X\n", handle); return -EINVAL; } @@ -151,9 +152,6 @@ int nv50_cursor_create(struct nv50_crtc *crtc) crtc->cursor->enable = nv50_cursor_enable; crtc->cursor->disable = nv50_cursor_disable; - /* defaults */ - crtc->cursor->visible = true; /* won't happen until there is a cursor bo */ - return 0; } diff --git a/linux-core/nv50_kms_wrapper.c b/linux-core/nv50_kms_wrapper.c index 529a9055..b3d5ce65 100644 --- a/linux-core/nv50_kms_wrapper.c +++ b/linux-core/nv50_kms_wrapper.c @@ -233,20 +233,35 @@ static int nv50_kms_crtc_cursor_set(struct drm_crtc *drm_crtc, uint32_t buffer_h { struct nv50_crtc *crtc = to_nv50_crtc(drm_crtc); struct nv50_display *display = nv50_get_display(crtc->dev); - int rval; + int rval = 0; if (width != 64 || height != 64) return -EINVAL; - rval = crtc->cursor->set_bo(crtc, (drm_handle_t) buffer_handle); + /* set bo before doing show cursor */ + if (buffer_handle) { + rval = crtc->cursor->set_bo(crtc, (drm_handle_t) buffer_handle); + if (rval != 0) + goto out; + } + + if (buffer_handle) { + rval = crtc->cursor->show(crtc); + if (rval != 0) + goto out; + } else { /* no handle implies hiding the cursor */ + rval = crtc->cursor->hide(crtc); + goto out; + } if (rval != 0) return rval; +out: /* in case this triggers any other cursor changes */ display->update(display); - return 0; + return rval; } static int nv50_kms_crtc_cursor_move(struct drm_crtc *drm_crtc, int x, int y) -- cgit v1.2.3 From 14522b3e1bd1129333af7f1a16a436a5f90388ea Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Tue, 24 Jun 2008 12:38:57 +0200 Subject: NV50: fix a few misc things --- linux-core/nv50_kms_wrapper.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/linux-core/nv50_kms_wrapper.c b/linux-core/nv50_kms_wrapper.c index b3d5ce65..8b97882a 100644 --- a/linux-core/nv50_kms_wrapper.c +++ b/linux-core/nv50_kms_wrapper.c @@ -245,6 +245,8 @@ static int nv50_kms_crtc_cursor_set(struct drm_crtc *drm_crtc, uint32_t buffer_h goto out; } + crtc->cursor->visible = buffer_handle ? true : false; + if (buffer_handle) { rval = crtc->cursor->show(crtc); if (rval != 0) @@ -858,6 +860,7 @@ static void nv50_kms_connector_fill_modes(struct drm_connector *drm_connector, u drm_mode_connector_update_edid_property(drm_connector, edid); ret = drm_add_edid_modes(drm_connector, edid); connector->digital = edid->digital; /* cache */ + kfree(edid); } if (ret) /* number of modes > 1 */ -- cgit v1.2.3 From 5dbcb7551ff0b2c759f34ca85c30cfa95f33ba09 Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Tue, 24 Jun 2008 20:29:08 +0200 Subject: NV50: minor change --- linux-core/nv50_connector.c | 2 +- linux-core/nv50_sor.c | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/linux-core/nv50_connector.c b/linux-core/nv50_connector.c index d13622b7..a13f8e59 100644 --- a/linux-core/nv50_connector.c +++ b/linux-core/nv50_connector.c @@ -184,7 +184,7 @@ int nv50_connector_create(struct drm_device *dev, int bus, int i2c_index, int ty } /* some reasonable defaults */ - if (type == CONNECTOR_DVI_D || type == CONNECTOR_LVDS) + if (type == CONNECTOR_DVI_D || type == CONNECTOR_DVI_I || type == CONNECTOR_LVDS) connector->scaling_mode = SCALE_FULLSCREEN; else connector->scaling_mode = SCALE_PANEL; diff --git a/linux-core/nv50_sor.c b/linux-core/nv50_sor.c index 75909c82..fca9612f 100644 --- a/linux-core/nv50_sor.c +++ b/linux-core/nv50_sor.c @@ -83,8 +83,6 @@ static int nv50_sor_execute_mode(struct nv50_output *output, bool disconnect) if (desired_mode->flags & V_NVSYNC) mode_ctl |= NV50_SOR_MODE_CTRL_NVSYNC; - /* TODO: DPMS ?????? */ - OUT_MODE(NV50_SOR0_MODE_CTRL + offset, mode_ctl); return 0; -- cgit v1.2.3 From d55629a13d0f287e186e93a4828ef86b36678eba Mon Sep 17 00:00:00 2001 From: root Date: Tue, 24 Jun 2008 23:18:29 +0100 Subject: silence warning --- linux-core/intel_fb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index 64a8fc94..cbd22ba6 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -882,7 +882,7 @@ static int intelfb_single_fb_probe(struct drm_device *dev) struct intel_framebuffer *intel_fb; struct fb_info *info; struct intelfb_par *par; - struct drm_mode_set *modeset; + struct drm_mode_set *modeset = NULL; DRM_DEBUG("\n"); /* first up get a count of crtcs now in use and new min/maxes width/heights */ -- cgit v1.2.3 From 5a0164d1e1799b68b3131efd7b9fcaf20c578257 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Mon, 23 Jun 2008 01:00:42 +1000 Subject: nouveau: allocate drm-use vram buffers from end of vram. This avoids seeing garbage from engine setup etc before X gets around to pointing the CRTCs at a new scanout buffer. Not actually a noticable problem before G80 as PRAMIN is forced to the end of VRAM by the hardware already. --- shared-core/nouveau_drm.h | 4 ++- shared-core/nouveau_drv.h | 2 +- shared-core/nouveau_mem.c | 58 ++++++++++++++++++++++++++---------------- shared-core/nouveau_notifier.c | 2 +- shared-core/nouveau_object.c | 2 +- 5 files changed, 42 insertions(+), 26 deletions(-) diff --git a/shared-core/nouveau_drm.h b/shared-core/nouveau_drm.h index cf762052..bbb51bc4 100644 --- a/shared-core/nouveau_drm.h +++ b/shared-core/nouveau_drm.h @@ -88,9 +88,11 @@ struct drm_nouveau_gpuobj_free { #define NOUVEAU_MEM_INSTANCE 0x00000200 /* internal */ #define NOUVEAU_MEM_NOTIFIER 0x00000400 /* internal */ #define NOUVEAU_MEM_NOVM 0x00000800 /* internal */ +#define NOUVEAU_MEM_USER 0x00001000 /* internal */ #define NOUVEAU_MEM_INTERNAL (NOUVEAU_MEM_INSTANCE | \ NOUVEAU_MEM_NOTIFIER | \ - NOUVEAU_MEM_NOVM) + NOUVEAU_MEM_NOVM | \ + NOUVEAU_MEM_USER) struct drm_nouveau_mem_alloc { int flags; diff --git a/shared-core/nouveau_drv.h b/shared-core/nouveau_drv.h index 20aa6b86..33e2a5b6 100644 --- a/shared-core/nouveau_drv.h +++ b/shared-core/nouveau_drv.h @@ -375,7 +375,7 @@ extern int nouveau_mem_init_heap(struct mem_block **, uint64_t start, uint64_t size); extern struct mem_block *nouveau_mem_alloc_block(struct mem_block *, uint64_t size, int align2, - struct drm_file *); + struct drm_file *, int tail); extern void nouveau_mem_takedown(struct mem_block **heap); extern void nouveau_mem_free_block(struct mem_block *); extern struct mem_block* find_block_by_handle(struct mem_block *heap, drm_handle_t handle); diff --git a/shared-core/nouveau_mem.c b/shared-core/nouveau_mem.c index 810eaf9e..51ac48dd 100644 --- a/shared-core/nouveau_mem.c +++ b/shared-core/nouveau_mem.c @@ -35,8 +35,9 @@ #include "drm_sarea.h" #include "nouveau_drv.h" -static struct mem_block *split_block(struct mem_block *p, uint64_t start, uint64_t size, - struct drm_file *file_priv) +static struct mem_block * +split_block(struct mem_block *p, uint64_t start, uint64_t size, + struct drm_file *file_priv) { /* Maybe cut off the start of an existing block */ if (start > p->start) { @@ -77,10 +78,9 @@ out: return p; } -struct mem_block *nouveau_mem_alloc_block(struct mem_block *heap, - uint64_t size, - int align2, - struct drm_file *file_priv) +struct mem_block * +nouveau_mem_alloc_block(struct mem_block *heap, uint64_t size, + int align2, struct drm_file *file_priv, int tail) { struct mem_block *p; uint64_t mask = (1 << align2) - 1; @@ -88,10 +88,22 @@ struct mem_block *nouveau_mem_alloc_block(struct mem_block *heap, if (!heap) return NULL; - list_for_each(p, heap) { - uint64_t start = (p->start + mask) & ~mask; - if (p->file_priv == 0 && start + size <= p->start + p->size) - return split_block(p, start, size, file_priv); + if (tail) { + list_for_each_prev(p, heap) { + uint64_t start = ((p->start + p->size) - size) & ~mask; + + if (p->file_priv == 0 && start >= p->start && + start + size <= p->start + p->size) + return split_block(p, start, size, file_priv); + } + } else { + list_for_each(p, heap) { + uint64_t start = (p->start + mask) & ~mask; + + if (p->file_priv == 0 && + start + size <= p->start + p->size) + return split_block(p, start, size, file_priv); + } } return NULL; @@ -574,13 +586,13 @@ int nouveau_mem_init(struct drm_device *dev) return 0; } -struct mem_block* nouveau_mem_alloc(struct drm_device *dev, int alignment, - uint64_t size, int flags, - struct drm_file *file_priv) +struct mem_block * +nouveau_mem_alloc(struct drm_device *dev, int alignment, uint64_t size, + int flags, struct drm_file *file_priv) { - struct mem_block *block; - int type; struct drm_nouveau_private *dev_priv = dev->dev_private; + struct mem_block *block; + int type, tail = !(flags & NOUVEAU_MEM_USER); /* * Make things easier on ourselves: all allocations are page-aligned. @@ -611,14 +623,14 @@ struct mem_block* nouveau_mem_alloc(struct drm_device *dev, int alignment, #define NOUVEAU_MEM_ALLOC_AGP {\ type=NOUVEAU_MEM_AGP;\ block = nouveau_mem_alloc_block(dev_priv->agp_heap, size,\ - alignment, file_priv); \ + alignment, file_priv, tail); \ if (block) goto alloc_ok;\ } #define NOUVEAU_MEM_ALLOC_PCI {\ type = NOUVEAU_MEM_PCI;\ block = nouveau_mem_alloc_block(dev_priv->pci_heap, size, \ - alignment, file_priv); \ + alignment, file_priv, tail); \ if ( block ) goto alloc_ok;\ } @@ -627,11 +639,11 @@ struct mem_block* nouveau_mem_alloc(struct drm_device *dev, int alignment, if (!(flags&NOUVEAU_MEM_MAPPED)) {\ block = nouveau_mem_alloc_block(dev_priv->fb_nomap_heap,\ size, alignment, \ - file_priv); \ + file_priv, tail); \ if (block) goto alloc_ok;\ }\ block = nouveau_mem_alloc_block(dev_priv->fb_heap, size,\ - alignment, file_priv);\ + alignment, file_priv, tail);\ if (block) goto alloc_ok;\ } @@ -749,7 +761,9 @@ out_free: * Ioctls */ -int nouveau_ioctl_mem_alloc(struct drm_device *dev, void *data, struct drm_file *file_priv) +int +nouveau_ioctl_mem_alloc(struct drm_device *dev, void *data, + struct drm_file *file_priv) { struct drm_nouveau_mem_alloc *alloc = data; struct mem_block *block; @@ -759,8 +773,8 @@ int nouveau_ioctl_mem_alloc(struct drm_device *dev, void *data, struct drm_file if (alloc->flags & NOUVEAU_MEM_INTERNAL) return -EINVAL; - block=nouveau_mem_alloc(dev, alloc->alignment, alloc->size, - alloc->flags, file_priv); + block = nouveau_mem_alloc(dev, alloc->alignment, alloc->size, + alloc->flags | NOUVEAU_MEM_USER, file_priv); if (!block) return -ENOMEM; alloc->map_handle=block->map_handle; diff --git a/shared-core/nouveau_notifier.c b/shared-core/nouveau_notifier.c index 82c8ab7d..edece4da 100644 --- a/shared-core/nouveau_notifier.c +++ b/shared-core/nouveau_notifier.c @@ -94,7 +94,7 @@ nouveau_notifier_alloc(struct nouveau_channel *chan, uint32_t handle, } mem = nouveau_mem_alloc_block(chan->notifier_heap, count*32, 0, - (struct drm_file *)-2); + (struct drm_file *)-2, 0); if (!mem) { DRM_ERROR("Channel %d notifier block full\n", chan->id); return -ENOMEM; diff --git a/shared-core/nouveau_object.c b/shared-core/nouveau_object.c index 09f9027a..5664bfc8 100644 --- a/shared-core/nouveau_object.c +++ b/shared-core/nouveau_object.c @@ -248,7 +248,7 @@ nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan, /* Allocate a chunk of the PRAMIN aperture */ gpuobj->im_pramin = nouveau_mem_alloc_block(pramin, size, drm_order(align), - (struct drm_file *)-2); + (struct drm_file *)-2, 0); if (!gpuobj->im_pramin) { nouveau_gpuobj_del(dev, &gpuobj); return -ENOMEM; -- cgit v1.2.3 From be7276281694145e7c947b91a1c8e6e347de666c Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 25 Jun 2008 16:45:41 +1000 Subject: nv50: when destroying a channel make sure it's not still current on PFIFO We won't get a PFIFO context switch when the same channel ID is recreated if the hw still thinks the channel is already active, which causes fun issues. Should allow X to be stopped and started without tearing down the entire card state in lastclose(). --- shared-core/nv50_fifo.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/shared-core/nv50_fifo.c b/shared-core/nv50_fifo.c index edf4edbf..d6810666 100644 --- a/shared-core/nv50_fifo.c +++ b/shared-core/nv50_fifo.c @@ -289,6 +289,7 @@ void nv50_fifo_destroy_context(struct nouveau_channel *chan) { struct drm_device *dev = chan->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; DRM_DEBUG("ch%d\n", chan->id); @@ -298,6 +299,9 @@ nv50_fifo_destroy_context(struct nouveau_channel *chan) if (chan->id == 0) nv50_fifo_channel_disable(dev, 127, 0); + if ((NV_READ(NV03_PFIFO_CACHE1_PUSH1) & 0xffff) == chan->id) + NV_WRITE(NV03_PFIFO_CACHE1_PUSH1, 127); + nouveau_gpuobj_ref_del(dev, &chan->ramfc); } -- cgit v1.2.3 From 09b67dda0bc040860aedce4a2d28bce1c80e56d6 Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Wed, 25 Jun 2008 15:16:38 +0200 Subject: NV50: Some cleanup and fixes. --- linux-core/nv50_crtc.c | 10 ++++++---- linux-core/nv50_crtc.h | 1 + linux-core/nv50_cursor.c | 18 +++++++++++++++++- linux-core/nv50_cursor.h | 1 + shared-core/nouveau_mem.c | 29 +++++++++++++++++++++++++++++ 5 files changed, 54 insertions(+), 5 deletions(-) diff --git a/linux-core/nv50_crtc.c b/linux-core/nv50_crtc.c index 0bcf3058..af2f03d8 100644 --- a/linux-core/nv50_crtc.c +++ b/linux-core/nv50_crtc.c @@ -192,10 +192,9 @@ static int nv50_crtc_blank(struct nv50_crtc *crtc, bool blanked) } else { OUT_MODE(NV50_CRTC0_FB_OFFSET + offset, crtc->fb->block->start >> 8); OUT_MODE(0x864 + offset, 0); - if (crtc->cursor->block) - OUT_MODE(NV50_CRTC0_CURSOR_OFFSET + offset, crtc->cursor->block->start >> 8); - else - OUT_MODE(NV50_CRTC0_CURSOR_OFFSET + offset, 0); + + crtc->cursor->set_offset(crtc); + if (dev_priv->chipset != 0x50) OUT_MODE(NV84_CRTC0_BLANK_UNK2 + offset, NV84_CRTC0_BLANK_UNK2_UNBLANK); @@ -212,6 +211,9 @@ static int nv50_crtc_blank(struct nv50_crtc *crtc, bool blanked) OUT_MODE(NV50_CRTC0_BLANK_CTRL + offset, NV50_CRTC0_BLANK_CTRL_UNBLANK); } + /* sometimes you need to know if a screen is already blanked. */ + crtc->blanked = blanked; + return 0; } diff --git a/linux-core/nv50_crtc.h b/linux-core/nv50_crtc.h index 0eadc3d4..b63c5a22 100644 --- a/linux-core/nv50_crtc.h +++ b/linux-core/nv50_crtc.h @@ -39,6 +39,7 @@ struct nv50_crtc { struct drm_device *dev; int index; bool active; + bool blanked; struct nouveau_hw_mode *mode; struct nouveau_hw_mode *native_mode; diff --git a/linux-core/nv50_cursor.c b/linux-core/nv50_cursor.c index 47ae11bb..091c94fe 100644 --- a/linux-core/nv50_cursor.c +++ b/linux-core/nv50_cursor.c @@ -103,6 +103,21 @@ static int nv50_cursor_set_pos(struct nv50_crtc *crtc, int x, int y) return 0; } +static int nv50_cursor_set_offset(struct nv50_crtc *crtc) +{ + struct drm_nouveau_private *dev_priv = crtc->dev->dev_private; + + NV50_DEBUG("\n"); + + if (crtc->cursor->block) { + OUT_MODE(NV50_CRTC0_CURSOR_OFFSET + crtc->index * 0x400, crtc->cursor->block->start >> 8); + } else { + OUT_MODE(NV50_CRTC0_CURSOR_OFFSET + crtc->index * 0x400, 0); + } + + return 0; +} + static int nv50_cursor_set_bo(struct nv50_crtc *crtc, drm_handle_t handle) { struct mem_block *block = NULL; @@ -121,7 +136,7 @@ static int nv50_cursor_set_bo(struct nv50_crtc *crtc, drm_handle_t handle) /* set the cursor offset cursor */ if (first_time) { - OUT_MODE(NV50_CRTC0_CURSOR_OFFSET + crtc->index * 0x400, crtc->cursor->block->start >> 8); + crtc->cursor->set_offset(crtc); if (crtc->cursor->visible) crtc->cursor->show(crtc); } @@ -148,6 +163,7 @@ int nv50_cursor_create(struct nv50_crtc *crtc) crtc->cursor->show = nv50_cursor_show; crtc->cursor->hide = nv50_cursor_hide; crtc->cursor->set_pos = nv50_cursor_set_pos; + crtc->cursor->set_offset = nv50_cursor_set_offset; crtc->cursor->set_bo = nv50_cursor_set_bo; crtc->cursor->enable = nv50_cursor_enable; crtc->cursor->disable = nv50_cursor_disable; diff --git a/linux-core/nv50_cursor.h b/linux-core/nv50_cursor.h index a2e4632c..4fd0d39a 100644 --- a/linux-core/nv50_cursor.h +++ b/linux-core/nv50_cursor.h @@ -40,6 +40,7 @@ struct nv50_cursor { int (*show) (struct nv50_crtc *crtc); int (*hide) (struct nv50_crtc *crtc); int (*set_pos) (struct nv50_crtc *crtc, int x, int y); + int (*set_offset) (struct nv50_crtc *crtc); int (*set_bo) (struct nv50_crtc *crtc, drm_handle_t handle); int (*enable) (struct nv50_crtc *crtc); int (*disable) (struct nv50_crtc *crtc); diff --git a/shared-core/nouveau_mem.c b/shared-core/nouveau_mem.c index 51ac48dd..4acd6bd6 100644 --- a/shared-core/nouveau_mem.c +++ b/shared-core/nouveau_mem.c @@ -34,6 +34,8 @@ #include "drm.h" #include "drm_sarea.h" #include "nouveau_drv.h" +#include "nv50_kms_wrapper.h" + static struct mem_block * split_block(struct mem_block *p, uint64_t start, uint64_t size, @@ -730,6 +732,33 @@ void nouveau_mem_free(struct drm_device* dev, struct mem_block* block) DRM_DEBUG("freeing 0x%llx type=0x%08x\n", block->start, block->flags); + /* Check if the deallocations cause problems for our modesetting system. */ + if (drm_core_check_feature(dev, DRIVER_MODESET)) { + if (dev_priv->card_type >= NV_50) { + struct nv50_crtc *crtc = NULL; + struct nv50_display *display = nv50_get_display(dev); + + list_for_each_entry(crtc, &display->crtcs, head) { + if (crtc->fb->block == block) { + crtc->fb->block = NULL; + + /* this will force a lut change next time a fb is loaded */ + crtc->lut->depth = 0; + + if (!crtc->blanked) + crtc->blank(crtc, TRUE); + } + + if (crtc->cursor->block == block) { + crtc->cursor->block = NULL; + + if (crtc->cursor->visible) + crtc->cursor->hide(crtc); + } + } + } + } + if (block->flags&NOUVEAU_MEM_MAPPED) drm_rmmap(dev, block->map); -- cgit v1.2.3 From 4d85d5d25116304e476849ee64c206ffb3a7f372 Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Wed, 25 Jun 2008 15:27:07 +0200 Subject: NV50: i misunderstood NOUVEAU_MEM_INTERNAL, so remove it --- linux-core/nv50_lut.c | 2 +- shared-core/nouveau_mem.c | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/linux-core/nv50_lut.c b/linux-core/nv50_lut.c index 5cdf6b5d..7982a926 100644 --- a/linux-core/nv50_lut.c +++ b/linux-core/nv50_lut.c @@ -33,7 +33,7 @@ static int nv50_lut_alloc(struct nv50_crtc *crtc) { struct mem_block *block; struct drm_file *file_priv = kzalloc(sizeof(struct drm_file), GFP_KERNEL); - uint32_t flags = NOUVEAU_MEM_INTERNAL | NOUVEAU_MEM_FB | NOUVEAU_MEM_MAPPED; + uint32_t flags = NOUVEAU_MEM_FB | NOUVEAU_MEM_MAPPED; int rval = 0; NV50_DEBUG("\n"); diff --git a/shared-core/nouveau_mem.c b/shared-core/nouveau_mem.c index 4acd6bd6..46b6e4d6 100644 --- a/shared-core/nouveau_mem.c +++ b/shared-core/nouveau_mem.c @@ -742,9 +742,6 @@ void nouveau_mem_free(struct drm_device* dev, struct mem_block* block) if (crtc->fb->block == block) { crtc->fb->block = NULL; - /* this will force a lut change next time a fb is loaded */ - crtc->lut->depth = 0; - if (!crtc->blanked) crtc->blank(crtc, TRUE); } -- cgit v1.2.3 From 13943fe5823c45759091c1a1f487a4abe377421e Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Thu, 26 Jun 2008 21:28:29 +0200 Subject: modesetting-101: Make dpms property optional + misc cleanup. - intel_crt seems the only one to provide it, so init it there. --- linux-core/drm_crtc.c | 77 +++++++++++++++++++++++++++++++------------------- linux-core/drm_crtc.h | 3 +- linux-core/intel_crt.c | 4 +++ linux-core/intel_tv.c | 2 +- 4 files changed, 55 insertions(+), 31 deletions(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index aab936c2..b6e636e0 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -43,10 +43,10 @@ struct drm_prop_enum_list { * Global properties */ static struct drm_prop_enum_list drm_dpms_enum_list[] = -{ { DPMSModeOn, "On" }, - { DPMSModeStandby, "Standby" }, - { DPMSModeSuspend, "Suspend" }, - { DPMSModeOff, "Off" } +{ { DPMSModeOn, "On" }, + { DPMSModeStandby, "Standby" }, + { DPMSModeSuspend, "Suspend" }, + { DPMSModeOff, "Off" } }; char *drm_get_dpms_name(int val) @@ -61,26 +61,26 @@ char *drm_get_dpms_name(int val) } static struct drm_prop_enum_list drm_connector_enum_list[] = -{ { DRM_MODE_CONNECTOR_Unknown, "Unknown" }, - { DRM_MODE_CONNECTOR_VGA, "VGA" }, - { DRM_MODE_CONNECTOR_DVII, "DVI-I" }, - { DRM_MODE_CONNECTOR_DVID, "DVI-D" }, - { DRM_MODE_CONNECTOR_DVIA, "DVI-A" }, - { DRM_MODE_CONNECTOR_Composite, "Composite" }, - { DRM_MODE_CONNECTOR_SVIDEO, "SVIDEO" }, - { DRM_MODE_CONNECTOR_LVDS, "LVDS" }, - { DRM_MODE_CONNECTOR_Component, "Component" }, - { DRM_MODE_CONNECTOR_9PinDIN, "9-pin DIN" }, - { DRM_MODE_CONNECTOR_DisplayPort, "DisplayPort" }, - { DRM_MODE_CONNECTOR_HDMIA, "HDMI Type A" }, - { DRM_MODE_CONNECTOR_HDMIB, "HDMI Type B" }, +{ { DRM_MODE_CONNECTOR_Unknown, "Unknown" }, + { DRM_MODE_CONNECTOR_VGA, "VGA" }, + { DRM_MODE_CONNECTOR_DVII, "DVI-I" }, + { DRM_MODE_CONNECTOR_DVID, "DVI-D" }, + { DRM_MODE_CONNECTOR_DVIA, "DVI-A" }, + { DRM_MODE_CONNECTOR_Composite, "Composite" }, + { DRM_MODE_CONNECTOR_SVIDEO, "SVIDEO" }, + { DRM_MODE_CONNECTOR_LVDS, "LVDS" }, + { DRM_MODE_CONNECTOR_Component, "Component" }, + { DRM_MODE_CONNECTOR_9PinDIN, "9-pin DIN" }, + { DRM_MODE_CONNECTOR_DisplayPort, "DisplayPort" }, + { DRM_MODE_CONNECTOR_HDMIA, "HDMI Type A" }, + { DRM_MODE_CONNECTOR_HDMIB, "HDMI Type B" }, }; static struct drm_prop_enum_list drm_encoder_enum_list[] = -{ { DRM_MODE_ENCODER_NONE, "None" }, - { DRM_MODE_ENCODER_DAC, "DAC" }, - { DRM_MODE_ENCODER_TMDS, "TMDS" }, - { DRM_MODE_ENCODER_LVDS, "LVDS" }, - { DRM_MODE_ENCODER_TVDAC, "TV" }, +{ { DRM_MODE_ENCODER_NONE, "None" }, + { DRM_MODE_ENCODER_DAC, "DAC" }, + { DRM_MODE_ENCODER_TMDS, "TMDS" }, + { DRM_MODE_ENCODER_LVDS, "LVDS" }, + { DRM_MODE_ENCODER_TVDAC, "TV" }, }; char *drm_get_encoder_name(struct drm_encoder *encoder) @@ -164,7 +164,7 @@ static void drm_mode_object_put(struct drm_device *dev, struct drm_mode_object * static void *drm_mode_object_find(struct drm_device *dev, uint32_t id, uint32_t type) { struct drm_mode_object *obj; - + obj = idr_find(&dev->mode_config.crtc_idr, id); if (!obj || (obj->type != type) || (obj->id != id)) return NULL; @@ -369,8 +369,6 @@ void drm_connector_init(struct drm_device *dev, drm_connector_attach_property(connector, dev->mode_config.edid_property, 0); - drm_connector_attach_property(connector, dev->mode_config.dpms_property, 0); - mutex_unlock(&dev->mode_config.mutex); } EXPORT_SYMBOL(drm_connector_init); @@ -479,8 +477,6 @@ EXPORT_SYMBOL(drm_mode_destroy); static int drm_mode_create_standard_connector_properties(struct drm_device *dev) { - int i; - /* * Standard properties (apply to all connectors) */ @@ -488,6 +484,24 @@ static int drm_mode_create_standard_connector_properties(struct drm_device *dev) drm_property_create(dev, DRM_MODE_PROP_BLOB | DRM_MODE_PROP_IMMUTABLE, "EDID", 0); + return 0; +} + +/** + * drm_mode_create_dpms_property - create dpms connector property + * @dev: DRM device + * + * Called by a driver wanting to support the dpms property. + * Caller is responsible for attaching it to the appropriate connector. + */ +bool drm_mode_create_dpms_property(struct drm_device *dev) +{ + int i; + + /* already allocated */ + if (dev->mode_config.dpms_property) + return 0; + dev->mode_config.dpms_property = drm_property_create(dev, DRM_MODE_PROP_ENUM, "DPMS", ARRAY_SIZE(drm_dpms_enum_list)); @@ -496,6 +510,7 @@ static int drm_mode_create_standard_connector_properties(struct drm_device *dev) return 0; } +EXPORT_SYMBOL(drm_mode_create_dpms_property); /** * drm_create_tv_properties - create TV specific connector properties @@ -508,11 +523,15 @@ static int drm_mode_create_standard_connector_properties(struct drm_device *dev) * responsible for allocating a list of format names and passing them to * this routine. */ -bool drm_create_tv_properties(struct drm_device *dev, int num_modes, +bool drm_mode_create_tv_properties(struct drm_device *dev, int num_modes, char *modes[]) { int i; + /* already allocated */ + if (dev->mode_config.tv_mode_property) + return 0; + dev->mode_config.tv_left_margin_property = drm_property_create(dev, DRM_MODE_PROP_RANGE | DRM_MODE_PROP_IMMUTABLE, @@ -547,7 +566,7 @@ bool drm_create_tv_properties(struct drm_device *dev, int num_modes, return 0; } -EXPORT_SYMBOL(drm_create_tv_properties); +EXPORT_SYMBOL(drm_mode_create_tv_properties); /** * drm_mode_config_init - initialize DRM mode_configuration structure diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index d6fa4cca..b94e91a1 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -677,7 +677,8 @@ extern struct drm_property *drm_property_create(struct drm_device *dev, int flag extern void drm_property_destroy(struct drm_device *dev, struct drm_property *property); extern int drm_property_add_enum(struct drm_property *property, int index, uint64_t value, const char *name); -extern bool drm_create_tv_properties(struct drm_device *dev, int num_formats, +extern bool drm_mode_create_dpms_property(struct drm_device *dev); +extern bool drm_mode_create_tv_properties(struct drm_device *dev, int num_formats, char *formats[]); extern char *drm_get_encoder_name(struct drm_encoder *encoder); diff --git a/linux-core/intel_crt.c b/linux-core/intel_crt.c index b9e8ee63..c7509d5e 100644 --- a/linux-core/intel_crt.c +++ b/linux-core/intel_crt.c @@ -292,5 +292,9 @@ void intel_crt_init(struct drm_device *dev) drm_encoder_helper_add(&intel_output->enc, &intel_crt_helper_funcs); drm_connector_helper_add(connector, &intel_crt_connector_helper_funcs); + /* create dpms property */ + drm_mode_create_dpms_property(dev); + drm_connector_attach_property(connector, dev->mode_config.dpms_property, 0); + drm_sysfs_connector_add(connector); } diff --git a/linux-core/intel_tv.c b/linux-core/intel_tv.c index 39f33d6c..f564fa91 100644 --- a/linux-core/intel_tv.c +++ b/linux-core/intel_tv.c @@ -1713,7 +1713,7 @@ intel_tv_init(struct drm_device *dev) goto out; for (i = 0; i < NUM_TV_MODES; i++) tv_format_names[i] = tv_modes[i].name; - drm_create_tv_properties(dev, NUM_TV_MODES, tv_format_names); + drm_mode_create_tv_properties(dev, NUM_TV_MODES, tv_format_names); drm_connector_attach_property(connector, dev->mode_config.tv_mode_property, initial_mode); -- cgit v1.2.3 From 087e3f577d795bcd007619514bb2977eede70c16 Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Thu, 26 Jun 2008 23:12:04 +0200 Subject: Revert "modesetting-101: Make dpms property optional + misc cleanup." This reverts commit 13943fe5823c45759091c1a1f487a4abe377421e. --- linux-core/drm_crtc.c | 77 +++++++++++++++++++------------------------------- linux-core/drm_crtc.h | 3 +- linux-core/intel_crt.c | 4 --- linux-core/intel_tv.c | 2 +- 4 files changed, 31 insertions(+), 55 deletions(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index b6e636e0..aab936c2 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -43,10 +43,10 @@ struct drm_prop_enum_list { * Global properties */ static struct drm_prop_enum_list drm_dpms_enum_list[] = -{ { DPMSModeOn, "On" }, - { DPMSModeStandby, "Standby" }, - { DPMSModeSuspend, "Suspend" }, - { DPMSModeOff, "Off" } +{ { DPMSModeOn, "On" }, + { DPMSModeStandby, "Standby" }, + { DPMSModeSuspend, "Suspend" }, + { DPMSModeOff, "Off" } }; char *drm_get_dpms_name(int val) @@ -61,26 +61,26 @@ char *drm_get_dpms_name(int val) } static struct drm_prop_enum_list drm_connector_enum_list[] = -{ { DRM_MODE_CONNECTOR_Unknown, "Unknown" }, - { DRM_MODE_CONNECTOR_VGA, "VGA" }, - { DRM_MODE_CONNECTOR_DVII, "DVI-I" }, - { DRM_MODE_CONNECTOR_DVID, "DVI-D" }, - { DRM_MODE_CONNECTOR_DVIA, "DVI-A" }, - { DRM_MODE_CONNECTOR_Composite, "Composite" }, - { DRM_MODE_CONNECTOR_SVIDEO, "SVIDEO" }, - { DRM_MODE_CONNECTOR_LVDS, "LVDS" }, - { DRM_MODE_CONNECTOR_Component, "Component" }, - { DRM_MODE_CONNECTOR_9PinDIN, "9-pin DIN" }, - { DRM_MODE_CONNECTOR_DisplayPort, "DisplayPort" }, - { DRM_MODE_CONNECTOR_HDMIA, "HDMI Type A" }, - { DRM_MODE_CONNECTOR_HDMIB, "HDMI Type B" }, +{ { DRM_MODE_CONNECTOR_Unknown, "Unknown" }, + { DRM_MODE_CONNECTOR_VGA, "VGA" }, + { DRM_MODE_CONNECTOR_DVII, "DVI-I" }, + { DRM_MODE_CONNECTOR_DVID, "DVI-D" }, + { DRM_MODE_CONNECTOR_DVIA, "DVI-A" }, + { DRM_MODE_CONNECTOR_Composite, "Composite" }, + { DRM_MODE_CONNECTOR_SVIDEO, "SVIDEO" }, + { DRM_MODE_CONNECTOR_LVDS, "LVDS" }, + { DRM_MODE_CONNECTOR_Component, "Component" }, + { DRM_MODE_CONNECTOR_9PinDIN, "9-pin DIN" }, + { DRM_MODE_CONNECTOR_DisplayPort, "DisplayPort" }, + { DRM_MODE_CONNECTOR_HDMIA, "HDMI Type A" }, + { DRM_MODE_CONNECTOR_HDMIB, "HDMI Type B" }, }; static struct drm_prop_enum_list drm_encoder_enum_list[] = -{ { DRM_MODE_ENCODER_NONE, "None" }, - { DRM_MODE_ENCODER_DAC, "DAC" }, - { DRM_MODE_ENCODER_TMDS, "TMDS" }, - { DRM_MODE_ENCODER_LVDS, "LVDS" }, - { DRM_MODE_ENCODER_TVDAC, "TV" }, +{ { DRM_MODE_ENCODER_NONE, "None" }, + { DRM_MODE_ENCODER_DAC, "DAC" }, + { DRM_MODE_ENCODER_TMDS, "TMDS" }, + { DRM_MODE_ENCODER_LVDS, "LVDS" }, + { DRM_MODE_ENCODER_TVDAC, "TV" }, }; char *drm_get_encoder_name(struct drm_encoder *encoder) @@ -164,7 +164,7 @@ static void drm_mode_object_put(struct drm_device *dev, struct drm_mode_object * static void *drm_mode_object_find(struct drm_device *dev, uint32_t id, uint32_t type) { struct drm_mode_object *obj; - + obj = idr_find(&dev->mode_config.crtc_idr, id); if (!obj || (obj->type != type) || (obj->id != id)) return NULL; @@ -369,6 +369,8 @@ void drm_connector_init(struct drm_device *dev, drm_connector_attach_property(connector, dev->mode_config.edid_property, 0); + drm_connector_attach_property(connector, dev->mode_config.dpms_property, 0); + mutex_unlock(&dev->mode_config.mutex); } EXPORT_SYMBOL(drm_connector_init); @@ -477,6 +479,8 @@ EXPORT_SYMBOL(drm_mode_destroy); static int drm_mode_create_standard_connector_properties(struct drm_device *dev) { + int i; + /* * Standard properties (apply to all connectors) */ @@ -484,24 +488,6 @@ static int drm_mode_create_standard_connector_properties(struct drm_device *dev) drm_property_create(dev, DRM_MODE_PROP_BLOB | DRM_MODE_PROP_IMMUTABLE, "EDID", 0); - return 0; -} - -/** - * drm_mode_create_dpms_property - create dpms connector property - * @dev: DRM device - * - * Called by a driver wanting to support the dpms property. - * Caller is responsible for attaching it to the appropriate connector. - */ -bool drm_mode_create_dpms_property(struct drm_device *dev) -{ - int i; - - /* already allocated */ - if (dev->mode_config.dpms_property) - return 0; - dev->mode_config.dpms_property = drm_property_create(dev, DRM_MODE_PROP_ENUM, "DPMS", ARRAY_SIZE(drm_dpms_enum_list)); @@ -510,7 +496,6 @@ bool drm_mode_create_dpms_property(struct drm_device *dev) return 0; } -EXPORT_SYMBOL(drm_mode_create_dpms_property); /** * drm_create_tv_properties - create TV specific connector properties @@ -523,15 +508,11 @@ EXPORT_SYMBOL(drm_mode_create_dpms_property); * responsible for allocating a list of format names and passing them to * this routine. */ -bool drm_mode_create_tv_properties(struct drm_device *dev, int num_modes, +bool drm_create_tv_properties(struct drm_device *dev, int num_modes, char *modes[]) { int i; - /* already allocated */ - if (dev->mode_config.tv_mode_property) - return 0; - dev->mode_config.tv_left_margin_property = drm_property_create(dev, DRM_MODE_PROP_RANGE | DRM_MODE_PROP_IMMUTABLE, @@ -566,7 +547,7 @@ bool drm_mode_create_tv_properties(struct drm_device *dev, int num_modes, return 0; } -EXPORT_SYMBOL(drm_mode_create_tv_properties); +EXPORT_SYMBOL(drm_create_tv_properties); /** * drm_mode_config_init - initialize DRM mode_configuration structure diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index b94e91a1..d6fa4cca 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -677,8 +677,7 @@ extern struct drm_property *drm_property_create(struct drm_device *dev, int flag extern void drm_property_destroy(struct drm_device *dev, struct drm_property *property); extern int drm_property_add_enum(struct drm_property *property, int index, uint64_t value, const char *name); -extern bool drm_mode_create_dpms_property(struct drm_device *dev); -extern bool drm_mode_create_tv_properties(struct drm_device *dev, int num_formats, +extern bool drm_create_tv_properties(struct drm_device *dev, int num_formats, char *formats[]); extern char *drm_get_encoder_name(struct drm_encoder *encoder); diff --git a/linux-core/intel_crt.c b/linux-core/intel_crt.c index c7509d5e..b9e8ee63 100644 --- a/linux-core/intel_crt.c +++ b/linux-core/intel_crt.c @@ -292,9 +292,5 @@ void intel_crt_init(struct drm_device *dev) drm_encoder_helper_add(&intel_output->enc, &intel_crt_helper_funcs); drm_connector_helper_add(connector, &intel_crt_connector_helper_funcs); - /* create dpms property */ - drm_mode_create_dpms_property(dev); - drm_connector_attach_property(connector, dev->mode_config.dpms_property, 0); - drm_sysfs_connector_add(connector); } diff --git a/linux-core/intel_tv.c b/linux-core/intel_tv.c index f564fa91..39f33d6c 100644 --- a/linux-core/intel_tv.c +++ b/linux-core/intel_tv.c @@ -1713,7 +1713,7 @@ intel_tv_init(struct drm_device *dev) goto out; for (i = 0; i < NUM_TV_MODES; i++) tv_format_names[i] = tv_modes[i].name; - drm_mode_create_tv_properties(dev, NUM_TV_MODES, tv_format_names); + drm_create_tv_properties(dev, NUM_TV_MODES, tv_format_names); drm_connector_attach_property(connector, dev->mode_config.tv_mode_property, initial_mode); -- cgit v1.2.3 From d88616555d2d3abc118f77d5556e14dd1512272b Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Thu, 26 Jun 2008 23:21:01 +0200 Subject: [modesetting-101] tab-cleanup --- linux-core/drm_crtc.c | 96 +++++++++++++++++++++++++-------------------------- 1 file changed, 47 insertions(+), 49 deletions(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index aab936c2..4f21d09e 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -43,10 +43,10 @@ struct drm_prop_enum_list { * Global properties */ static struct drm_prop_enum_list drm_dpms_enum_list[] = -{ { DPMSModeOn, "On" }, - { DPMSModeStandby, "Standby" }, - { DPMSModeSuspend, "Suspend" }, - { DPMSModeOff, "Off" } +{ { DPMSModeOn, "On" }, + { DPMSModeStandby, "Standby" }, + { DPMSModeSuspend, "Suspend" }, + { DPMSModeOff, "Off" } }; char *drm_get_dpms_name(int val) @@ -61,26 +61,26 @@ char *drm_get_dpms_name(int val) } static struct drm_prop_enum_list drm_connector_enum_list[] = -{ { DRM_MODE_CONNECTOR_Unknown, "Unknown" }, - { DRM_MODE_CONNECTOR_VGA, "VGA" }, - { DRM_MODE_CONNECTOR_DVII, "DVI-I" }, - { DRM_MODE_CONNECTOR_DVID, "DVI-D" }, - { DRM_MODE_CONNECTOR_DVIA, "DVI-A" }, - { DRM_MODE_CONNECTOR_Composite, "Composite" }, - { DRM_MODE_CONNECTOR_SVIDEO, "SVIDEO" }, - { DRM_MODE_CONNECTOR_LVDS, "LVDS" }, - { DRM_MODE_CONNECTOR_Component, "Component" }, - { DRM_MODE_CONNECTOR_9PinDIN, "9-pin DIN" }, - { DRM_MODE_CONNECTOR_DisplayPort, "DisplayPort" }, - { DRM_MODE_CONNECTOR_HDMIA, "HDMI Type A" }, - { DRM_MODE_CONNECTOR_HDMIB, "HDMI Type B" }, +{ { DRM_MODE_CONNECTOR_Unknown, "Unknown" }, + { DRM_MODE_CONNECTOR_VGA, "VGA" }, + { DRM_MODE_CONNECTOR_DVII, "DVI-I" }, + { DRM_MODE_CONNECTOR_DVID, "DVI-D" }, + { DRM_MODE_CONNECTOR_DVIA, "DVI-A" }, + { DRM_MODE_CONNECTOR_Composite, "Composite" }, + { DRM_MODE_CONNECTOR_SVIDEO, "SVIDEO" }, + { DRM_MODE_CONNECTOR_LVDS, "LVDS" }, + { DRM_MODE_CONNECTOR_Component, "Component" }, + { DRM_MODE_CONNECTOR_9PinDIN, "9-pin DIN" }, + { DRM_MODE_CONNECTOR_DisplayPort, "DisplayPort" }, + { DRM_MODE_CONNECTOR_HDMIA, "HDMI Type A" }, + { DRM_MODE_CONNECTOR_HDMIB, "HDMI Type B" }, }; static struct drm_prop_enum_list drm_encoder_enum_list[] = -{ { DRM_MODE_ENCODER_NONE, "None" }, - { DRM_MODE_ENCODER_DAC, "DAC" }, - { DRM_MODE_ENCODER_TMDS, "TMDS" }, - { DRM_MODE_ENCODER_LVDS, "LVDS" }, - { DRM_MODE_ENCODER_TVDAC, "TV" }, +{ { DRM_MODE_ENCODER_NONE, "None" }, + { DRM_MODE_ENCODER_DAC, "DAC" }, + { DRM_MODE_ENCODER_TMDS, "TMDS" }, + { DRM_MODE_ENCODER_LVDS, "LVDS" }, + { DRM_MODE_ENCODER_TVDAC, "TV" }, }; char *drm_get_encoder_name(struct drm_encoder *encoder) @@ -139,7 +139,7 @@ again: ret = idr_get_new_above(&dev->mode_config.crtc_idr, obj, 1, &new_id); if (ret == -EAGAIN) - goto again; + goto again; obj->id = new_id; obj->type = obj_type; @@ -164,7 +164,7 @@ static void drm_mode_object_put(struct drm_device *dev, struct drm_mode_object * static void *drm_mode_object_find(struct drm_device *dev, uint32_t id, uint32_t type) { struct drm_mode_object *obj; - + obj = idr_find(&dev->mode_config.crtc_idr, id); if (!obj || (obj->type != type) || (obj->id != id)) return NULL; @@ -411,7 +411,7 @@ void drm_encoder_init(struct drm_device *dev, int encoder_type) { encoder->dev = dev; - + drm_mode_object_get(dev, &encoder->base, DRM_MODE_OBJECT_ENCODER); encoder->encoder_type = encoder_type; encoder->funcs = funcs; @@ -590,7 +590,7 @@ int drm_mode_group_init(struct drm_device *dev, struct drm_mode_group *group) total_objects += dev->mode_config.num_crtc; total_objects += dev->mode_config.num_connector; total_objects += dev->mode_config.num_encoder; - + group->id_list = kzalloc(total_objects * sizeof(uint32_t), GFP_KERNEL); if (!group->id_list) return -ENOMEM; @@ -736,7 +736,7 @@ void drm_crtc_convert_umode(struct drm_display_mode *out, struct drm_mode_modein strncpy(out->name, in->name, DRM_DISPLAY_MODE_LEN); out->name[DRM_DISPLAY_MODE_LEN-1] = 0; } - + /** * drm_mode_getresources - get graphics configuration * @inode: inode from the ioctl @@ -795,7 +795,7 @@ int drm_mode_getresources(struct drm_device *dev, list_for_each(lh, &dev->mode_config.encoder_list) encoder_count++; } else { - + crtc_count = mode_group->num_crtcs; connector_count = mode_group->num_connectors; encoder_count = mode_group->num_encoders; @@ -900,13 +900,11 @@ int drm_mode_getresources(struct drm_device *dev, } } card_res->count_connectors = connector_count; - - DRM_DEBUG("Counted %d %d %d\n", card_res->count_crtcs, card_res->count_connectors, card_res->count_encoders); -out: +out: mutex_unlock(&dev->mode_config.mutex); return ret; } @@ -959,7 +957,7 @@ int drm_mode_getcrtc(struct drm_device *dev, drm_crtc_convert_to_umode(&crtc_resp->mode, &crtc->mode); crtc_resp->mode_valid = 1; - + } else { crtc_resp->mode_valid = 0; } @@ -1114,7 +1112,7 @@ int drm_mode_getencoder(struct drm_device *dev, struct drm_mode_object *obj; struct drm_encoder *encoder; int ret = 0; - + mutex_lock(&dev->mode_config.mutex); obj = drm_mode_object_find(dev, enc_resp->encoder_id, DRM_MODE_OBJECT_ENCODER); if (!obj) { @@ -1132,7 +1130,7 @@ int drm_mode_getencoder(struct drm_device *dev, enc_resp->encoder_id = encoder->base.id; enc_resp->crtcs = encoder->possible_crtcs; enc_resp->clones = encoder->possible_clones; - + out: mutex_unlock(&dev->mode_config.mutex); return ret; @@ -1177,7 +1175,7 @@ int drm_mode_setcrtc(struct drm_device *dev, goto out; } crtc = obj_to_crtc(obj); - + if (crtc_req->mode_valid) { /* If we have a mode we need a framebuffer. */ /* If we pass -1, set the mode with the currently bound fb */ @@ -1185,7 +1183,7 @@ int drm_mode_setcrtc(struct drm_device *dev, list_for_each_entry(crtcfb, &dev->mode_config.crtc_list, head) { if (crtcfb == crtc) { DRM_DEBUG("Using current fb for setmode\n"); - fb = crtc->fb; + fb = crtc->fb; } } } else { @@ -1604,7 +1602,7 @@ int drm_mode_attachmode_ioctl(struct drm_device *dev, ret = -ENOMEM; goto out; } - + drm_crtc_convert_umode(mode, umode); ret = drm_mode_attachmode(dev, connector, mode); @@ -1644,7 +1642,7 @@ int drm_mode_detachmode_ioctl(struct drm_device *dev, goto out; } connector = obj_to_connector(obj); - + drm_crtc_convert_umode(&mode, umode); ret = drm_mode_detachmode(dev, connector, &mode); out: @@ -1728,7 +1726,7 @@ void drm_property_destroy(struct drm_device *dev, struct drm_property *property) kfree(property->values); drm_mode_object_put(dev, &property->base); list_del(&property->head); - kfree(property); + kfree(property); } EXPORT_SYMBOL(drm_property_destroy); @@ -1844,12 +1842,12 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev, copied = 0; enum_ptr = (struct drm_mode_property_enum *)(unsigned long)out_resp->enum_blob_ptr; list_for_each_entry(prop_enum, &property->enum_blob_list, head) { - + if (copy_to_user(&enum_ptr[copied].value, &prop_enum->value, sizeof(uint64_t))) { ret = -EFAULT; goto done; } - + if (copy_to_user(&enum_ptr[copied].name, &prop_enum->name, DRM_PROP_NAME_LEN)) { ret = -EFAULT; @@ -1866,18 +1864,18 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev, copied = 0; blob_id_ptr = (uint32_t *)(unsigned long)out_resp->enum_blob_ptr; blob_length_ptr = (uint32_t *)(unsigned long)out_resp->values_ptr; - + list_for_each_entry(prop_blob, &property->enum_blob_list, head) { if (put_user(prop_blob->base.id, blob_id_ptr + copied)) { ret = -EFAULT; goto done; } - + if (put_user(prop_blob->length, blob_length_ptr + copied)) { ret = -EFAULT; goto done; } - + copied++; } } @@ -1906,7 +1904,7 @@ static struct drm_property_blob *drm_property_create_blob(struct drm_device *dev memcpy(blob->data, data, length); drm_mode_object_get(dev, &blob->base, DRM_MODE_OBJECT_BLOB); - + list_add_tail(&blob->head, &dev->mode_config.property_blob_list); return blob; } @@ -1958,7 +1956,7 @@ int drm_mode_connector_update_edid_property(struct drm_connector *connector, str drm_property_destroy_blob(dev, connector->edid_blob_ptr); connector->edid_blob_ptr = drm_property_create_blob(connector->dev, 128, edid); - + ret = drm_connector_property_set_value(connector, dev->mode_config.edid_property, connector->edid_blob_ptr->base.id); return ret; } @@ -1990,7 +1988,7 @@ int drm_mode_connector_property_set_ioctl(struct drm_device *dev, if (i == DRM_CONNECTOR_MAX_PROPERTY) { goto out; } - + obj = drm_mode_object_find(dev, out_resp->prop_id, DRM_MODE_OBJECT_PROPERTY); if (!obj) { goto out; @@ -2129,7 +2127,7 @@ int drm_mode_gamma_set_ioctl(struct drm_device *dev, goto out; } crtc = obj_to_crtc(obj); - + /* memcpy into gamma store */ if (crtc_lut->gamma_size != crtc->gamma_size) { ret = -EINVAL; @@ -2180,7 +2178,7 @@ int drm_mode_gamma_get_ioctl(struct drm_device *dev, goto out; } crtc = obj_to_crtc(obj); - + /* memcpy into gamma store */ if (crtc_lut->gamma_size != crtc->gamma_size) { ret = -EINVAL; -- cgit v1.2.3 From 701011224c048e064295ee12e8a02f7f66d4175a Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Fri, 27 Jun 2008 01:16:36 +0200 Subject: NV50: Implement DPMS. --- linux-core/nv50_dac.c | 38 ++++++++++++++++++++++++++++++++++++++ linux-core/nv50_kms_wrapper.c | 34 +++++++++++++++++++++++++++++++--- linux-core/nv50_output.h | 2 ++ linux-core/nv50_sor.c | 24 ++++++++++++++++++++++++ 4 files changed, 95 insertions(+), 3 deletions(-) diff --git a/linux-core/nv50_dac.c b/linux-core/nv50_dac.c index b237241e..f51ecf9d 100644 --- a/linux-core/nv50_dac.c +++ b/linux-core/nv50_dac.c @@ -96,6 +96,43 @@ static int nv50_dac_set_clock_mode(struct nv50_output *output) return 0; } +static int nv50_dac_set_power_mode(struct nv50_output *output, int mode) +{ + struct drm_nouveau_private *dev_priv = output->dev->dev_private; + uint32_t val; + int or = nv50_output_or_offset(output); + + NV50_DEBUG("or %d\n", or); + + /* wait for it to be done */ + while (NV_READ(NV50_PDISPLAY_DAC_REGS_DPMS_CTRL(or)) & NV50_PDISPLAY_DAC_REGS_DPMS_CTRL_PENDING); + + val = NV_READ(NV50_PDISPLAY_DAC_REGS_DPMS_CTRL(or)) & ~0x7F; + + if (mode != DPMSModeOn) + val |= NV50_PDISPLAY_DAC_REGS_DPMS_CTRL_BLANKED; + + switch (mode) { + case DPMSModeStandby: + val |= NV50_PDISPLAY_DAC_REGS_DPMS_CTRL_HSYNC_OFF; + break; + case DPMSModeSuspend: + val |= NV50_PDISPLAY_DAC_REGS_DPMS_CTRL_VSYNC_OFF; + break; + case DPMSModeOff: + val |= NV50_PDISPLAY_DAC_REGS_DPMS_CTRL_OFF; + val |= NV50_PDISPLAY_DAC_REGS_DPMS_CTRL_HSYNC_OFF; + val |= NV50_PDISPLAY_DAC_REGS_DPMS_CTRL_VSYNC_OFF; + break; + default: + break; + } + + NV_WRITE(NV50_PDISPLAY_DAC_REGS_DPMS_CTRL(or), val | NV50_PDISPLAY_DAC_REGS_DPMS_CTRL_PENDING); + + return 0; +} + static int nv50_dac_destroy(struct nv50_output *output) { struct drm_device *dev = output->dev; @@ -172,6 +209,7 @@ int nv50_dac_create(struct drm_device *dev, int dcb_entry) output->validate_mode = nv50_dac_validate_mode; output->execute_mode = nv50_dac_execute_mode; output->set_clock_mode = nv50_dac_set_clock_mode; + output->set_power_mode = nv50_dac_set_power_mode; output->detect = NULL; /* TODO */ output->destroy = nv50_dac_destroy; diff --git a/linux-core/nv50_kms_wrapper.c b/linux-core/nv50_kms_wrapper.c index 8b97882a..79eb2964 100644 --- a/linux-core/nv50_kms_wrapper.c +++ b/linux-core/nv50_kms_wrapper.c @@ -640,6 +640,18 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) /* next line changes crtc, so putting it here is important */ display->last_crtc = crtc->index; + /* this is executed immediately */ + list_for_each_entry(output, &display->outputs, head) { + if (output->crtc != crtc) + continue; + + rval = output->set_power_mode(output, DPMSModeOn); + if (rval != 0) { + DRM_ERROR("output set power mode failed\n"); + goto out; + } + } + /* blank any unused crtcs */ list_for_each_entry(crtc, &display->crtcs, head) { if (!(crtc_mask & (1 << crtc->index))) @@ -654,9 +666,6 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) return 0; out: - if (display) - display->update(display); - kfree(hw_mode); if (rval != 0) @@ -938,12 +947,31 @@ static void nv50_kms_connector_fill_modes(struct drm_connector *drm_connector, u } } +static bool nv50_kms_connector_set_property(struct drm_connector *connector, + struct drm_property *property, + uint64_t value) +{ + struct drm_device *dev = connector->dev; + + if (property == dev->mode_config.dpms_property && connector->encoder) { + struct nv50_output *output = to_nv50_output(connector->encoder); + + if (!output->set_power_mode(output, (int) value)) + return true; + else + return false; + } + + return false; +} + static const struct drm_connector_funcs nv50_kms_connector_funcs = { .save = NULL, .restore = NULL, .detect = nv50_kms_connector_detect, .destroy = nv50_kms_connector_destroy, .fill_modes = nv50_kms_connector_fill_modes, + .set_property = nv50_kms_connector_set_property }; static int nv50_kms_connectors_init(struct drm_device *dev) diff --git a/linux-core/nv50_output.h b/linux-core/nv50_output.h index bdee2826..7a6f9c7e 100644 --- a/linux-core/nv50_output.h +++ b/linux-core/nv50_output.h @@ -49,6 +49,8 @@ struct nv50_output { int (*validate_mode) (struct nv50_output *output, struct nouveau_hw_mode *mode); int (*execute_mode) (struct nv50_output *output, bool disconnect); int (*set_clock_mode) (struct nv50_output *output); + /* this is not a normal modeset call, it is a direct register write, so it's executed immediately */ + int (*set_power_mode) (struct nv50_output *output, int mode); bool (*detect) (struct nv50_output *output); int (*destroy) (struct nv50_output *output); }; diff --git a/linux-core/nv50_sor.c b/linux-core/nv50_sor.c index fca9612f..84192803 100644 --- a/linux-core/nv50_sor.c +++ b/linux-core/nv50_sor.c @@ -114,6 +114,29 @@ static int nv50_sor_set_clock_mode(struct nv50_output *output) return 0; } +static int nv50_sor_set_power_mode(struct nv50_output *output, int mode) +{ + struct drm_nouveau_private *dev_priv = output->dev->dev_private; + uint32_t val; + int or = nv50_output_or_offset(output); + + NV50_DEBUG("or %d\n", nv50_output_or_offset(output)); + + /* wait for it to be done */ + while (NV_READ(NV50_PDISPLAY_SOR_REGS_DPMS_CTRL(or)) & NV50_PDISPLAY_SOR_REGS_DPMS_CTRL_PENDING); + + val = NV_READ(NV50_PDISPLAY_SOR_REGS_DPMS_CTRL(or)); + + if (mode == DPMSModeOn) + val |= NV50_PDISPLAY_SOR_REGS_DPMS_CTRL_ON; + else + val &= ~NV50_PDISPLAY_SOR_REGS_DPMS_CTRL_ON; + + NV_WRITE(NV50_PDISPLAY_SOR_REGS_DPMS_CTRL(or), val | NV50_PDISPLAY_SOR_REGS_DPMS_CTRL_PENDING); + + return 0; +} + static int nv50_sor_destroy(struct nv50_output *output) { struct drm_device *dev = output->dev; @@ -194,6 +217,7 @@ int nv50_sor_create(struct drm_device *dev, int dcb_entry) output->validate_mode = nv50_sor_validate_mode; output->execute_mode = nv50_sor_execute_mode; output->set_clock_mode = nv50_sor_set_clock_mode; + output->set_power_mode = nv50_sor_set_power_mode; output->detect = NULL; output->destroy = nv50_sor_destroy; -- cgit v1.2.3 From 01ee5eda9aaff880153223df8bb70a34b1a87cee Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Fri, 27 Jun 2008 01:29:30 +0200 Subject: NV50: A minor change. --- linux-core/nv50_kms_wrapper.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/linux-core/nv50_kms_wrapper.c b/linux-core/nv50_kms_wrapper.c index 79eb2964..900dfccd 100644 --- a/linux-core/nv50_kms_wrapper.c +++ b/linux-core/nv50_kms_wrapper.c @@ -484,6 +484,8 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) */ if (switch_fb) { + crtc = to_nv50_crtc(set->crtc); + /* set framebuffer */ set->crtc->fb = set->fb; @@ -573,6 +575,8 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) */ if (modeset) { + crtc = to_nv50_crtc(set->crtc); + /* disconnect unused outputs */ list_for_each_entry(output, &display->outputs, head) { if (output->crtc) { @@ -586,6 +590,14 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) } } + /* blank any unused crtcs */ + list_for_each_entry(crtc, &display->crtcs, head) { + if (!(crtc_mask & (1 << crtc->index))) + crtc->blank(crtc, TRUE); + } + + crtc = to_nv50_crtc(set->crtc); + rval = crtc->set_mode(crtc, hw_mode); if (rval != 0) { DRM_ERROR("crtc mode set failed\n"); @@ -651,12 +663,6 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) goto out; } } - - /* blank any unused crtcs */ - list_for_each_entry(crtc, &display->crtcs, head) { - if (!(crtc_mask & (1 << crtc->index))) - crtc->blank(crtc, TRUE); - } } display->update(display); -- cgit v1.2.3 From 71906e86e81440037aa08b6f23f36e9fd3835639 Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Fri, 27 Jun 2008 16:30:25 +0200 Subject: [modesetting-101] Actually store properties when being changed. --- linux-core/drm_crtc.c | 3 +++ linux-core/nv50_kms_wrapper.c | 17 +++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 4f21d09e..b9276c3a 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -2017,6 +2017,9 @@ int drm_mode_connector_property_set_ioctl(struct drm_device *dev, } } + /* store the property value */ + drm_connector_property_set_value(connector, property, out_resp->value); + if (connector->funcs->set_property) ret = connector->funcs->set_property(connector, property, out_resp->value); diff --git a/linux-core/nv50_kms_wrapper.c b/linux-core/nv50_kms_wrapper.c index 900dfccd..9ece228e 100644 --- a/linux-core/nv50_kms_wrapper.c +++ b/linux-core/nv50_kms_wrapper.c @@ -663,6 +663,23 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) goto out; } } + + /* update dpms state to DPMSModeOn */ + for (i = 0; i < set->num_connectors; i++) { + drm_connector = set->connectors[i]; + if (!drm_connector) { + DRM_ERROR("No connector\n"); + goto out; + } + + rval = drm_connector_property_set_value(drm_connector, + dev->mode_config.dpms_property, + DPMSModeOn); + if (rval != 0) { + DRM_ERROR("failed to update dpms state\n"); + goto out; + } + } } display->update(display); -- cgit v1.2.3 From 9f28da80f6cc8e45670b217a2483983f2838095d Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Fri, 27 Jun 2008 18:45:08 +0200 Subject: Change some obviously wrong things about property blobs, still broken though. - I do not fully understand these blobs, so i'm leaving it at this for the moment. --- libdrm/xf86drmMode.c | 2 +- linux-core/drm_crtc.c | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/libdrm/xf86drmMode.c b/libdrm/xf86drmMode.c index df865415..ca21a961 100644 --- a/libdrm/xf86drmMode.c +++ b/libdrm/xf86drmMode.c @@ -495,7 +495,7 @@ drmModePropertyPtr drmModeGetProperty(int fd, uint32_t property_id) if (prop.flags & DRM_MODE_PROP_ENUM) { r->count_enums = prop.count_enum_blobs; r->enums = drmAllocCpy(U642VOID(prop.enum_blob_ptr), prop.count_enum_blobs, sizeof(struct drm_mode_property_enum)); - } else if (prop.flags & DRM_MODE_PROP_ENUM) { + } else if (prop.flags & DRM_MODE_PROP_BLOB) { r->values = drmAllocCpy(U642VOID(prop.values_ptr), prop.count_enum_blobs, sizeof(uint32_t)); r->blob_ids = drmAllocCpy(U642VOID(prop.enum_blob_ptr), prop.count_enum_blobs, sizeof(uint32_t)); r->count_blobs = prop.count_enum_blobs; diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index b9276c3a..23ae7d83 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -1837,7 +1837,6 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev, out_resp->count_values = value_count; if (property->flags & DRM_MODE_PROP_ENUM) { - if ((out_resp->count_enum_blobs >= enum_count) && enum_count) { copied = 0; enum_ptr = (struct drm_mode_property_enum *)(unsigned long)out_resp->enum_blob_ptr; @@ -1879,7 +1878,7 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev, copied++; } } - out_resp->count_enum_blobs = enum_count; + out_resp->count_enum_blobs = blob_count; } done: mutex_unlock(&dev->mode_config.mutex); -- cgit v1.2.3 From 91c742663a618e81da69ad4f098321d9af56d636 Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Fri, 27 Jun 2008 18:58:13 +0200 Subject: NV50: use list_head item instead of list_head head to avoid confusion --- linux-core/nv50_connector.c | 6 +++--- linux-core/nv50_connector.h | 2 +- linux-core/nv50_crtc.c | 4 ++-- linux-core/nv50_crtc.h | 2 +- linux-core/nv50_dac.c | 4 ++-- linux-core/nv50_display.c | 10 +++++----- linux-core/nv50_kms_wrapper.c | 22 +++++++++++----------- linux-core/nv50_output.h | 2 +- linux-core/nv50_sor.c | 4 ++-- shared-core/nouveau_irq.c | 4 ++-- shared-core/nouveau_mem.c | 2 +- 11 files changed, 31 insertions(+), 31 deletions(-) diff --git a/linux-core/nv50_connector.c b/linux-core/nv50_connector.c index a13f8e59..ac5194c0 100644 --- a/linux-core/nv50_connector.c +++ b/linux-core/nv50_connector.c @@ -60,7 +60,7 @@ static struct nv50_output *nv50_connector_to_output(struct nv50_connector *conne if (!digital_possible && digital) return NULL; - list_for_each_entry(output, &display->outputs, head) { + list_for_each_entry(output, &display->outputs, item) { if (connector->bus != output->bus) continue; if (digital && output->type == OUTPUT_TMDS) @@ -122,7 +122,7 @@ static int nv50_connector_destroy(struct nv50_connector *connector) if (!display || !connector) return -EINVAL; - list_del(&connector->head); + list_del(&connector->item); if (connector->i2c_chan) nv50_i2c_channel_destroy(connector->i2c_chan); @@ -157,7 +157,7 @@ int nv50_connector_create(struct drm_device *dev, int bus, int i2c_index, int ty if (type == CONNECTOR_UNKNOWN) goto out; - list_add_tail(&connector->head, &display->connectors); + list_add_tail(&connector->item, &display->connectors); connector->bus = bus; connector->type = type; diff --git a/linux-core/nv50_connector.h b/linux-core/nv50_connector.h index c70d6ef4..484227a0 100644 --- a/linux-core/nv50_connector.h +++ b/linux-core/nv50_connector.h @@ -38,7 +38,7 @@ #define CONNECTOR_TV 5 struct nv50_connector { - struct list_head head; + struct list_head item; struct drm_device *dev; int type; diff --git a/linux-core/nv50_crtc.c b/linux-core/nv50_crtc.c index af2f03d8..fd2ad38a 100644 --- a/linux-core/nv50_crtc.c +++ b/linux-core/nv50_crtc.c @@ -445,7 +445,7 @@ static int nv50_crtc_destroy(struct nv50_crtc *crtc) if (!display || !crtc) return -EINVAL; - list_del(&crtc->head); + list_del(&crtc->item); nv50_fb_destroy(crtc); nv50_lut_destroy(crtc); @@ -484,7 +484,7 @@ int nv50_crtc_create(struct drm_device *dev, int index) goto out; } - list_add_tail(&crtc->head, &display->crtcs); + list_add_tail(&crtc->item, &display->crtcs); crtc->index = index; diff --git a/linux-core/nv50_crtc.h b/linux-core/nv50_crtc.h index b63c5a22..de9a33f2 100644 --- a/linux-core/nv50_crtc.h +++ b/linux-core/nv50_crtc.h @@ -34,7 +34,7 @@ struct nv50_lut; struct nv50_fb; struct nv50_crtc { - struct list_head head; + struct list_head item; struct drm_device *dev; int index; diff --git a/linux-core/nv50_dac.c b/linux-core/nv50_dac.c index f51ecf9d..34b54902 100644 --- a/linux-core/nv50_dac.c +++ b/linux-core/nv50_dac.c @@ -144,7 +144,7 @@ static int nv50_dac_destroy(struct nv50_output *output) if (!display || !output) return -EINVAL; - list_del(&output->head); + list_del(&output->item); kfree(output->native_mode); if (dev_priv->free_output) @@ -197,7 +197,7 @@ int nv50_dac_create(struct drm_device *dev, int dcb_entry) output->dcb_entry = dcb_entry; output->bus = entry->bus; - list_add_tail(&output->head, &display->outputs); + list_add_tail(&output->item, &display->outputs); output->native_mode = kzalloc(sizeof(struct nouveau_hw_mode), GFP_KERNEL); if (!output->native_mode) { diff --git a/linux-core/nv50_display.c b/linux-core/nv50_display.c index 0c82ff8f..1d828552 100644 --- a/linux-core/nv50_display.c +++ b/linux-core/nv50_display.c @@ -139,14 +139,14 @@ static int nv50_display_disable(struct nv50_display *display) NV50_DEBUG("\n"); - list_for_each_entry(crtc, &display->crtcs, head) { + list_for_each_entry(crtc, &display->crtcs, item) { crtc->blank(crtc, TRUE); } display->update(display); /* Almost like ack'ing a vblank interrupt, maybe in the spirit of cleaning up? */ - list_for_each_entry(crtc, &display->crtcs, head) { + list_for_each_entry(crtc, &display->crtcs, item) { if (crtc->active) { uint32_t mask; @@ -305,15 +305,15 @@ int nv50_display_destroy(struct drm_device *dev) if (display->init_done) display->disable(display); - list_for_each_entry(connector, &display->connectors, head) { + list_for_each_entry(connector, &display->connectors, item) { connector->destroy(connector); } - list_for_each_entry(output, &display->outputs, head) { + list_for_each_entry(output, &display->outputs, item) { output->destroy(output); } - list_for_each_entry(crtc, &display->crtcs, head) { + list_for_each_entry(crtc, &display->crtcs, item) { crtc->destroy(crtc); } diff --git a/linux-core/nv50_kms_wrapper.c b/linux-core/nv50_kms_wrapper.c index 9ece228e..7f1a095b 100644 --- a/linux-core/nv50_kms_wrapper.c +++ b/linux-core/nv50_kms_wrapper.c @@ -155,11 +155,11 @@ static void nv50_kms_mirror_routing(struct drm_device *dev) struct drm_connector *drm_connector = NULL; /* Wipe all previous connections. */ - list_for_each_entry(connector, &display->connectors, head) { + list_for_each_entry(connector, &display->connectors, item) { connector->output = NULL; } - list_for_each_entry(output, &display->outputs, head) { + list_for_each_entry(output, &display->outputs, item) { output->crtc = NULL; } @@ -578,7 +578,7 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) crtc = to_nv50_crtc(set->crtc); /* disconnect unused outputs */ - list_for_each_entry(output, &display->outputs, head) { + list_for_each_entry(output, &display->outputs, item) { if (output->crtc) { crtc_mask |= 1 << output->crtc->index; } else { @@ -591,7 +591,7 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) } /* blank any unused crtcs */ - list_for_each_entry(crtc, &display->crtcs, head) { + list_for_each_entry(crtc, &display->crtcs, item) { if (!(crtc_mask & (1 << crtc->index))) crtc->blank(crtc, TRUE); } @@ -605,12 +605,12 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) } /* find native mode. */ - list_for_each_entry(output, &display->outputs, head) { + list_for_each_entry(output, &display->outputs, item) { if (output->crtc != crtc) continue; *crtc->native_mode = *output->native_mode; - list_for_each_entry(connector, &display->connectors, head) { + list_for_each_entry(connector, &display->connectors, item) { if (connector->output != output) continue; @@ -632,7 +632,7 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) goto out; } - list_for_each_entry(output, &display->outputs, head) { + list_for_each_entry(output, &display->outputs, item) { if (output->crtc != crtc) continue; @@ -653,7 +653,7 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) display->last_crtc = crtc->index; /* this is executed immediately */ - list_for_each_entry(output, &display->outputs, head) { + list_for_each_entry(output, &display->outputs, item) { if (output->crtc != crtc) continue; @@ -727,7 +727,7 @@ static int nv50_kms_crtcs_init(struct drm_device *dev) * The internal structure is already allocated and so is the public one. * Just a matter of getting to the memory and register it. */ - list_for_each_entry(crtc, &display->crtcs, head) { + list_for_each_entry(crtc, &display->crtcs, item) { struct drm_crtc *drm_crtc = to_nv50_kms_crtc(crtc); drm_crtc_init(dev, drm_crtc, &nv50_kms_crtc_funcs); @@ -759,7 +759,7 @@ static int nv50_kms_encoders_init(struct drm_device *dev) struct nv50_display *display = nv50_get_display(dev); struct nv50_output *output = NULL; - list_for_each_entry(output, &display->outputs, head) { + list_for_each_entry(output, &display->outputs, item) { struct drm_encoder *drm_encoder = to_nv50_kms_encoder(output); uint32_t type = DRM_MODE_ENCODER_NONE; @@ -1003,7 +1003,7 @@ static int nv50_kms_connectors_init(struct drm_device *dev) struct nv50_connector *connector = NULL; int i; - list_for_each_entry(connector, &display->connectors, head) { + list_for_each_entry(connector, &display->connectors, item) { struct drm_connector *drm_connector = to_nv50_kms_connector(connector); uint32_t type = DRM_MODE_CONNECTOR_Unknown; diff --git a/linux-core/nv50_output.h b/linux-core/nv50_output.h index 7a6f9c7e..a5faf050 100644 --- a/linux-core/nv50_output.h +++ b/linux-core/nv50_output.h @@ -36,7 +36,7 @@ #define OUTPUT_TV 4 struct nv50_output { - struct list_head head; + struct list_head item; struct drm_device *dev; int bus; diff --git a/linux-core/nv50_sor.c b/linux-core/nv50_sor.c index 84192803..4d82697e 100644 --- a/linux-core/nv50_sor.c +++ b/linux-core/nv50_sor.c @@ -148,7 +148,7 @@ static int nv50_sor_destroy(struct nv50_output *output) if (!display || !output) return -EINVAL; - list_del(&output->head); + list_del(&output->item); kfree(output->native_mode); if (dev_priv->free_output) @@ -205,7 +205,7 @@ int nv50_sor_create(struct drm_device *dev, int dcb_entry) output->dcb_entry = dcb_entry; output->bus = entry->bus; - list_add_tail(&output->head, &display->outputs); + list_add_tail(&output->item, &display->outputs); output->native_mode = kzalloc(sizeof(struct nouveau_hw_mode), GFP_KERNEL); if (!output->native_mode) { diff --git a/shared-core/nouveau_irq.c b/shared-core/nouveau_irq.c index e68b755f..4c46da8d 100644 --- a/shared-core/nouveau_irq.c +++ b/shared-core/nouveau_irq.c @@ -549,7 +549,7 @@ nouveau_nv50_display_irq_handler(struct drm_device *dev) if (display->last_crtc == crtc_index) clock_ack = true; - list_for_each_entry(crtc, &display->crtcs, head) { + list_for_each_entry(crtc, &display->crtcs, item) { if (crtc->index == crtc_index) break; } @@ -564,7 +564,7 @@ nouveau_nv50_display_irq_handler(struct drm_device *dev) crtc->set_clock_mode(crtc); - list_for_each_entry(output, &display->outputs, head) { + list_for_each_entry(output, &display->outputs, item) { if (!output->crtc) continue; diff --git a/shared-core/nouveau_mem.c b/shared-core/nouveau_mem.c index 46b6e4d6..425cebe2 100644 --- a/shared-core/nouveau_mem.c +++ b/shared-core/nouveau_mem.c @@ -738,7 +738,7 @@ void nouveau_mem_free(struct drm_device* dev, struct mem_block* block) struct nv50_crtc *crtc = NULL; struct nv50_display *display = nv50_get_display(dev); - list_for_each_entry(crtc, &display->crtcs, head) { + list_for_each_entry(crtc, &display->crtcs, item) { if (crtc->fb->block == block) { crtc->fb->block = NULL; -- cgit v1.2.3 From bc32d1798a213d7701b20feb95781eb51a42e945 Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Tue, 1 Jul 2008 15:14:30 +0200 Subject: NV50: some i2c cleanup --- linux-core/nv50_i2c.c | 48 +++++++++++++++++++++++++-- shared-core/nouveau_reg.h | 82 +++++++---------------------------------------- 2 files changed, 57 insertions(+), 73 deletions(-) diff --git a/linux-core/nv50_i2c.c b/linux-core/nv50_i2c.c index cf55645b..e90a4cee 100644 --- a/linux-core/nv50_i2c.c +++ b/linux-core/nv50_i2c.c @@ -28,18 +28,62 @@ #include "nv50_i2c.h" +static uint32_t nv50_i2c_port(int index) +{ + uint32_t port = 0; + + switch (index) { + case 0: + port = NV50_PCONNECTOR_I2C_PORT_0; + break; + case 1: + port = NV50_PCONNECTOR_I2C_PORT_1; + break; + case 2: + port = NV50_PCONNECTOR_I2C_PORT_2; + break; + case 3: + port = NV50_PCONNECTOR_I2C_PORT_3; + break; + case 4: + port = NV50_PCONNECTOR_I2C_PORT_4; + break; + case 5: + port = NV50_PCONNECTOR_I2C_PORT_5; + break; + default: + break; + } + + if (!port) { + DRM_ERROR("Invalid i2c port, returning 0.\n"); + BUG(); + } + + return port; +} + static void nv50_i2c_set_bits(struct nv50_i2c_channel *chan, int clock_high, int data_high) { struct drm_nouveau_private *dev_priv = chan->dev->dev_private; + uint32_t port = nv50_i2c_port(chan->index); - NV_WRITE(NV50_PCONNECTOR_I2C_PORT(chan->index), 4 | (data_high << 1) | clock_high); + if (!port) + return; + + NV_WRITE(port, 4 | (data_high << 1) | clock_high); } static void nv50_i2c_get_bits(struct nv50_i2c_channel *chan, int *clock_high, int *data_high) { struct drm_nouveau_private *dev_priv = chan->dev->dev_private; + uint32_t port = nv50_i2c_port(chan->index); + uint32_t val; + + if (!port) + return; - uint32_t val = NV_READ(NV50_PCONNECTOR_I2C_PORT(chan->index)); + val = NV_READ(port); if (val & 1) *clock_high = 1; diff --git a/shared-core/nouveau_reg.h b/shared-core/nouveau_reg.h index 8cf7f889..6ed23e26 100644 --- a/shared-core/nouveau_reg.h +++ b/shared-core/nouveau_reg.h @@ -632,90 +632,30 @@ # define NV50_PCONNECTOR_HOTPLUG_INTR_PLUG_I2C1 (1<<1) # define NV50_PCONNECTOR_HOTPLUG_INTR_PLUG_I2C2 (1<<2) # define NV50_PCONNECTOR_HOTPLUG_INTR_PLUG_I2C3 (1<<3) -# define NV50_PCONNECTOR_HOTPLUG_INTR_PLUG_I2C4 (1<<4) -# define NV50_PCONNECTOR_HOTPLUG_INTR_PLUG_I2C5 (1<<5) -# define NV50_PCONNECTOR_HOTPLUG_INTR_PLUG_I2C6 (1<<6) -# define NV50_PCONNECTOR_HOTPLUG_INTR_PLUG_I2C7 (1<<7) -# define NV50_PCONNECTOR_HOTPLUG_INTR_PLUG_I2C8 (1<<8) -# define NV50_PCONNECTOR_HOTPLUG_INTR_PLUG_I2C9 (1<<9) -# define NV50_PCONNECTOR_HOTPLUG_INTR_PLUG_I2C10 (1<<10) -# define NV50_PCONNECTOR_HOTPLUG_INTR_PLUG_I2C11 (1<<11) -# define NV50_PCONNECTOR_HOTPLUG_INTR_PLUG_I2C12 (1<<12) -# define NV50_PCONNECTOR_HOTPLUG_INTR_PLUG_I2C13 (1<<13) -# define NV50_PCONNECTOR_HOTPLUG_INTR_PLUG_I2C14 (1<<14) -# define NV50_PCONNECTOR_HOTPLUG_INTR_PLUG_I2C15 (1<<15) # define NV50_PCONNECTOR_HOTPLUG_INTR_UNPLUG_I2C0 (1<<16) # define NV50_PCONNECTOR_HOTPLUG_INTR_UNPLUG_I2C1 (1<<17) # define NV50_PCONNECTOR_HOTPLUG_INTR_UNPLUG_I2C2 (1<<18) # define NV50_PCONNECTOR_HOTPLUG_INTR_UNPLUG_I2C3 (1<<19) -# define NV50_PCONNECTOR_HOTPLUG_INTR_UNPLUG_I2C4 (1<<20) -# define NV50_PCONNECTOR_HOTPLUG_INTR_UNPLUG_I2C5 (1<<21) -# define NV50_PCONNECTOR_HOTPLUG_INTR_UNPLUG_I2C6 (1<<22) -# define NV50_PCONNECTOR_HOTPLUG_INTR_UNPLUG_I2C7 (1<<23) -# define NV50_PCONNECTOR_HOTPLUG_INTR_UNPLUG_I2C8 (1<<24) -# define NV50_PCONNECTOR_HOTPLUG_INTR_UNPLUG_I2C9 (1<<25) -# define NV50_PCONNECTOR_HOTPLUG_INTR_UNPLUG_I2C10 (1<<26) -# define NV50_PCONNECTOR_HOTPLUG_INTR_UNPLUG_I2C11 (1<<27) -# define NV50_PCONNECTOR_HOTPLUG_INTR_UNPLUG_I2C12 (1<<28) -# define NV50_PCONNECTOR_HOTPLUG_INTR_UNPLUG_I2C13 (1<<29) -# define NV50_PCONNECTOR_HOTPLUG_INTR_UNPLUG_I2C14 (1<<30) -# define NV50_PCONNECTOR_HOTPLUG_INTR_UNPLUG_I2C15 (1<<31) # define NV50_PCONNECTOR_HOTPLUG_CTRL 0x0000e054 # define NV50_PCONNECTOR_HOTPLUG_CTRL_PLUG_I2C0 (1<<0) # define NV50_PCONNECTOR_HOTPLUG_CTRL_PLUG_I2C1 (1<<1) # define NV50_PCONNECTOR_HOTPLUG_CTRL_PLUG_I2C2 (1<<2) # define NV50_PCONNECTOR_HOTPLUG_CTRL_PLUG_I2C3 (1<<3) -# define NV50_PCONNECTOR_HOTPLUG_CTRL_PLUG_I2C4 (1<<4) -# define NV50_PCONNECTOR_HOTPLUG_CTRL_PLUG_I2C5 (1<<5) -# define NV50_PCONNECTOR_HOTPLUG_CTRL_PLUG_I2C6 (1<<6) -# define NV50_PCONNECTOR_HOTPLUG_CTRL_PLUG_I2C7 (1<<7) -# define NV50_PCONNECTOR_HOTPLUG_CTRL_PLUG_I2C8 (1<<8) -# define NV50_PCONNECTOR_HOTPLUG_CTRL_PLUG_I2C9 (1<<9) -# define NV50_PCONNECTOR_HOTPLUG_CTRL_PLUG_I2C10 (1<<10) -# define NV50_PCONNECTOR_HOTPLUG_CTRL_PLUG_I2C11 (1<<11) -# define NV50_PCONNECTOR_HOTPLUG_CTRL_PLUG_I2C12 (1<<12) -# define NV50_PCONNECTOR_HOTPLUG_CTRL_PLUG_I2C13 (1<<13) -# define NV50_PCONNECTOR_HOTPLUG_CTRL_PLUG_I2C14 (1<<14) -# define NV50_PCONNECTOR_HOTPLUG_CTRL_PLUG_I2C15 (1<<15) # define NV50_PCONNECTOR_HOTPLUG_CTRL_UNPLUG_I2C0 (1<<16) # define NV50_PCONNECTOR_HOTPLUG_CTRL_UNPLUG_I2C1 (1<<17) # define NV50_PCONNECTOR_HOTPLUG_CTRL_UNPLUG_I2C2 (1<<18) # define NV50_PCONNECTOR_HOTPLUG_CTRL_UNPLUG_I2C3 (1<<19) -# define NV50_PCONNECTOR_HOTPLUG_CTRL_UNPLUG_I2C4 (1<<20) -# define NV50_PCONNECTOR_HOTPLUG_CTRL_UNPLUG_I2C5 (1<<21) -# define NV50_PCONNECTOR_HOTPLUG_CTRL_UNPLUG_I2C6 (1<<22) -# define NV50_PCONNECTOR_HOTPLUG_CTRL_UNPLUG_I2C7 (1<<23) -# define NV50_PCONNECTOR_HOTPLUG_CTRL_UNPLUG_I2C8 (1<<24) -# define NV50_PCONNECTOR_HOTPLUG_CTRL_UNPLUG_I2C9 (1<<25) -# define NV50_PCONNECTOR_HOTPLUG_CTRL_UNPLUG_I2C10 (1<<26) -# define NV50_PCONNECTOR_HOTPLUG_CTRL_UNPLUG_I2C11 (1<<27) -# define NV50_PCONNECTOR_HOTPLUG_CTRL_UNPLUG_I2C12 (1<<28) -# define NV50_PCONNECTOR_HOTPLUG_CTRL_UNPLUG_I2C13 (1<<29) -# define NV50_PCONNECTOR_HOTPLUG_CTRL_UNPLUG_I2C14 (1<<30) -# define NV50_PCONNECTOR_HOTPLUG_CTRL_UNPLUG_I2C15 (1<<31) -# define NV50_PCONNECTOR_HOTPLUG_STATE1 0x0000e104 -# define NV50_PCONNECTOR_HOTPLUG_STATE1_PIN_CONNECTED_I2C0 (1<<2) -# define NV50_PCONNECTOR_HOTPLUG_STATE1_PIN_CONNECTED_I2C1 (1<<6) -# define NV50_PCONNECTOR_HOTPLUG_STATE1_PIN_CONNECTED_I2C2 (1<<10) -# define NV50_PCONNECTOR_HOTPLUG_STATE1_PIN_CONNECTED_I2C3 (1<<14) -# define NV50_PCONNECTOR_HOTPLUG_STATE1_PIN_CONNECTED_I2C4 (1<<18) -# define NV50_PCONNECTOR_HOTPLUG_STATE1_PIN_CONNECTED_I2C5 (1<<22) -# define NV50_PCONNECTOR_HOTPLUG_STATE1_PIN_CONNECTED_I2C6 (1<<26) -# define NV50_PCONNECTOR_HOTPLUG_STATE1_PIN_CONNECTED_I2C7 (1<<30) -# define NV50_PCONNECTOR_HOTPLUG_STATE2 0x0000e108 -# define NV50_PCONNECTOR_HOTPLUG_STATE2_PIN_CONNECTED_I2C8 (1<<2) -# define NV50_PCONNECTOR_HOTPLUG_STATE2_PIN_CONNECTED_I2C9 (1<<6) -# define NV50_PCONNECTOR_HOTPLUG_STATE2_PIN_CONNECTED_I2C10 (1<<10) -# define NV50_PCONNECTOR_HOTPLUG_STATE2_PIN_CONNECTED_I2C11 (1<<14) -# define NV50_PCONNECTOR_HOTPLUG_STATE2_PIN_CONNECTED_I2C12 (1<<18) -# define NV50_PCONNECTOR_HOTPLUG_STATE2_PIN_CONNECTED_I2C13 (1<<22) -# define NV50_PCONNECTOR_HOTPLUG_STATE2_PIN_CONNECTED_I2C14 (1<<26) -# define NV50_PCONNECTOR_HOTPLUG_STATE2_PIN_CONNECTED_I2C15 (1<<30) -# define NV50_PCONNECTOR_I2C 0x0000e138 -# define NV50_PCONNECTOR_I2C__LEN 0x10 -# define NV50_PCONNECTOR_I2C__ESIZE 0x18 -# define NV50_PCONNECTOR_I2C_PORT(i) (0x0000e138+(i)*0x18) - +# define NV50_PCONNECTOR_HOTPLUG_STATE 0x0000e104 +# define NV50_PCONNECTOR_HOTPLUG_STATE_PIN_CONNECTED_I2C0 (1<<2) +# define NV50_PCONNECTOR_HOTPLUG_STATE_PIN_CONNECTED_I2C1 (1<<6) +# define NV50_PCONNECTOR_HOTPLUG_STATE_PIN_CONNECTED_I2C2 (1<<10) +# define NV50_PCONNECTOR_HOTPLUG_STATE_PIN_CONNECTED_I2C3 (1<<14) +# define NV50_PCONNECTOR_I2C_PORT_0 0x0000e138 +# define NV50_PCONNECTOR_I2C_PORT_1 0x0000e150 +# define NV50_PCONNECTOR_I2C_PORT_2 0x0000e168 +# define NV50_PCONNECTOR_I2C_PORT_3 0x0000e180 +# define NV50_PCONNECTOR_I2C_PORT_4 0x0000e240 +# define NV50_PCONNECTOR_I2C_PORT_5 0x0000e258 #define NV50_PBUS 0x00088000 #define NV50_PBUS__LEN 0x1 -- cgit v1.2.3 From 2b9c5719c09226a36a4a1e9869e6075b8ec08824 Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Tue, 1 Jul 2008 16:00:09 +0200 Subject: NV50: switch to fixed point scale factor calculations --- linux-core/nv50_crtc.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/linux-core/nv50_crtc.c b/linux-core/nv50_crtc.c index fd2ad38a..c9745e08 100644 --- a/linux-core/nv50_crtc.c +++ b/linux-core/nv50_crtc.c @@ -232,17 +232,18 @@ static int nv50_crtc_set_dither(struct nv50_crtc *crtc) static void nv50_crtc_calc_scale(struct nv50_crtc *crtc, uint32_t *outX, uint32_t *outY) { - float hor_scale, ver_scale; + uint32_t hor_scale, ver_scale; - hor_scale = (float)crtc->native_mode->hdisplay/(float)crtc->mode->hdisplay; - ver_scale = (float)crtc->native_mode->vdisplay/(float)crtc->mode->vdisplay; + /* max res is 8192, which is 2^13, which leaves 19 bits */ + hor_scale = (crtc->native_mode->hdisplay << 19)/crtc->mode->hdisplay; + ver_scale = (crtc->native_mode->vdisplay << 19)/crtc->mode->vdisplay; if (ver_scale > hor_scale) { - *outX = crtc->mode->hdisplay * hor_scale; - *outY = crtc->mode->vdisplay * hor_scale; + *outX = (crtc->mode->hdisplay * hor_scale) >> 19; + *outY = (crtc->mode->vdisplay * hor_scale) >> 19; } else { - *outX = crtc->mode->hdisplay * ver_scale; - *outY = crtc->mode->vdisplay * ver_scale; + *outX = (crtc->mode->hdisplay * ver_scale) >> 19; + *outY = (crtc->mode->vdisplay * ver_scale) >> 19; } } -- cgit v1.2.3 From b28d309210475b6f671af7617c779bd1d7a6810a Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Wed, 2 Jul 2008 13:59:19 +0200 Subject: tests: Improved and renamed the mode app to modeprint --- tests/mode/Makefile | 14 -- tests/mode/modetest.c | 409 --------------------------------------------- tests/mode/test | 1 - tests/modeprint/Makefile | 14 ++ tests/modeprint/modetest.c | 352 ++++++++++++++++++++++++++++++++++++++ tests/modeprint/test | 1 + 6 files changed, 367 insertions(+), 424 deletions(-) delete mode 100644 tests/mode/Makefile delete mode 100644 tests/mode/modetest.c delete mode 100755 tests/mode/test create mode 100644 tests/modeprint/Makefile create mode 100644 tests/modeprint/modetest.c create mode 100755 tests/modeprint/test diff --git a/tests/mode/Makefile b/tests/mode/Makefile deleted file mode 100644 index 7a9c3c24..00000000 --- a/tests/mode/Makefile +++ /dev/null @@ -1,14 +0,0 @@ - -all: app - -#CFLAGS = -g -ansi -pedantic -DPOSIX_C_SOURCE=199309L \ -# -D_POSIX_SOURCE -D_XOPEN_SOURCE -D_BSD_SOURCE -D_SVID_SOURCE \ - -app: modetest.c - @gcc $(CFLAGS) -o app -Wall -I../../libdrm -I../../shared-core -L../../libdrm/.libs -ldrm modetest.c - -clean: - @rm -f app - -run: app - @sudo ./test diff --git a/tests/mode/modetest.c b/tests/mode/modetest.c deleted file mode 100644 index bb91e832..00000000 --- a/tests/mode/modetest.c +++ /dev/null @@ -1,409 +0,0 @@ - -#include -#include -#include -#include -#include -#include - -#include "xf86drm.h" -#include "xf86drmMode.h" - -int dpms_prop_id = 0; -const char* getConnectionText(drmModeConnection conn) -{ - switch (conn) { - case DRM_MODE_CONNECTED: - return "connected"; - case DRM_MODE_DISCONNECTED: - return "disconnected"; - default: - return "unknown"; - } - -} - -int printMode(struct drm_mode_modeinfo *mode) -{ -#if 1 - printf("Mode: %s\n", mode->name); - printf("\tclock : %i\n", mode->clock); - printf("\thdisplay : %i\n", mode->hdisplay); - printf("\thsync_start : %i\n", mode->hsync_start); - printf("\thsync_end : %i\n", mode->hsync_end); - printf("\thtotal : %i\n", mode->htotal); - printf("\thskew : %i\n", mode->hskew); - printf("\tvdisplay : %i\n", mode->vdisplay); - printf("\tvsync_start : %i\n", mode->vsync_start); - printf("\tvsync_end : %i\n", mode->vsync_end); - printf("\tvtotal : %i\n", mode->vtotal); - printf("\tvscan : %i\n", mode->vscan); - printf("\tvrefresh : %i\n", mode->vrefresh); - printf("\tflags : %i\n", mode->flags); -#else - printf("Mode: \"%s\" %ix%i %.0f\n", mode->name, - mode->hdisplay, mode->vdisplay, mode->vrefresh / 1000.0); -#endif - return 0; -} - -int printConnector(int fd, drmModeResPtr res, drmModeConnectorPtr connector, uint32_t id) -{ - int i = 0, j; - struct drm_mode_modeinfo *mode = NULL; - drmModePropertyPtr props; - drmModeEncoderPtr enc; - unsigned char *name = NULL; - - printf("Connector: %d-%d\n", connector->connector_type, connector->connector_type_id); - printf("\tid : %i\n", id); - printf("\tencoder id : %i\n", connector->encoder); - printf("\tconn : %s\n", getConnectionText(connector->connection)); - printf("\tsize : %ix%i (mm)\n", connector->mmWidth, connector->mmHeight); - printf("\tcount_modes : %i\n", connector->count_modes); - printf("\tcount_props : %i\n", connector->count_props); - printf("\tcount_encs : %i\n", connector->count_encoders); - - for (i = 0; i < connector->count_encoders; i++) { - enc = drmModeGetEncoder(fd, connector->encoders[i]); - if (enc) { - printf("Encoder: %d %d %d %d %d\n", enc->crtc, enc->encoder_id, enc->encoder_type, enc->crtcs, enc->clones); - } - } - - for (i = 0; i < connector->count_props; i++) { - props = drmModeGetProperty(fd, connector->props[i]); - name = NULL; - if (props) { - printf("Property: %s\n", props->name); - printf("\tid: %i\n", props->prop_id); - printf("\tflags: %i\n", props->flags); - printf("\tvalues %d: ", props->count_values); - for (j = 0; j < props->count_values; j++) - printf("%lld ", props->values[j]); - - printf("\n\tenums %d: \n", props->count_enums); - - if (props->flags & DRM_MODE_PROP_BLOB) { - drmModePropertyBlobPtr blob; - - blob = drmModeGetPropertyBlob(fd, connector->prop_values[i]); - if (blob) { - printf("blob is %d length, %08X\n", blob->length, *(uint32_t *)blob->data); - drmModeFreePropertyBlob(blob); - } - - } else { - if (!strncmp(props->name, "DPMS", 4)) - dpms_prop_id = props->prop_id; - - for (j = 0; j < props->count_enums; j++) { - printf("\t\t%lld = %s\n", props->enums[j].value, props->enums[j].name); - if (connector->prop_values[i] == props->enums[j].value) - name = props->enums[j].name; - - } - - if (props->count_enums && name) { - printf("\tconnector property name %s %s\n", props->name, name); - } else { - printf("\tconnector property id %s %lli\n", props->name, connector->prop_values[i]); - } - } - - drmModeFreeProperty(props); - } - } - - for (i = 0; i < connector->count_modes; i++) { - mode = &connector->modes[i]; - if (mode) - printMode(mode); - else - printf("\t\tmode: Invalid mode %p\n", &connector->modes[i]); - } - - return 0; -} - -int printEncoder(int fd, drmModeResPtr res, drmModeEncoderPtr encoder, uint32_t id) -{ - printf("Encoder\n"); - printf("\tid :%i\n", id); - printf("\ttype :%d\n", encoder->encoder_type); - printf("\tcrtcs :%d\n", encoder->crtcs); - printf("\tclones :%d\n", encoder->clones); - return 0; -} - -int printCrtc(int fd, drmModeResPtr res, drmModeCrtcPtr crtc, uint32_t id) -{ - printf("Crtc\n"); - printf("\tid : %i\n", id); - printf("\tx : %i\n", crtc->x); - printf("\ty : %i\n", crtc->y); - printf("\twidth : %i\n", crtc->width); - printf("\theight : %i\n", crtc->height); - printf("\tmode : %p\n", &crtc->mode); - printf("\tgamma size : %d\n", crtc->gamma_size); - printf("\tnum connectors : %i\n", crtc->count_connectors); - printf("\tconnectors : %i\n", crtc->connectors); - printf("\tnum possible : %i\n", crtc->count_possibles); - printf("\tpossibles : %i\n", crtc->possibles); - - return 0; -} - -int printFrameBuffer(int fd, drmModeResPtr res, drmModeFBPtr fb) -{ - printf("Framebuffer\n"); - printf("\thandle : %i\n", fb->handle); - printf("\twidth : %i\n", fb->width); - printf("\theight : %i\n", fb->height); - printf("\tpitch : %i\n", fb->pitch);; - printf("\tbpp : %i\n", fb->bpp); - printf("\tdepth : %i\n", fb->depth); - printf("\tbuffer_id : %i\n", fb->buffer_id); - - return 0; -} - -int printRes(int fd, drmModeResPtr res) -{ - int i; - drmModeConnectorPtr connector; - drmModeCrtcPtr crtc; - drmModeFBPtr fb; - drmModeEncoderPtr encoder; - - for (i = 0; i < res->count_connectors; i++) { - connector = drmModeGetConnector(fd, res->connectors[i]); - - if (!connector) - printf("Could not get connector %i\n", i); - else { - printConnector(fd, res, connector, res->connectors[i]); - drmModeFreeConnector(connector); - } - } - - for (i = 0; i < res->count_encoders; i++) { - encoder = drmModeGetEncoder(fd, res->encoders[i]); - - if (!encoder) - printf("Could not get encoder %i\n", i); - else { - printEncoder(fd, res, encoder, res->encoders[i]); - drmModeFreeEncoder(encoder); - } - } - - - for (i = 0; i < res->count_crtcs; i++) { - crtc = drmModeGetCrtc(fd, res->crtcs[i]); - - if (!crtc) - printf("Could not get crtc %i\n", i); - else { - printCrtc(fd, res, crtc, res->crtcs[i]); - drmModeFreeCrtc(crtc); - } - } - - for (i = 0; i < res->count_fbs; i++) { - fb = drmModeGetFB(fd, res->fbs[i]); - - if (!fb) - printf("Could not get fb %i\n", res->fbs[i]); - else { - printFrameBuffer(fd, res, fb); - drmModeFreeFB(fb); - } - } - - return 0; -} - -static struct drm_mode_modeinfo mode = { - .name = "Test mode", - .clock = 25200, - .hdisplay = 640, - .hsync_start = 656, - .hsync_end = 752, - .htotal = 800, - .hskew = 0, - .vdisplay = 480, - .vsync_start = 490, - .vsync_end = 492, - .vtotal = 525, - .vscan = 0, - .vrefresh = 60000, /* vertical refresh * 1000 */ - .flags = 10, -}; - -int testMode(int fd, drmModeResPtr res) -{ - uint32_t connector = res->connectors[0]; - uint32_t newMode = 0; - int ret = 0; - int error = 0; - - printf("Test: adding mode to connector %i\n", connector); - - /* printMode(&mode); */ - - printf("\tAttaching mode %i to connector %i\n", newMode, connector); - - ret = drmModeAttachMode(fd, connector, &mode); - - if (ret) - goto err_mode; - - printf("\tDetaching mode %i from connector %i\n", newMode, connector); - ret = drmModeDetachMode(fd, connector, &mode); - - if (ret) - goto err_mode; - return 0; - -err_mode: - - printf("\tFailed\n"); - - if (error) - printf("\tFailed to delete mode %i\n", newMode); - return 1; -} - -/* -int testFrameBufferGet(int fd, uint32_t fb) -{ - drmModeFBPtr frame; - - printf("Test: get framebuffer %i\n", fb); - - frame = drmModeGetFB(fd, fb); - - if (!frame) { - printf("\tFailed\n"); - } else { - printFrameBuffer(fd, frame); - drmModeFreeFB(frame); - } - - return 0; -} -*/ - -int testFrameBufferAdd(int fd, drmModeResPtr res) -{ - uint32_t fb = 0; - int ret = 0; - drmModeFBPtr frame = 0; - drmBO bo; - - printf("Test: adding framebuffer\n"); - - printf("\tCreating BO\n"); - - /* TODO */ - ret = drmBOCreate(fd, 800 * 600 * 4, 0, 0, - DRM_BO_FLAG_READ | - DRM_BO_FLAG_WRITE | - DRM_BO_FLAG_MEM_TT | - DRM_BO_FLAG_MEM_VRAM | - DRM_BO_FLAG_NO_EVICT, - DRM_BO_HINT_DONT_FENCE, &bo); - - printf("\tgot %i\n", ret); - if (ret) - goto err; - - printf("\tAdding FB\n"); - ret = drmModeAddFB(fd, 800, 600, 32, 8, 0, bo.handle, &fb); - if (ret) - goto err_bo; - - frame = drmModeGetFB(fd, fb); - - if (!frame) { - printf("Couldn't retrive created framebuffer\n"); - } else { - printFrameBuffer(fd, res, frame); - drmModeFreeFB(frame); - } - - printf("\tRemoveing FB\n"); - - ret = drmModeRmFB(fd, fb); - - if (ret) { - printf("\tFailed this shouldn't happen!\n"); - goto err_bo; - } - - printf("\tRemoveing BO\n"); - - ret = drmBOUnreference(fb, &bo); - - return 0; - -err_bo: - drmBOUnreference(fd, &bo); - -err: - printf("\tFailed\n"); - - return 1; -} - -int testDPMS(int fd, drmModeResPtr res) -{ - int connector_id; - int i; - - for (i = 0; i < res->count_connectors; i++) { - connector_id = res->connectors[i]; - /* turn connector off */ - drmModeConnectorSetProperty(fd, connector_id, dpms_prop_id, 3); - sleep(2); - drmModeConnectorSetProperty(fd, connector_id, dpms_prop_id, 0); - } - return 1; - -} - -int main(int argc, char **argv) -{ - int fd; - drmModeResPtr res; - - printf("Starting test\n"); - - fd = drmOpen("i915", NULL); - - if (fd < 0) { - printf("Failed to open the card fb (%d)\n",fd); - return 1; - } - - res = drmModeGetResources(fd); - if (res == 0) { - printf("Failed to get resources from card\n"); - drmClose(fd); - return 1; - } - - printRes(fd, res); - - testMode(fd, res); - - testFrameBufferAdd(fd, res); - - /* try dpms test */ - testDPMS(fd, res); - drmModeFreeResources(res); - printf("Ok\n"); - - return 0; -} diff --git a/tests/mode/test b/tests/mode/test deleted file mode 100755 index f98e3708..00000000 --- a/tests/mode/test +++ /dev/null @@ -1 +0,0 @@ -LD_PRELOAD=../../libdrm/.libs/libdrm.so ./app diff --git a/tests/modeprint/Makefile b/tests/modeprint/Makefile new file mode 100644 index 00000000..7a9c3c24 --- /dev/null +++ b/tests/modeprint/Makefile @@ -0,0 +1,14 @@ + +all: app + +#CFLAGS = -g -ansi -pedantic -DPOSIX_C_SOURCE=199309L \ +# -D_POSIX_SOURCE -D_XOPEN_SOURCE -D_BSD_SOURCE -D_SVID_SOURCE \ + +app: modetest.c + @gcc $(CFLAGS) -o app -Wall -I../../libdrm -I../../shared-core -L../../libdrm/.libs -ldrm modetest.c + +clean: + @rm -f app + +run: app + @sudo ./test diff --git a/tests/modeprint/modetest.c b/tests/modeprint/modetest.c new file mode 100644 index 00000000..36925a0b --- /dev/null +++ b/tests/modeprint/modetest.c @@ -0,0 +1,352 @@ + +#include +#include +#include +#include +#include +#include + +#include "xf86drm.h" +#include "xf86drmMode.h" + +int connectors; +int full_props; +int edid; +int modes; +int full_modes; +int encoders; +int crtcs; +int fbs; + +const char* getConnectionText(drmModeConnection conn) +{ + switch (conn) { + case DRM_MODE_CONNECTED: + return "connected"; + case DRM_MODE_DISCONNECTED: + return "disconnected"; + default: + return "unknown"; + } + +} + +int printMode(struct drm_mode_modeinfo *mode) +{ + if (full_modes) { + printf("Mode: %s\n", mode->name); + printf("\tclock : %i\n", mode->clock); + printf("\thdisplay : %i\n", mode->hdisplay); + printf("\thsync_start : %i\n", mode->hsync_start); + printf("\thsync_end : %i\n", mode->hsync_end); + printf("\thtotal : %i\n", mode->htotal); + printf("\thskew : %i\n", mode->hskew); + printf("\tvdisplay : %i\n", mode->vdisplay); + printf("\tvsync_start : %i\n", mode->vsync_start); + printf("\tvsync_end : %i\n", mode->vsync_end); + printf("\tvtotal : %i\n", mode->vtotal); + printf("\tvscan : %i\n", mode->vscan); + printf("\tvrefresh : %i\n", mode->vrefresh); + printf("\tflags : %i\n", mode->flags); + } else { + printf("Mode: \"%s\" %ix%i %.0f\n", mode->name, + mode->hdisplay, mode->vdisplay, mode->vrefresh / 1000.0); + } + return 0; +} + +int printConnector(int fd, drmModeResPtr res, drmModeConnectorPtr connector, uint32_t id) +{ + int i = 0, j; + struct drm_mode_modeinfo *mode = NULL; + drmModePropertyPtr props; + unsigned char *name = NULL; + + printf("Connector: %d-%d\n", connector->connector_type, connector->connector_type_id); + printf("\tid : %i\n", id); + printf("\tencoder id : %i\n", connector->encoder); + printf("\tconn : %s\n", getConnectionText(connector->connection)); + printf("\tsize : %ix%i (mm)\n", connector->mmWidth, connector->mmHeight); + printf("\tcount_modes : %i\n", connector->count_modes); + printf("\tcount_props : %i\n", connector->count_props); + printf("\tcount_encoders : %i\n", connector->count_encoders); + + if (connector->count_encoders) { + printf("\t\tencoders"); + for (i = 0; i < connector->count_encoders; i++) + printf(" %i", connector->encoders[i]); + printf("\n"); + } + + if (full_props) { + for (i = 0; i < connector->count_props; i++) { + props = drmModeGetProperty(fd, connector->props[i]); + name = NULL; + if (props) { + printf("Property: %s\n", props->name); + printf("\tid: %i\n", props->prop_id); + printf("\tflags: %i\n", props->flags); + printf("\tvalues %d: ", props->count_values); + for (j = 0; j < props->count_values; j++) + printf("%lld ", props->values[j]); + + printf("\n\tenums %d: \n", props->count_enums); + + if (props->flags & DRM_MODE_PROP_BLOB) { + drmModePropertyBlobPtr blob; + + blob = drmModeGetPropertyBlob(fd, connector->prop_values[i]); + if (blob) { + printf("blob is %d length, %08X\n", blob->length, *(uint32_t *)blob->data); + drmModeFreePropertyBlob(blob); + } + + } else { + if (!strncmp(props->name, "DPMS", 4)) + ; + + for (j = 0; j < props->count_enums; j++) { + printf("\t\t%lld = %s\n", props->enums[j].value, props->enums[j].name); + if (connector->prop_values[i] == props->enums[j].value) + name = props->enums[j].name; + + } + + if (props->count_enums && name) { + printf("\tconnector property name %s %s\n", props->name, name); + } else { + printf("\tconnector property id %s %lli\n", props->name, connector->prop_values[i]); + } + } + + drmModeFreeProperty(props); + } + } + } else { + if (connector->count_props) { + printf("\t\tprops"); + for (i = 0; i < connector->count_props; i++) + printf(" %i", connector->props[i]); + printf("\n"); + } + } + + if (modes) { + for (i = 0; i < connector->count_modes; i++) { + mode = &connector->modes[i]; + printMode(mode); + } + } + + return 0; +} + +int printEncoder(int fd, drmModeResPtr res, drmModeEncoderPtr encoder, uint32_t id) +{ + printf("Encoder\n"); + printf("\tid :%i\n", id); + printf("\tcrtc :%d\n", encoder->crtc); + printf("\ttype :%d\n", encoder->encoder_type); + printf("\tcrtcs :%d\n", encoder->crtcs); + printf("\tclones :%d\n", encoder->clones); + return 0; +} + +int printCrtc(int fd, drmModeResPtr res, drmModeCrtcPtr crtc, uint32_t id) +{ + printf("Crtc\n"); + printf("\tid : %i\n", id); + printf("\tx : %i\n", crtc->x); + printf("\ty : %i\n", crtc->y); + printf("\twidth : %i\n", crtc->width); + printf("\theight : %i\n", crtc->height); + printf("\tmode : %p\n", &crtc->mode); + printf("\tgamma size : %d\n", crtc->gamma_size); + printf("\tnum connectors : %i\n", crtc->count_connectors); + printf("\tconnectors : %i\n", crtc->connectors); + printf("\tnum possible : %i\n", crtc->count_possibles); + printf("\tpossibles : %i\n", crtc->possibles); + + return 0; +} + +int printFrameBuffer(int fd, drmModeResPtr res, drmModeFBPtr fb) +{ + printf("Framebuffer\n"); + printf("\thandle : %i\n", fb->handle); + printf("\twidth : %i\n", fb->width); + printf("\theight : %i\n", fb->height); + printf("\tpitch : %i\n", fb->pitch);; + printf("\tbpp : %i\n", fb->bpp); + printf("\tdepth : %i\n", fb->depth); + printf("\tbuffer_id : %i\n", fb->buffer_id); + + return 0; +} + +int printRes(int fd, drmModeResPtr res) +{ + int i; + drmModeFBPtr fb; + drmModeCrtcPtr crtc; + drmModeEncoderPtr encoder; + drmModeConnectorPtr connector; + + printf("Resources\n\n"); + + printf("count_connectors : %i\n", res->count_connectors); + printf("count_encoders : %i\n", res->count_encoders); + printf("count_crtcs : %i\n", res->count_crtcs); + printf("count_fbs : %i\n", res->count_fbs); + + printf("\n"); + + if (connectors) { + for (i = 0; i < res->count_connectors; i++) { + connector = drmModeGetConnector(fd, res->connectors[i]); + + if (!connector) + printf("Could not get connector %i\n", i); + else { + printConnector(fd, res, connector, res->connectors[i]); + drmModeFreeConnector(connector); + } + } + printf("\n"); + } + + + if (encoders) { + for (i = 0; i < res->count_encoders; i++) { + encoder = drmModeGetEncoder(fd, res->encoders[i]); + + if (!encoder) + printf("Could not get encoder %i\n", i); + else { + printEncoder(fd, res, encoder, res->encoders[i]); + drmModeFreeEncoder(encoder); + } + } + printf("\n"); + } + + if (crtcs) { + for (i = 0; i < res->count_crtcs; i++) { + crtc = drmModeGetCrtc(fd, res->crtcs[i]); + + if (!crtc) + printf("Could not get crtc %i\n", i); + else { + printCrtc(fd, res, crtc, res->crtcs[i]); + drmModeFreeCrtc(crtc); + } + } + printf("\n"); + } + + if (fbs) { + for (i = 0; i < res->count_fbs; i++) { + fb = drmModeGetFB(fd, res->fbs[i]); + + if (!fb) + printf("Could not get fb %i\n", res->fbs[i]); + else { + printFrameBuffer(fd, res, fb); + drmModeFreeFB(fb); + } + } + } + + return 0; +} + +void args(int argc, char **argv) +{ + int i; + + fbs = 0; + edid = 0; + crtcs = 0; + modes = 0; + encoders = 0; + full_modes = 0; + full_props = 0; + connectors = 0; + + for (i = 1; i < argc; i++) { + if (strcmp(argv[i], "-fb") == 0) { + fbs = 1; + } else if (strcmp(argv[i], "-crtcs") == 0) { + crtcs = 1; + } else if (strcmp(argv[i], "-cons") == 0) { + connectors = 1; + modes = 1; + } else if (strcmp(argv[i], "-modes") == 0) { + connectors = 1; + modes = 1; + } else if (strcmp(argv[i], "-full") == 0) { + connectors = 1; + modes = 1; + full_modes = 1; + } else if (strcmp(argv[i], "-props") == 0) { + connectors = 1; + full_props = 1; + } else if (strcmp(argv[i], "-edids") == 0) { + connectors = 1; + edid = 1; + } else if (strcmp(argv[i], "-encoders") == 0) { + encoders = 1; + } else if (strcmp(argv[i], "-v") == 0) { + fbs = 1; + edid = 1; + crtcs = 1; + modes = 1; + encoders = 1; + full_modes = 1; + full_props = 1; + connectors = 1; + } + } + + if (argc == 1) { + fbs = 1; + modes = 1; + full_modes = 0; + encoders = 1; + connectors = 1; + crtcs = 1; + full_props = 0; + edid = 1; + } +} +int main(int argc, char **argv) +{ + int fd; + drmModeResPtr res; + + args(argc, argv); + + printf("Starting test\n"); + + fd = drmOpen("i915", NULL); + + if (fd < 0) { + printf("Failed to open the card fb (%d)\n",fd); + return 1; + } + + res = drmModeGetResources(fd); + if (res == 0) { + printf("Failed to get resources from card\n"); + drmClose(fd); + return 1; + } + + printRes(fd, res); + + drmModeFreeResources(res); + + printf("Ok\n"); + + return 0; +} diff --git a/tests/modeprint/test b/tests/modeprint/test new file mode 100755 index 00000000..bd1952cc --- /dev/null +++ b/tests/modeprint/test @@ -0,0 +1 @@ +LD_PRELOAD=../../libdrm/.libs/libdrm.so ./app $@ -- cgit v1.2.3 From f1fe9178f1a2aef272c7feeb15c8de42c8c609d5 Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Wed, 2 Jul 2008 16:13:54 +0200 Subject: NV50: basic fbcon + misc fixes - There is one fb, used for as many outputs as possible. - Eventually smaller screens will be scaled to see the full console, but for the moment this'll do. --- linux-core/Makefile.kernel | 3 +- linux-core/nv50_display.c | 3 +- linux-core/nv50_fbcon.c | 599 ++++++++++++++++++++++++++++++++++++++++++ linux-core/nv50_fbcon.h | 41 +++ linux-core/nv50_kms_wrapper.c | 12 +- shared-core/nouveau_state.c | 5 +- 6 files changed, 657 insertions(+), 6 deletions(-) create mode 100644 linux-core/nv50_fbcon.c create mode 100644 linux-core/nv50_fbcon.h diff --git a/linux-core/Makefile.kernel b/linux-core/Makefile.kernel index 23430140..246c0b35 100644 --- a/linux-core/Makefile.kernel +++ b/linux-core/Makefile.kernel @@ -38,7 +38,8 @@ nouveau-objs := nouveau_drv.o nouveau_state.o nouveau_fifo.o nouveau_mem.o \ nv04_instmem.o nv50_instmem.o \ nouveau_bios.o \ nv50_crtc.o nv50_cursor.o nv50_lut.o nv50_fb.o nv50_output.o nv50_sor.o nv50_dac.o nv50_connector.o nv50_i2c.o nv50_display.o \ - nv50_kms_wrapper.o + nv50_kms_wrapper.o \ + nv50_fbcon.o radeon-objs := radeon_drv.o radeon_cp.o radeon_state.o radeon_mem.o radeon_irq.o r300_cmdbuf.o radeon_ms-objs := radeon_ms_drv.o radeon_ms_drm.o radeon_ms_family.o \ radeon_ms_state.o radeon_ms_bo.o radeon_ms_irq.o \ diff --git a/linux-core/nv50_display.c b/linux-core/nv50_display.c index 1d828552..cd527c44 100644 --- a/linux-core/nv50_display.c +++ b/linux-core/nv50_display.c @@ -337,10 +337,11 @@ void nv50_display_command(struct drm_nouveau_private *dev_priv, uint32_t mthd, u while (NV_READ(NV50_PDISPLAY_CTRL_STATE) & NV50_PDISPLAY_CTRL_STATE_PENDING) { counter++; - if (counter > 25000) { + if (counter > 1000000) { DRM_ERROR("You probably need a reboot now\n"); break; } + udelay(1); } } diff --git a/linux-core/nv50_fbcon.c b/linux-core/nv50_fbcon.c new file mode 100644 index 00000000..c428ff94 --- /dev/null +++ b/linux-core/nv50_fbcon.c @@ -0,0 +1,599 @@ +/* + * Copyright (C) 2008 Maarten Maathuis. + * All Rights Reserved. + * + * 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 (including the + * next paragraph) 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 OWNER(S) AND/OR ITS SUPPLIERS 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "nv50_fbcon.h" + +static int nv50_fbcon_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + struct fb_info *info) +{ + struct nv50_fbcon_par *par = info->par; + struct drm_device *dev = par->dev; + struct drm_framebuffer *drm_fb; + + list_for_each_entry(drm_fb, &dev->mode_config.fb_kernel_list, filp_head) { + if (regno > 255) + return 1; + + /* TODO: 8 bit support */ + if (regno < 16) { + switch (drm_fb->depth) { + case 15: + drm_fb->pseudo_palette[regno] = ((red & 0xf800) >> 1) | + ((green & 0xf800) >> 6) | + ((blue & 0xf800) >> 11); + break; + case 16: + drm_fb->pseudo_palette[regno] = (red & 0xf800) | + ((green & 0xfc00) >> 5) | + ((blue & 0xf800) >> 11); + break; + case 24: + case 32: + drm_fb->pseudo_palette[regno] = ((red & 0xff00) << 8) | + (green & 0xff00) | + ((blue & 0xff00) >> 8); + break; + } + } + } + return 0; +} + +static int nv50_fbcon_check_var(struct fb_var_screeninfo *var, struct fb_info *info) +{ + struct nv50_fbcon_par *par = info->par; + struct drm_framebuffer *drm_fb = par->fb; + int depth; + + NV50_DEBUG("\n"); + + if (!var || !drm_fb || !info) { + DRM_ERROR("No var, drm_fb or info\n"); + } + + par->use_preferred_mode = false; + + if (var->pixclock == -1 || !var->pixclock) { + DRM_INFO("Using preferred mode.\n"); + par->use_preferred_mode = true; + } + + /* Need to resize the fb object !!! */ + if (var->xres > drm_fb->width || var->yres > drm_fb->height) { + DRM_ERROR("Requested width/height is greater than current fb object %dx%d > %dx%d\n", var->xres,var->yres, drm_fb->width, drm_fb->height); + DRM_ERROR("Need resizing code.\n"); + return -EINVAL; + } + + switch (var->bits_per_pixel) { + case 16: + depth = (var->green.length == 6) ? 16 : 15; + break; + case 32: + depth = (var->transp.length > 0) ? 32 : 24; + break; + default: + depth = var->bits_per_pixel; + break; + } + + switch (depth) { + case 15: + var->red.offset = 10; + var->green.offset = 5; + var->blue.offset = 0; + var->red.length = 5; + var->green.length = 5; + var->blue.length = 5; + var->transp.length = 1; + var->transp.offset = 15; + break; + case 16: + var->red.offset = 11; + var->green.offset = 5; + var->blue.offset = 0; + var->red.length = 5; + var->green.length = 6; + var->blue.length = 5; + var->transp.length = 0; + var->transp.offset = 0; + break; + case 24: + var->red.offset = 16; + var->green.offset = 8; + var->blue.offset = 0; + var->red.length = 8; + var->green.length = 8; + var->blue.length = 8; + var->transp.length = 0; + var->transp.offset = 0; + break; + case 32: + var->red.offset = 16; + var->green.offset = 8; + var->blue.offset = 0; + var->red.length = 8; + var->green.length = 8; + var->blue.length = 8; + var->transp.length = 8; + var->transp.offset = 24; + break; + default: + DRM_ERROR("Invalid depth %d\n", depth); + return -EINVAL; + } + + return 0; +} + +static int nv50_fbcon_set_par(struct fb_info *info) +{ + struct nv50_fbcon_par *par; + struct drm_framebuffer *drm_fb; + struct drm_connector *drm_connector; + struct drm_crtc *drm_crtc; + struct fb_var_screeninfo *var; + struct drm_display_mode *drm_mode = NULL, *t; + struct drm_device *dev; + int rval; + bool crtc_used[2] = {false, false}; + + NV50_DEBUG("\n"); + + if (!info) { + DRM_ERROR("No fb_info\n"); + return -EINVAL; + } + + par = info->par; + + if (!par) { + DRM_ERROR("No nv50_fbcon_par\n"); + return -EINVAL; + } + + drm_fb = par->fb; + var = &info->var; + dev = par->dev; + + if (!drm_fb || !var || !dev) { + DRM_ERROR("No drm_fb, var or dev\n"); + return -EINVAL; + } + + par->use_preferred_mode = false; + + if (var->pixclock == -1 || !var->pixclock) { + DRM_INFO("Using preferred mode.\n"); + par->use_preferred_mode = true; + } + + /* FB setup */ + switch (var->bits_per_pixel) { + case 16: + drm_fb->depth = (var->green.length == 6) ? 16 : 15; + break; + case 32: + drm_fb->depth = (var->transp.length > 0) ? 32 : 24; + break; + default: + drm_fb->depth = var->bits_per_pixel; + break; + } + + drm_fb->bits_per_pixel = var->bits_per_pixel; + + info->fix.line_length = drm_fb->pitch; + info->fix.smem_len = info->fix.line_length * drm_fb->height; + /* ignoring 8bpp for the moment */ + info->fix.visual = FB_VISUAL_TRUECOLOR; + + info->screen_size = info->fix.smem_len; /* ??? */ + + /* create a drm mode */ + if (!par->use_preferred_mode) { + drm_mode = drm_mode_create(dev); + drm_mode->hdisplay = var->xres; + drm_mode->hsync_start = drm_mode->hdisplay + var->right_margin; + drm_mode->hsync_end = drm_mode->hsync_start + var->hsync_len; + drm_mode->htotal = drm_mode->hsync_end + var->left_margin; + drm_mode->vdisplay = var->yres; + drm_mode->vsync_start = drm_mode->vdisplay + var->lower_margin; + drm_mode->vsync_end = drm_mode->vsync_start + var->vsync_len; + drm_mode->vtotal = drm_mode->vsync_end + var->upper_margin; + drm_mode->clock = PICOS2KHZ(var->pixclock); + drm_mode->vrefresh = drm_mode_vrefresh(drm_mode); + drm_mode->flags = 0; + drm_mode->flags |= var->sync & FB_SYNC_HOR_HIGH_ACT ? V_PHSYNC : V_NHSYNC; + drm_mode->flags |= var->sync & FB_SYNC_VERT_HIGH_ACT ? V_PVSYNC : V_NVSYNC; + + drm_mode_set_name(drm_mode); + drm_mode_set_crtcinfo(drm_mode, CRTC_INTERLACE_HALVE_V); + } + + /* hook up crtc's */ + list_for_each_entry(drm_connector, &dev->mode_config.connector_list, head) { + enum drm_connector_status status; + struct drm_mode_set mode_set; + int crtc_count = 0; + + status = drm_connector->funcs->detect(drm_connector); + + if (status != connector_status_connected) + continue; + + memset(&mode_set, 0, sizeof(struct drm_mode_set)); + + /* set connector */ + mode_set.num_connectors = 1; + mode_set.connectors = kzalloc(sizeof(struct drm_connector *), GFP_KERNEL); + if (!mode_set.connectors) { + rval = -ENOMEM; + goto out; + } + mode_set.connectors[0] = drm_connector; + + /* set fb */ + list_for_each_entry(drm_fb, &dev->mode_config.fb_kernel_list, filp_head) { + break; /* first entry is the only entry */ + } + mode_set.fb = drm_fb; + + /* set mode */ + if (par->use_preferred_mode) { + /* find preferred mode */ + list_for_each_entry_safe(drm_mode, t, &drm_connector->modes, head) { + if (drm_mode->type & DRM_MODE_TYPE_PREFERRED) + break; + } + } + mode_set.mode = drm_mode; + + list_for_each_entry(drm_crtc, &dev->mode_config.crtc_list, head) { + if (crtc_used[crtc_count]) { + crtc_count++; + continue; + } + + /* found a crtc */ + mode_set.crtc = drm_crtc; + + break; + } + + /* proceed as planned */ + if (mode_set.crtc) { + mode_set.crtc->funcs->set_config(&mode_set); + crtc_used[crtc_count] = true; + } + + kfree(mode_set.connectors); + } + + return 0; + +out: + return rval; +} + +static struct fb_ops nv50_fb_ops = { + .owner = THIS_MODULE, + //.fb_open = nv50_fb_open, + //.fb_read = nv50_fb_read, + //.fb_write = nv50_fb_write, + //.fb_release = nv50_fb_release, + //.fb_ioctl = nv50_fb_ioctl, + .fb_check_var = nv50_fbcon_check_var, + .fb_set_par = nv50_fbcon_set_par, + .fb_setcolreg = nv50_fbcon_setcolreg, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + //.fb_pan_display = nv50_fb_pan_display, +}; + +static int nv50_fbcon_initial_config(struct drm_device *dev) +{ + struct drm_connector *drm_connector; + + struct drm_framebuffer *drm_fb = NULL; + struct drm_mode_fb_cmd drm_fb_cmd; + enum drm_connector_status status; + uint32_t max_width = 0, max_height = 0, pitch = 0; + struct mem_block *block; + struct drm_file *file_priv; + uint32_t flags; + int rval = 0; + + list_for_each_entry(drm_connector, &dev->mode_config.connector_list, head) { + status = drm_connector->funcs->detect(drm_connector); + + /* find the framebuffer size */ + if (status == connector_status_connected) { + struct drm_display_mode *mode, *t; + list_for_each_entry_safe(mode, t, &drm_connector->modes, head) { + if (mode->type & DRM_MODE_TYPE_PREFERRED) { + if (mode->hdisplay > max_width) + max_width = mode->hdisplay; + if (mode->vdisplay > max_height) + max_height = mode->vdisplay; + } + } + } + } + + /* allocate framebuffer */ + file_priv = kzalloc(sizeof(struct drm_file), GFP_KERNEL); + if (!file_priv) { + rval = -ENOMEM; + goto out; + } + + pitch = (max_width + 63) & ~63; + pitch *= 4; /* TODO */ + + flags = NOUVEAU_MEM_FB | NOUVEAU_MEM_MAPPED; + + /* Any file_priv should do as it's pointer is used as identification. */ + block = nouveau_mem_alloc(dev, 0, pitch * max_height, flags, file_priv); + if (!block) { + rval = -ENOMEM; + goto out; + } + + memset(&drm_fb_cmd, 0, sizeof(struct drm_mode_fb_cmd)); + + drm_fb_cmd.width = max_width; + drm_fb_cmd.height = max_height; + drm_fb_cmd.pitch = pitch; + drm_fb_cmd.bpp = 32; /* TODO */ + drm_fb_cmd.handle = block->map_handle; + drm_fb_cmd.depth = 24; /* TODO */ + + drm_fb = dev->mode_config.funcs->fb_create(dev, file_priv, &drm_fb_cmd); + if (!drm_fb) { + rval = -EINVAL; + goto out; + } + + list_add(&drm_fb->filp_head, &dev->mode_config.fb_kernel_list); + + return 0; + +out: + if (file_priv) + kfree(file_priv); + if (drm_fb) + drm_fb->funcs->destroy(drm_fb); + + return rval; +} + +/* + * Single framebuffer, ideally operating in clone mode across various connectors. + */ +int nv50_fbcon_init(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct fb_info *info; + struct nv50_fbcon_par *par; + struct device *device = &dev->pdev->dev; + struct drm_framebuffer *drm_fb; + struct mem_block *block; + void __iomem *fb = NULL; + int rval; + + rval = nv50_fbcon_initial_config(dev); + if (rval != 0) { + DRM_ERROR("nv50_fbcon_initial_config failed\n"); + return rval; + } + + list_for_each_entry(drm_fb, &dev->mode_config.fb_kernel_list, filp_head) { + break; /* first entry is the only entry */ + } + + if (!drm_fb) { + DRM_ERROR("no drm_fb found\n"); + return -EINVAL; + } + + block = find_block_by_handle(dev_priv->fb_heap, drm_fb->mm_handle); + if (!block) { + DRM_ERROR("can't find mem_block\n"); + return -EINVAL; + } + + info = framebuffer_alloc(sizeof(struct nv50_fbcon_par), device); + if (!info) { + DRM_ERROR("framebuffer_alloc failed\n"); + return -EINVAL; + } + + par = info->par; + + strcpy(info->fix.id, "nv50drmfb"); + info->fix.type = FB_TYPE_PACKED_PIXELS; + info->fix.visual = FB_VISUAL_TRUECOLOR; + info->fix.type_aux = 0; + info->fix.xpanstep = 0; /* 1 is doing it in hw */ + info->fix.ypanstep = 0; + info->fix.ywrapstep = 0; + info->fix.accel = FB_ACCEL_NONE; + info->fix.type_aux = 0; + + info->flags = FBINFO_DEFAULT; + + info->fbops = &nv50_fb_ops; + + info->fix.line_length = drm_fb->pitch; + info->fix.smem_start = dev_priv->fb_phys + block->start; + info->fix.smem_len = info->fix.line_length * drm_fb->height; + + info->flags = FBINFO_DEFAULT; + + fb = ioremap(dev_priv->fb_phys + block->start, block->size); + if (!fb) { + DRM_ERROR("Unable to ioremap framebuffer\n"); + return -EINVAL; + } + + info->screen_base = fb; + info->screen_size = info->fix.smem_len; /* FIXME */ + + info->pseudo_palette = drm_fb->pseudo_palette; + info->var.xres_virtual = drm_fb->width; + info->var.yres_virtual = drm_fb->height; + info->var.bits_per_pixel = drm_fb->bits_per_pixel; + info->var.xoffset = 0; + info->var.yoffset = 0; + info->var.activate = FB_ACTIVATE_NOW; + info->var.height = -1; + info->var.width = -1; + + /* TODO: improve this */ + info->var.xres = drm_fb->width; + info->var.yres = drm_fb->height; + + info->fix.mmio_start = drm_get_resource_start(dev, 0); + info->fix.mmio_len = drm_get_resource_len(dev, 0); + + DRM_DEBUG("fb depth is %d\n", drm_fb->depth); + DRM_DEBUG(" pitch is %d\n", drm_fb->pitch); + + switch(drm_fb->depth) { + case 15: + info->var.red.offset = 10; + info->var.green.offset = 5; + info->var.blue.offset = 0; + info->var.red.length = 5; + info->var.green.length = 5; + info->var.blue.length = 5; + info->var.transp.offset = 15; + info->var.transp.length = 1; + break; + case 16: + info->var.red.offset = 11; + info->var.green.offset = 5; + info->var.blue.offset = 0; + info->var.red.length = 5; + info->var.green.length = 6; + info->var.blue.length = 5; + info->var.transp.offset = 0; + break; + case 24: + info->var.red.offset = 16; + info->var.green.offset = 8; + info->var.blue.offset = 0; + info->var.red.length = 8; + info->var.green.length = 8; + info->var.blue.length = 8; + info->var.transp.offset = 0; + info->var.transp.length = 0; + break; + case 32: + info->var.red.offset = 16; + info->var.green.offset = 8; + info->var.blue.offset = 0; + info->var.red.length = 8; + info->var.green.length = 8; + info->var.blue.length = 8; + info->var.transp.offset = 24; + info->var.transp.length = 8; + break; + default: + break; + } + + drm_fb->fbdev = info; + par->dev = dev; + par->fb = drm_fb; + + register_framebuffer(info); + + DRM_INFO("nv50drmfb initialised\n"); + + return 0; +} + +int nv50_fbcon_destroy(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct drm_framebuffer *drm_fb; + struct fb_info *info; + struct mem_block *block; + struct drm_file *file_priv; + + list_for_each_entry(drm_fb, &dev->mode_config.fb_kernel_list, filp_head) { + break; /* first entry is the only entry */ + } + + if (!drm_fb) { + DRM_ERROR("No framebuffer to destroy\n"); + return -EINVAL; + } + + info = drm_fb->fbdev; + if (!info) { + DRM_ERROR("No fb_info\n"); + return -EINVAL; + } + + unregister_framebuffer(info); + + block = find_block_by_handle(dev_priv->fb_heap, drm_fb->mm_handle); + if (!block) { + DRM_ERROR("can't find mem_block\n"); + return -EINVAL; + } + + /* we need to free this after memory is freed */ + file_priv = block->file_priv; + + /* free memory */ + nouveau_mem_free(dev, block); + + if (file_priv) { + kfree(file_priv); + file_priv = NULL; + } + + framebuffer_release(info); + + return 0; +} diff --git a/linux-core/nv50_fbcon.h b/linux-core/nv50_fbcon.h new file mode 100644 index 00000000..98e7101a --- /dev/null +++ b/linux-core/nv50_fbcon.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2008 Maarten Maathuis. + * All Rights Reserved. + * + * 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 (including the + * next paragraph) 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 OWNER(S) AND/OR ITS SUPPLIERS 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. + * + */ + +#ifndef __NV50_FBCON_H__ +#define __NV50_FBCON_H__ + +#include "nv50_kms_wrapper.h" + +struct nv50_fbcon_par { + struct drm_framebuffer *fb; + struct drm_device *dev; + bool use_preferred_mode; +}; + +int nv50_fbcon_init(struct drm_device *dev); +int nv50_fbcon_destroy(struct drm_device *dev); + +#endif /* __NV50_FBCON_H__ */ \ No newline at end of file diff --git a/linux-core/nv50_kms_wrapper.c b/linux-core/nv50_kms_wrapper.c index 7f1a095b..2a214f68 100644 --- a/linux-core/nv50_kms_wrapper.c +++ b/linux-core/nv50_kms_wrapper.c @@ -153,6 +153,7 @@ static void nv50_kms_mirror_routing(struct drm_device *dev) struct nv50_output *output = NULL; struct nv50_connector *connector = NULL; struct drm_connector *drm_connector = NULL; + struct drm_crtc *drm_crtc = NULL; /* Wipe all previous connections. */ list_for_each_entry(connector, &display->connectors, item) { @@ -179,6 +180,13 @@ static void nv50_kms_mirror_routing(struct drm_device *dev) } } } + + /* mirror crtc active state */ + list_for_each_entry(drm_crtc, &dev->mode_config.crtc_list, head) { + crtc = to_nv50_crtc(drm_crtc); + + crtc->active = drm_crtc->enabled; + } } /* @@ -428,8 +436,6 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) drm_crtc = drm_encoder->crtc; drm_encoder->crtc = NULL; - crtc = to_nv50_crtc(drm_crtc); - crtc->active = false; drm_crtc->enabled = false; } @@ -456,6 +462,7 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) } drm_encoder->crtc = set->crtc; + set->crtc->enabled = true; drm_connector->encoder = drm_encoder; } } @@ -468,7 +475,6 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) crtc = to_nv50_crtc(set->crtc); /* keeping the encoders and connectors attached, so they can be tracked */ - crtc->active = false; set->crtc->enabled = false; } diff --git a/shared-core/nouveau_state.c b/shared-core/nouveau_state.c index 9f8fc43d..3baae6ad 100644 --- a/shared-core/nouveau_state.c +++ b/shared-core/nouveau_state.c @@ -28,6 +28,7 @@ #include "nouveau_drv.h" #include "nouveau_drm.h" #include "nv50_kms_wrapper.h" +#include "nv50_fbcon.h" static int nouveau_init_card_mappings(struct drm_device *dev) { @@ -367,7 +368,8 @@ nouveau_card_init(struct drm_device *dev) if (drm_core_check_feature(dev, DRIVER_MODESET)) if (dev_priv->card_type >= NV_50) { nv50_kms_init(dev); - nv50_kms_connector_detect_all(dev); + //nv50_kms_connector_detect_all(dev); + nv50_fbcon_init(dev); } return 0; @@ -615,6 +617,7 @@ int nouveau_unload(struct drm_device *dev) { if (drm_core_check_feature(dev, DRIVER_MODESET)) { nv50_kms_destroy(dev); + nv50_fbcon_destroy(dev); nouveau_close(dev); } -- cgit v1.2.3 From 4f233ce61858b94e0c1bd36e331b36d1b59512e5 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Wed, 2 Jul 2008 22:46:44 +0200 Subject: tests: Updated modeprint --- tests/modeprint/modetest.c | 132 +++++++++++++++++++++++++-------------------- 1 file changed, 73 insertions(+), 59 deletions(-) diff --git a/tests/modeprint/modetest.c b/tests/modeprint/modetest.c index 36925a0b..3f00922f 100644 --- a/tests/modeprint/modetest.c +++ b/tests/modeprint/modetest.c @@ -55,12 +55,63 @@ int printMode(struct drm_mode_modeinfo *mode) return 0; } +int printProperty(int fd, drmModeResPtr res, drmModePropertyPtr props, uint64_t value) +{ + const unsigned char *name = NULL; + int j; + + printf("Property: %s\n", props->name); + printf("\tid : %i\n", props->prop_id); + printf("\tflags : %i\n", props->flags); + printf("\tcount_values : %d\n", props->count_values); + + + if (props->count_values) { + printf("\tvalues :"); + for (j = 0; j < props->count_values; j++) + printf(" %lld", props->values[j]); + printf("\n"); + } + + + printf("\tcount_enums : %d\n", props->count_enums); + + if (props->flags & DRM_MODE_PROP_BLOB) { + drmModePropertyBlobPtr blob; + + blob = drmModeGetPropertyBlob(fd, value); + if (blob) { + printf("blob is %d length, %08X\n", blob->length, *(uint32_t *)blob->data); + drmModeFreePropertyBlob(blob); + } else { + printf("error getting blob %lld\n", value); + } + + } else { + if (!strncmp(props->name, "DPMS", 4)) + ; + + for (j = 0; j < props->count_enums; j++) { + printf("\t\t%lld = %s\n", props->enums[j].value, props->enums[j].name); + if (props->enums[j].value == value) + name = props->enums[j].name; + } + + if (props->count_enums && name) { + printf("\tcon_value : %s\n", name); + } else { + printf("\tcon_value : %lld\n", value); + } + } + + return 0; +} + int printConnector(int fd, drmModeResPtr res, drmModeConnectorPtr connector, uint32_t id) { - int i = 0, j; + int i = 0; struct drm_mode_modeinfo *mode = NULL; drmModePropertyPtr props; - unsigned char *name = NULL; printf("Connector: %d-%d\n", connector->connector_type, connector->connector_type_id); printf("\tid : %i\n", id); @@ -69,73 +120,36 @@ int printConnector(int fd, drmModeResPtr res, drmModeConnectorPtr connector, uin printf("\tsize : %ix%i (mm)\n", connector->mmWidth, connector->mmHeight); printf("\tcount_modes : %i\n", connector->count_modes); printf("\tcount_props : %i\n", connector->count_props); - printf("\tcount_encoders : %i\n", connector->count_encoders); + if (connector->count_props) { + printf("\tprops :"); + for (i = 0; i < connector->count_props; i++) + printf(" %i", connector->props[i]); + printf("\n"); + } + printf("\tcount_encoders : %i\n", connector->count_encoders); if (connector->count_encoders) { - printf("\t\tencoders"); + printf("\tencoders :"); for (i = 0; i < connector->count_encoders; i++) printf(" %i", connector->encoders[i]); printf("\n"); } + if (modes) { + for (i = 0; i < connector->count_modes; i++) { + mode = &connector->modes[i]; + printMode(mode); + } + } + if (full_props) { for (i = 0; i < connector->count_props; i++) { props = drmModeGetProperty(fd, connector->props[i]); - name = NULL; if (props) { - printf("Property: %s\n", props->name); - printf("\tid: %i\n", props->prop_id); - printf("\tflags: %i\n", props->flags); - printf("\tvalues %d: ", props->count_values); - for (j = 0; j < props->count_values; j++) - printf("%lld ", props->values[j]); - - printf("\n\tenums %d: \n", props->count_enums); - - if (props->flags & DRM_MODE_PROP_BLOB) { - drmModePropertyBlobPtr blob; - - blob = drmModeGetPropertyBlob(fd, connector->prop_values[i]); - if (blob) { - printf("blob is %d length, %08X\n", blob->length, *(uint32_t *)blob->data); - drmModeFreePropertyBlob(blob); - } - - } else { - if (!strncmp(props->name, "DPMS", 4)) - ; - - for (j = 0; j < props->count_enums; j++) { - printf("\t\t%lld = %s\n", props->enums[j].value, props->enums[j].name); - if (connector->prop_values[i] == props->enums[j].value) - name = props->enums[j].name; - - } - - if (props->count_enums && name) { - printf("\tconnector property name %s %s\n", props->name, name); - } else { - printf("\tconnector property id %s %lli\n", props->name, connector->prop_values[i]); - } - } - + printProperty(fd, res, props, connector->prop_values[i]); drmModeFreeProperty(props); } } - } else { - if (connector->count_props) { - printf("\t\tprops"); - for (i = 0; i < connector->count_props; i++) - printf(" %i", connector->props[i]); - printf("\n"); - } - } - - if (modes) { - for (i = 0; i < connector->count_modes; i++) { - mode = &connector->modes[i]; - printMode(mode); - } } return 0; @@ -310,13 +324,13 @@ void args(int argc, char **argv) if (argc == 1) { fbs = 1; + edid = 1; + crtcs = 1; modes = 1; - full_modes = 0; encoders = 1; - connectors = 1; - crtcs = 1; + full_modes = 0; full_props = 0; - edid = 1; + connectors = 1; } } int main(int argc, char **argv) -- cgit v1.2.3 From 49e1fa1d503bb66949d825c41c1d97c83cf86361 Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Wed, 2 Jul 2008 23:12:33 +0200 Subject: tests: modeprint s/fb/fd/ --- tests/modeprint/modetest.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/modeprint/modetest.c b/tests/modeprint/modetest.c index 3f00922f..d8a94709 100644 --- a/tests/modeprint/modetest.c +++ b/tests/modeprint/modetest.c @@ -345,7 +345,7 @@ int main(int argc, char **argv) fd = drmOpen("i915", NULL); if (fd < 0) { - printf("Failed to open the card fb (%d)\n",fd); + printf("Failed to open the card fd (%d)\n",fd); return 1; } -- cgit v1.2.3 From 70ba0871916af586b355550184e0782b36e132c9 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 3 Jul 2008 08:00:39 +1000 Subject: drm: fix encoders get permissions --- linux-core/drm_drv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c index 82e5af57..deb8eb9c 100644 --- a/linux-core/drm_drv.c +++ b/linux-core/drm_drv.c @@ -142,7 +142,7 @@ static struct drm_ioctl_desc drm_ioctls[] = { DRM_IOCTL_DEF(DRM_IOCTL_WAIT_HOTPLUG, drm_wait_hotplug, 0), DRM_IOCTL_DEF(DRM_IOCTL_MODE_REPLACEFB, drm_mode_replacefb, DRM_MASTER|DRM_ROOT_ONLY|DRM_CONTROL_ALLOW), - DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETENCODER, drm_mode_getencoder, DRM_MASTER|DRM_ROOT_ONLY|DRM_CONTROL_ALLOW), + DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETENCODER, drm_mode_getencoder, DRM_MASTER|DRM_CONTROL_ALLOW), DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETGAMMA, drm_mode_gamma_get_ioctl, DRM_MASTER), DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETGAMMA, drm_mode_gamma_set_ioctl, DRM_MASTER), -- cgit v1.2.3 From aa2d3cfc168481b7637d935af990ce447012ebfe Mon Sep 17 00:00:00 2001 From: Jakob Bornecrantz Date: Thu, 3 Jul 2008 00:03:48 +0200 Subject: tests: Fix faulty error messages in modeprint --- tests/modeprint/modetest.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/modeprint/modetest.c b/tests/modeprint/modetest.c index d8a94709..f0f8abd4 100644 --- a/tests/modeprint/modetest.c +++ b/tests/modeprint/modetest.c @@ -220,7 +220,7 @@ int printRes(int fd, drmModeResPtr res) connector = drmModeGetConnector(fd, res->connectors[i]); if (!connector) - printf("Could not get connector %i\n", i); + printf("Could not get connector %i\n", res->connectors[i]); else { printConnector(fd, res, connector, res->connectors[i]); drmModeFreeConnector(connector); @@ -235,7 +235,7 @@ int printRes(int fd, drmModeResPtr res) encoder = drmModeGetEncoder(fd, res->encoders[i]); if (!encoder) - printf("Could not get encoder %i\n", i); + printf("Could not get encoder %i\n", res->encoders[i]); else { printEncoder(fd, res, encoder, res->encoders[i]); drmModeFreeEncoder(encoder); @@ -249,7 +249,7 @@ int printRes(int fd, drmModeResPtr res) crtc = drmModeGetCrtc(fd, res->crtcs[i]); if (!crtc) - printf("Could not get crtc %i\n", i); + printf("Could not get crtc %i\n", res->crtcs[i]); else { printCrtc(fd, res, crtc, res->crtcs[i]); drmModeFreeCrtc(crtc); -- cgit v1.2.3 From 59a9a756e238dd73f3051434545b2d3bf225da87 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 3 Jul 2008 08:05:51 +1000 Subject: modesetting: lookup blob using correct identifier. blob is a blob not a connector --- linux-core/drm_crtc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 23ae7d83..c20dacd8 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -1926,7 +1926,7 @@ int drm_mode_getblob_ioctl(struct drm_device *dev, void *blob_ptr; mutex_lock(&dev->mode_config.mutex); - obj = drm_mode_object_find(dev, out_resp->blob_id, DRM_MODE_OBJECT_CONNECTOR); + obj = drm_mode_object_find(dev, out_resp->blob_id, DRM_MODE_OBJECT_BLOB); if (!obj) { ret = -EINVAL; goto done; -- cgit v1.2.3 From 5de978905abd6d44ee2ecdc7393194a4950c595c Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Thu, 3 Jul 2008 00:25:06 +0200 Subject: [libdrm] count connectors and such has no place in a crtc object --- libdrm/xf86drmMode.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/libdrm/xf86drmMode.h b/libdrm/xf86drmMode.h index f1b7c86e..9f1e7a26 100644 --- a/libdrm/xf86drmMode.h +++ b/libdrm/xf86drmMode.h @@ -106,12 +106,6 @@ typedef struct _drmModeCrtc { int mode_valid; struct drm_mode_modeinfo mode; - int count_connectors; - uint32_t connectors; /**< Connectors that are connected */ - - int count_possibles; - uint32_t possibles; /**< Connectors that can be connected */ - int gamma_size; /**< Number of gamma stops */ } drmModeCrtc, *drmModeCrtcPtr; -- cgit v1.2.3 From 94cf07bff1bf9a42ba6360f8feaa441b763b337f Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Thu, 3 Jul 2008 00:30:00 +0200 Subject: Forgot to fix the modeprint test. --- tests/modeprint/modetest.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tests/modeprint/modetest.c b/tests/modeprint/modetest.c index f0f8abd4..d5cbbc56 100644 --- a/tests/modeprint/modetest.c +++ b/tests/modeprint/modetest.c @@ -176,10 +176,6 @@ int printCrtc(int fd, drmModeResPtr res, drmModeCrtcPtr crtc, uint32_t id) printf("\theight : %i\n", crtc->height); printf("\tmode : %p\n", &crtc->mode); printf("\tgamma size : %d\n", crtc->gamma_size); - printf("\tnum connectors : %i\n", crtc->count_connectors); - printf("\tconnectors : %i\n", crtc->connectors); - printf("\tnum possible : %i\n", crtc->count_possibles); - printf("\tpossibles : %i\n", crtc->possibles); return 0; } -- cgit v1.2.3 From 02b30739f7676082af4ce92448d910085d1dfc65 Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Thu, 3 Jul 2008 01:05:07 +0200 Subject: [modeseting-101] add connected field to sysfs --- linux-core/drm_sysfs.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/linux-core/drm_sysfs.c b/linux-core/drm_sysfs.c index 92371c22..02b08534 100644 --- a/linux-core/drm_sysfs.c +++ b/linux-core/drm_sysfs.c @@ -176,6 +176,19 @@ static ssize_t dpms_show(struct device *device, return snprintf(buf, PAGE_SIZE, "%s", drm_get_dpms_name((int)dpms_status)); } +static ssize_t connected_show(struct device *device, + struct device_attribute *attr, + char *buf) +{ + struct drm_connector *connector = container_of(device, struct drm_connector, kdev); + struct drm_device *dev = connector->dev; + + if (connector->encoder) + return snprintf(buf, PAGE_SIZE, "connected"); + else + return snprintf(buf, PAGE_SIZE, "disconnected"); +} + static ssize_t edid_show(struct kobject *kobj, struct bin_attribute *attr, char *buf, loff_t off, size_t count) { @@ -221,6 +234,7 @@ static ssize_t modes_show(struct device *device, static struct device_attribute connector_attrs[] = { __ATTR_RO(status), + __ATTR_RO(connected), __ATTR_RO(dpms), __ATTR_RO(modes), }; -- cgit v1.2.3 From 47c8f317410976c679aeaee69a372ec45485d442 Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Thu, 3 Jul 2008 07:18:18 +0200 Subject: NV50: replace active by enabled --- linux-core/nv50_crtc.h | 2 +- linux-core/nv50_display.c | 2 +- linux-core/nv50_kms_wrapper.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/linux-core/nv50_crtc.h b/linux-core/nv50_crtc.h index de9a33f2..8235c9d6 100644 --- a/linux-core/nv50_crtc.h +++ b/linux-core/nv50_crtc.h @@ -38,7 +38,7 @@ struct nv50_crtc { struct drm_device *dev; int index; - bool active; + bool enabled; bool blanked; struct nouveau_hw_mode *mode; diff --git a/linux-core/nv50_display.c b/linux-core/nv50_display.c index cd527c44..2d12fb4f 100644 --- a/linux-core/nv50_display.c +++ b/linux-core/nv50_display.c @@ -147,7 +147,7 @@ static int nv50_display_disable(struct nv50_display *display) /* Almost like ack'ing a vblank interrupt, maybe in the spirit of cleaning up? */ list_for_each_entry(crtc, &display->crtcs, item) { - if (crtc->active) { + if (crtc->enabled) { uint32_t mask; if (crtc->index == 1) diff --git a/linux-core/nv50_kms_wrapper.c b/linux-core/nv50_kms_wrapper.c index 2a214f68..46edfb34 100644 --- a/linux-core/nv50_kms_wrapper.c +++ b/linux-core/nv50_kms_wrapper.c @@ -185,7 +185,7 @@ static void nv50_kms_mirror_routing(struct drm_device *dev) list_for_each_entry(drm_crtc, &dev->mode_config.crtc_list, head) { crtc = to_nv50_crtc(drm_crtc); - crtc->active = drm_crtc->enabled; + crtc->enabled = drm_crtc->enabled; } } -- cgit v1.2.3 From d5ca5c9cd379438ac303598677f3789adc3687b1 Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Thu, 3 Jul 2008 08:07:35 +0200 Subject: [drm-sysfs] connected is ambigious in the context of a connector, replace with enabled --- linux-core/drm_sysfs.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/linux-core/drm_sysfs.c b/linux-core/drm_sysfs.c index 02b08534..36b92224 100644 --- a/linux-core/drm_sysfs.c +++ b/linux-core/drm_sysfs.c @@ -176,17 +176,16 @@ static ssize_t dpms_show(struct device *device, return snprintf(buf, PAGE_SIZE, "%s", drm_get_dpms_name((int)dpms_status)); } -static ssize_t connected_show(struct device *device, +static ssize_t enabled_show(struct device *device, struct device_attribute *attr, char *buf) { struct drm_connector *connector = container_of(device, struct drm_connector, kdev); - struct drm_device *dev = connector->dev; if (connector->encoder) - return snprintf(buf, PAGE_SIZE, "connected"); + return snprintf(buf, PAGE_SIZE, "enabled"); else - return snprintf(buf, PAGE_SIZE, "disconnected"); + return snprintf(buf, PAGE_SIZE, "disabled"); } static ssize_t edid_show(struct kobject *kobj, struct bin_attribute *attr, @@ -234,7 +233,7 @@ static ssize_t modes_show(struct device *device, static struct device_attribute connector_attrs[] = { __ATTR_RO(status), - __ATTR_RO(connected), + __ATTR_RO(enabled), __ATTR_RO(dpms), __ATTR_RO(modes), }; -- cgit v1.2.3 From 062d85062061199f2326982e27d54955a4ad76dc Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Thu, 3 Jul 2008 09:08:01 +0200 Subject: nv50: s/FALSE/false && s/TRUE/true --- linux-core/nv50_display.c | 6 +++--- linux-core/nv50_i2c.c | 30 +++++++++++++++--------------- linux-core/nv50_kms_wrapper.c | 16 ++++++++-------- shared-core/nouveau_mem.c | 2 +- 4 files changed, 27 insertions(+), 27 deletions(-) diff --git a/linux-core/nv50_display.c b/linux-core/nv50_display.c index 2d12fb4f..b68c4e28 100644 --- a/linux-core/nv50_display.c +++ b/linux-core/nv50_display.c @@ -79,7 +79,7 @@ static int nv50_display_pre_init(struct nv50_display *display) NV_WRITE(NV50_PDISPLAY_UNK_388, 0x150000); NV_WRITE(NV50_PDISPLAY_UNK_38C, 0); - display->preinit_done = TRUE; + display->preinit_done = true; return 0; } @@ -125,7 +125,7 @@ static int nv50_display_init(struct nv50_display *display) /* enable clock change interrupts. */ NV_WRITE(NV50_PDISPLAY_SUPERVISOR_INTR, NV_READ(NV50_PDISPLAY_SUPERVISOR_INTR) | 0x70); - display->init_done = TRUE; + display->init_done = true; return 0; } @@ -140,7 +140,7 @@ static int nv50_display_disable(struct nv50_display *display) NV50_DEBUG("\n"); list_for_each_entry(crtc, &display->crtcs, item) { - crtc->blank(crtc, TRUE); + crtc->blank(crtc, true); } display->update(display); diff --git a/linux-core/nv50_i2c.c b/linux-core/nv50_i2c.c index e90a4cee..30e317c5 100644 --- a/linux-core/nv50_i2c.c +++ b/linux-core/nv50_i2c.c @@ -106,19 +106,19 @@ static bool nv50_i2c_raise_clock(struct nv50_i2c_channel *chan, int data) for (i = 2200; i > 0; i -= 2) { nv50_i2c_get_bits(chan, &clock, &data); if (clock) - return TRUE; + return true; udelay(2); } printk("a timeout occured in nv50_i2c_raise_clock\n"); - return FALSE; + return false; } static bool nv50_i2c_start(struct nv50_i2c_channel *chan) { if (!nv50_i2c_raise_clock(chan, 1)) - return FALSE; + return false; nv50_i2c_set_bits(chan, 1, 0); udelay(5); @@ -126,7 +126,7 @@ static bool nv50_i2c_start(struct nv50_i2c_channel *chan) nv50_i2c_set_bits(chan, 0, 0); udelay(5); - return TRUE; + return true; } static void nv50_i2c_stop(struct nv50_i2c_channel *chan) @@ -181,7 +181,7 @@ static bool nv50_i2c_write_byte(struct nv50_i2c_channel *chan, uint8_t byte) for (i = 7; i >= 0; i--) if (!nv50_i2c_write_bit(chan, (byte >> i) & 1)) - return FALSE; + return false; nv50_i2c_set_bits(chan, 0, 1); udelay(5); @@ -198,7 +198,7 @@ static bool nv50_i2c_write_byte(struct nv50_i2c_channel *chan, uint8_t byte) if (i <= 0) { printk("a timeout occured in nv50_i2c_write_byte\n"); - rval = FALSE; + rval = false; } } @@ -222,14 +222,14 @@ static bool nv50_i2c_read_byte(struct nv50_i2c_channel *chan, uint8_t *byte, boo if (bit) *byte |= (1 << i); } else { - return FALSE; + return false; } } if (!nv50_i2c_write_bit(chan, last ? 1 : 0)) - return FALSE; + return false; - return TRUE; + return true; } /* only 7 bits addresses. */ @@ -241,13 +241,13 @@ static bool nv50_i2c_address(struct nv50_i2c_channel *chan, uint8_t address, boo real_addr |= 1; if (nv50_i2c_write_byte(chan, real_addr)) - return TRUE; + return true; /* failure, so issue stop */ nv50_i2c_stop(chan); } - return FALSE; + return false; } static bool nv50_i2c_read(struct nv50_i2c_channel *chan, uint8_t address, uint8_t *buffer, uint32_t length) @@ -257,9 +257,9 @@ static bool nv50_i2c_read(struct nv50_i2c_channel *chan, uint8_t address, uint8_ /* retries */ for (i = 0; i < 4; i++) { - rval = nv50_i2c_address(chan, address, FALSE); + rval = nv50_i2c_address(chan, address, false); if (!rval) - return FALSE; + return false; for (j = 0; j < length; j++) { last = false; @@ -292,9 +292,9 @@ static bool nv50_i2c_write(struct nv50_i2c_channel *chan, uint8_t address, uint8 /* retries */ for (i = 0; i < 4; i++) { - rval = nv50_i2c_address(chan, address, TRUE); + rval = nv50_i2c_address(chan, address, true); if (!rval) - return FALSE; + return false; for (j = 0; j < length; j++) { rval = nv50_i2c_write_byte(chan, buffer[j]); diff --git a/linux-core/nv50_kms_wrapper.c b/linux-core/nv50_kms_wrapper.c index 46edfb34..f1f5b69f 100644 --- a/linux-core/nv50_kms_wrapper.c +++ b/linux-core/nv50_kms_wrapper.c @@ -529,7 +529,7 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) if (blank) { crtc = to_nv50_crtc(set->crtc); - rval = crtc->blank(crtc, TRUE); + rval = crtc->blank(crtc, true); if (rval != 0) { DRM_ERROR("blanking failed\n"); goto out; @@ -540,7 +540,7 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) if (drm_encoder->crtc == set->crtc) { output = to_nv50_output(drm_encoder); - rval = output->execute_mode(output, TRUE); + rval = output->execute_mode(output, true); if (rval != 0) { DRM_ERROR("detaching output failed\n"); goto out; @@ -556,7 +556,7 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) if (switch_fb && !modeset && !blank) { crtc = to_nv50_crtc(set->crtc); - rval = crtc->blank(crtc, TRUE); + rval = crtc->blank(crtc, true); if (rval != 0) { DRM_ERROR("blanking failed\n"); goto out; @@ -569,7 +569,7 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) } /* this also sets the fb offset */ - rval = crtc->blank(crtc, FALSE); + rval = crtc->blank(crtc, false); if (rval != 0) { DRM_ERROR("unblanking failed\n"); goto out; @@ -588,7 +588,7 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) if (output->crtc) { crtc_mask |= 1 << output->crtc->index; } else { - rval = output->execute_mode(output, TRUE); + rval = output->execute_mode(output, true); if (rval != 0) { DRM_ERROR("detaching output failed\n"); goto out; @@ -599,7 +599,7 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) /* blank any unused crtcs */ list_for_each_entry(crtc, &display->crtcs, item) { if (!(crtc_mask & (1 << crtc->index))) - crtc->blank(crtc, TRUE); + crtc->blank(crtc, true); } crtc = to_nv50_crtc(set->crtc); @@ -642,7 +642,7 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) if (output->crtc != crtc) continue; - rval = output->execute_mode(output, FALSE); + rval = output->execute_mode(output, false); if (rval != 0) { DRM_ERROR("output execute mode failed\n"); goto out; @@ -933,7 +933,7 @@ static void nv50_kms_connector_fill_modes(struct drm_connector *drm_connector, u } } - drm_mode_prune_invalid(drm_connector->dev, &drm_connector->modes, TRUE); + drm_mode_prune_invalid(drm_connector->dev, &drm_connector->modes, true); if (list_empty(&drm_connector->modes)) { struct drm_display_mode *stdmode; diff --git a/shared-core/nouveau_mem.c b/shared-core/nouveau_mem.c index 425cebe2..861d699f 100644 --- a/shared-core/nouveau_mem.c +++ b/shared-core/nouveau_mem.c @@ -743,7 +743,7 @@ void nouveau_mem_free(struct drm_device* dev, struct mem_block* block) crtc->fb->block = NULL; if (!crtc->blanked) - crtc->blank(crtc, TRUE); + crtc->blank(crtc, true); } if (crtc->cursor->block == block) { -- cgit v1.2.3 From 11b7a81c8a776aa7761ee03fe55d741a44ba5df7 Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Thu, 3 Jul 2008 17:25:37 +0200 Subject: libdrm: fix typo in comment --- libdrm/xf86drmMode.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libdrm/xf86drmMode.h b/libdrm/xf86drmMode.h index 9f1e7a26..7afc71d7 100644 --- a/libdrm/xf86drmMode.h +++ b/libdrm/xf86drmMode.h @@ -98,7 +98,7 @@ typedef struct _drmModeProperty { typedef struct _drmModeCrtc { unsigned int crtc_id; - unsigned int buffer_id; /**< FB id to connect to 0 = disconnect*/ + unsigned int buffer_id; /**< FB id to connect to 0 = disconnect */ uint32_t generation; uint32_t x, y; /**< Position on the frameuffer */ @@ -137,7 +137,7 @@ typedef enum { typedef struct _drmModeConnector { uint32_t generation; unsigned int connector_id; - unsigned int encoder; /**< Crtc currently connected to */ + unsigned int encoder; /**< Encoder currently connected to */ unsigned int connector_type; unsigned int connector_type_id; drmModeConnection connection; -- cgit v1.2.3 From 142a309604b65c26ca95594943ee91dde8688697 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 4 Jul 2008 09:34:24 +1000 Subject: modesetting: rip out all of the generation code. not needed, hotplug will work just as well hopefully. --- libdrm/xf86drmMode.h | 11 ----------- linux-core/drm_crtc.c | 5 ----- linux-core/drm_crtc.h | 3 --- shared-core/drm.h | 7 ------- 4 files changed, 26 deletions(-) diff --git a/libdrm/xf86drmMode.h b/libdrm/xf86drmMode.h index 7afc71d7..3e2f5c0e 100644 --- a/libdrm/xf86drmMode.h +++ b/libdrm/xf86drmMode.h @@ -50,16 +50,8 @@ * buffer object interface. This object needs to be pinned. */ -/* - * generation - these are to be read by userspace, and if it notices - * while calling a get output or get crtc that the generation has changed - * it should re-call the mode resource functions resync its view of the - * outputs with current view. - */ - typedef struct _drmModeRes { - uint32_t generation; int count_fbs; uint32_t *fbs; @@ -99,7 +91,6 @@ typedef struct _drmModeProperty { typedef struct _drmModeCrtc { unsigned int crtc_id; unsigned int buffer_id; /**< FB id to connect to 0 = disconnect */ - uint32_t generation; uint32_t x, y; /**< Position on the frameuffer */ uint32_t width, height; @@ -111,7 +102,6 @@ typedef struct _drmModeCrtc { } drmModeCrtc, *drmModeCrtcPtr; typedef struct _drmModeEncoder { - uint32_t generation; unsigned int encoder_id; unsigned int encoder_type; uint32_t crtc; @@ -135,7 +125,6 @@ typedef enum { } drmModeSubPixel; typedef struct _drmModeConnector { - uint32_t generation; unsigned int connector_id; unsigned int encoder; /**< Encoder currently connected to */ unsigned int connector_type; diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index c20dacd8..ca5e75a4 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -574,7 +574,6 @@ void drm_mode_config_init(struct drm_device *dev) drm_mode_create_standard_connector_properties(dev); /* Just to be sure */ - dev->mode_config.current_generation = 0; dev->mode_config.num_fb = 0; dev->mode_config.num_connector = 0; dev->mode_config.num_crtc = 0; @@ -805,7 +804,6 @@ int drm_mode_getresources(struct drm_device *dev, card_res->min_height = dev->mode_config.min_height; card_res->max_width = dev->mode_config.max_width; card_res->min_width = dev->mode_config.min_width; - card_res->generation = dev->mode_config.current_generation; /* handle this in 4 parts */ /* FBs */ @@ -946,7 +944,6 @@ int drm_mode_getcrtc(struct drm_device *dev, crtc_resp->x = crtc->x; crtc_resp->y = crtc->y; crtc_resp->gamma_size = crtc->gamma_size; - crtc_resp->generation = dev->mode_config.current_generation; if (crtc->fb) crtc_resp->fb_id = crtc->fb->base.id; else @@ -1036,7 +1033,6 @@ int drm_mode_getconnector(struct drm_device *dev, list_for_each_entry(mode, &connector->modes, head) mode_count++; - out_resp->generation = dev->mode_config.current_generation; out_resp->connector_type = connector->connector_type; out_resp->connector_type_id = connector->connector_type_id; out_resp->mm_width = connector->display_info.width_mm; @@ -1125,7 +1121,6 @@ int drm_mode_getencoder(struct drm_device *dev, enc_resp->crtc = encoder->crtc->base.id; else enc_resp->crtc = 0; - enc_resp->generation = dev->mode_config.current_generation; enc_resp->encoder_type = encoder->encoder_type; enc_resp->encoder_id = encoder->base.id; enc_resp->crtcs = encoder->possible_crtcs; diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index d6fa4cca..65ff3f29 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -561,9 +561,6 @@ struct drm_mode_config { /* in-kernel framebuffers - hung of filp_head in drm_framebuffer */ struct list_head fb_kernel_list; - /* currently in use generation id */ - int current_generation; - int min_width, min_height; int max_width, max_height; struct drm_mode_config_funcs *funcs; diff --git a/shared-core/drm.h b/shared-core/drm.h index 40653b4b..132c7746 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -1033,7 +1033,6 @@ struct drm_mode_card_res { int count_encoders; int min_width, max_width; int min_height, max_height; - uint32_t generation; }; struct drm_mode_crtc { @@ -1044,8 +1043,6 @@ struct drm_mode_crtc { int x, y; /**< Position on the frameuffer */ - uint32_t generation; - int count_connectors; unsigned int connectors; /**< Connectors that are connected */ @@ -1058,8 +1055,6 @@ struct drm_mode_crtc { struct drm_mode_get_encoder { - uint32_t generation; - uint32_t encoder_type; uint32_t encoder_id; @@ -1090,8 +1085,6 @@ struct drm_mode_get_connector { unsigned int connector_type; unsigned int connector_type_id; - uint32_t generation; - unsigned int connection; unsigned int mm_width, mm_height; /**< HxW in millimeters */ unsigned int subpixel; -- cgit v1.2.3 From b29578103f57a8d684b4a3a79f220e6cc626605e Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Fri, 4 Jul 2008 17:17:11 +0200 Subject: [modesetting-101] Add subconnector and select_subconnector properties. - These facilitate DVI-I and tv-out that can drive multiple types of signals. --- linux-core/drm_crtc.c | 96 +++++++++++++++++++++++++++++++++++++++- linux-core/drm_crtc.h | 19 +++++++- linux-core/drm_sysfs.c | 98 +++++++++++++++++++++++++++++++++++++++++ linux-core/intel_tv.c | 2 +- linux-core/nv50_connector.h | 1 - linux-core/nv50_kms_wrapper.c | 100 +++++++++++++++++++++++++++++++++++++----- linux-core/nv50_kms_wrapper.h | 1 + 7 files changed, 300 insertions(+), 17 deletions(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index ca5e75a4..1a381abe 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -60,6 +60,48 @@ char *drm_get_dpms_name(int val) return "unknown"; } +static struct drm_prop_enum_list drm_select_subconnector_enum_list[] = +{ + { DRM_MODE_SUBCONNECTOR_Automatic, "Automatic" }, /* DVI-I and TV-out */ + { DRM_MODE_SUBCONNECTOR_DVID, "DVI-D" }, /* DVI-I */ + { DRM_MODE_SUBCONNECTOR_DVIA, "DVI-A" }, /* DVI-I */ + { DRM_MODE_SUBCONNECTOR_Composite, "Composite" }, /* TV-out */ + { DRM_MODE_SUBCONNECTOR_SVIDEO, "SVIDEO" }, /* TV-out */ + { DRM_MODE_SUBCONNECTOR_Component, "Component" }, /* TV-out */ +}; + +char *drm_get_select_subconnector_name(int val) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(drm_select_subconnector_enum_list); i++) + if (drm_select_subconnector_enum_list[i].type == val) + return drm_select_subconnector_enum_list[i].name; + + return "unknown"; +} + +static struct drm_prop_enum_list drm_subconnector_enum_list[] = +{ + { DRM_MODE_SUBCONNECTOR_Unknown, "Unknown" }, /* DVI-I and TV-out */ + { DRM_MODE_SUBCONNECTOR_DVID, "DVI-D" }, /* DVI-I */ + { DRM_MODE_SUBCONNECTOR_DVIA, "DVI-A" }, /* DVI-I */ + { DRM_MODE_SUBCONNECTOR_Composite, "Composite" }, /* TV-out */ + { DRM_MODE_SUBCONNECTOR_SVIDEO, "SVIDEO" }, /* TV-out */ + { DRM_MODE_SUBCONNECTOR_Component, "Component" }, /* TV-out */ +}; + +char *drm_get_subconnector_name(int val) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(drm_subconnector_enum_list); i++) + if (drm_subconnector_enum_list[i].type == val) + return drm_subconnector_enum_list[i].name; + + return "unknown"; +} + static struct drm_prop_enum_list drm_connector_enum_list[] = { { DRM_MODE_CONNECTOR_Unknown, "Unknown" }, { DRM_MODE_CONNECTOR_VGA, "VGA" }, @@ -497,6 +539,38 @@ static int drm_mode_create_standard_connector_properties(struct drm_device *dev) return 0; } +/** + * drm_mode_create_dvi_i_properties - create DVI-I specific connector properties + * @dev: DRM device + * + * Called by a driver the first time a DVI-I connector is made. + */ +int drm_mode_create_dvi_i_properties(struct drm_device *dev) +{ + int i; + + if (dev->mode_config.dvi_i_select_subconnector_property) + return 0; + + dev->mode_config.dvi_i_select_subconnector_property = drm_property_create(dev, DRM_MODE_PROP_ENUM, + "select subconnector", 3); + /* add enum element 0-2 */ + for (i = 0; i < 3; i++) + drm_property_add_enum(dev->mode_config.dvi_i_select_subconnector_property, i, drm_select_subconnector_enum_list[i].type, + drm_select_subconnector_enum_list[i].name); + + /* This is a property which indicates the most likely thing to be connected. */ + dev->mode_config.dvi_i_subconnector_property = drm_property_create(dev, DRM_MODE_PROP_ENUM | DRM_MODE_PROP_IMMUTABLE, + "subconnector", 3); + /* add enum element 0-2 */ + for (i = 0; i < 3; i++) + drm_property_add_enum(dev->mode_config.dvi_i_subconnector_property, i, drm_subconnector_enum_list[i].type, + drm_subconnector_enum_list[i].name); + + return 0; +} +EXPORT_SYMBOL(drm_mode_create_dvi_i_properties); + /** * drm_create_tv_properties - create TV specific connector properties * @dev: DRM device @@ -508,11 +582,29 @@ static int drm_mode_create_standard_connector_properties(struct drm_device *dev) * responsible for allocating a list of format names and passing them to * this routine. */ -bool drm_create_tv_properties(struct drm_device *dev, int num_modes, +int drm_mode_create_tv_properties(struct drm_device *dev, int num_modes, char *modes[]) { int i; + if (dev->mode_config.tv_select_subconnector_property) /* already done */ + return 0; + + dev->mode_config.tv_select_subconnector_property = drm_property_create(dev, DRM_MODE_PROP_ENUM, + "select subconnector", 4); + /* add enum element 3-5 */ + for (i = 1; i < 4; i++) + drm_property_add_enum(dev->mode_config.tv_select_subconnector_property, i, drm_select_subconnector_enum_list[i + 2].type, + drm_select_subconnector_enum_list[i + 2].name); + + /* This is a property which indicates the most likely thing to be connected. */ + dev->mode_config.tv_subconnector_property = drm_property_create(dev, DRM_MODE_PROP_ENUM | DRM_MODE_PROP_IMMUTABLE, + "subconnector", 4); + /* add enum element 3-5 */ + for (i = 1; i < 4; i++) + drm_property_add_enum(dev->mode_config.tv_subconnector_property, i, drm_subconnector_enum_list[i + 2].type, + drm_subconnector_enum_list[i + 2].name); + dev->mode_config.tv_left_margin_property = drm_property_create(dev, DRM_MODE_PROP_RANGE | DRM_MODE_PROP_IMMUTABLE, @@ -547,7 +639,7 @@ bool drm_create_tv_properties(struct drm_device *dev, int num_modes, return 0; } -EXPORT_SYMBOL(drm_create_tv_properties); +EXPORT_SYMBOL(drm_mode_create_tv_properties); /** * drm_mode_config_init - initialize DRM mode_configuration structure diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index 65ff3f29..caceb650 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -170,6 +170,14 @@ struct drm_display_mode { #define DPMSModeSuspend 2 #define DPMSModeOff 3 +#define DRM_MODE_SUBCONNECTOR_Automatic 0 +#define DRM_MODE_SUBCONNECTOR_Unknown 0 +#define DRM_MODE_SUBCONNECTOR_DVID 3 +#define DRM_MODE_SUBCONNECTOR_DVIA 4 +#define DRM_MODE_SUBCONNECTOR_Composite 5 +#define DRM_MODE_SUBCONNECTOR_SVIDEO 6 +#define DRM_MODE_SUBCONNECTOR_Component 8 + #define DRM_MODE_CONNECTOR_Unknown 0 #define DRM_MODE_CONNECTOR_VGA 1 #define DRM_MODE_CONNECTOR_DVII 2 @@ -571,7 +579,13 @@ struct drm_mode_config { struct drm_property *edid_property; struct drm_property *dpms_property; + /* optional properties */ + struct drm_property *dvi_i_subconnector_property; + struct drm_property *dvi_i_select_subconnector_property; + /* TV properties */ + struct drm_property *tv_subconnector_property; + struct drm_property *tv_select_subconnector_property; struct drm_property *tv_mode_property; struct drm_property *tv_left_margin_property; struct drm_property *tv_right_margin_property; @@ -612,6 +626,8 @@ extern void drm_encoder_cleanup(struct drm_encoder *encoder); extern char *drm_get_connector_name(struct drm_connector *connector); extern char *drm_get_dpms_name(int val); +extern char *drm_get_select_subconnector_name(int val); +extern char *drm_get_subconnector_name(int val); extern void drm_fb_release(struct file *filp); extern int drm_mode_group_init_legacy_group(struct drm_device *dev, struct drm_mode_group *group); extern struct edid *drm_get_edid(struct drm_connector *connector, @@ -674,7 +690,8 @@ extern struct drm_property *drm_property_create(struct drm_device *dev, int flag extern void drm_property_destroy(struct drm_device *dev, struct drm_property *property); extern int drm_property_add_enum(struct drm_property *property, int index, uint64_t value, const char *name); -extern bool drm_create_tv_properties(struct drm_device *dev, int num_formats, +extern int drm_mode_create_dvi_i_properties(struct drm_device *dev); +extern int drm_mode_create_tv_properties(struct drm_device *dev, int num_formats, char *formats[]); extern char *drm_get_encoder_name(struct drm_encoder *encoder); diff --git a/linux-core/drm_sysfs.c b/linux-core/drm_sysfs.c index 36b92224..5c384a60 100644 --- a/linux-core/drm_sysfs.c +++ b/linux-core/drm_sysfs.c @@ -231,6 +231,78 @@ static ssize_t modes_show(struct device *device, return written; } +static ssize_t subconnector_show(struct device *device, + struct device_attribute *attr, + char *buf) +{ + struct drm_connector *connector = container_of(device, struct drm_connector, kdev); + struct drm_device *dev = connector->dev; + struct drm_property *prop = NULL; + uint64_t subconnector; + int ret; + + switch (connector->connector_type) { + case DRM_MODE_CONNECTOR_DVII: + prop = dev->mode_config.dvi_i_subconnector_property; + break; + case DRM_MODE_CONNECTOR_Composite: + case DRM_MODE_CONNECTOR_SVIDEO: + case DRM_MODE_CONNECTOR_Component: + prop = dev->mode_config.tv_subconnector_property; + break; + default: + DRM_ERROR("Wrong connector type for this property\n"); + return 0; + } + + if (!prop) { + DRM_ERROR("Unable to find subconnector property\n"); + return 0; + } + + ret = drm_connector_property_get_value(connector, prop, &subconnector); + if (ret) + return 0; + + return snprintf(buf, PAGE_SIZE, "%s", drm_get_subconnector_name((int)subconnector)); +} + +static ssize_t select_subconnector_show(struct device *device, + struct device_attribute *attr, + char *buf) +{ + struct drm_connector *connector = container_of(device, struct drm_connector, kdev); + struct drm_device *dev = connector->dev; + struct drm_property *prop = NULL; + uint64_t subconnector; + int ret; + + switch (connector->connector_type) { + case DRM_MODE_CONNECTOR_DVII: + prop = dev->mode_config.dvi_i_select_subconnector_property; + break; + case DRM_MODE_CONNECTOR_Composite: + case DRM_MODE_CONNECTOR_SVIDEO: + case DRM_MODE_CONNECTOR_Component: + prop = dev->mode_config.tv_select_subconnector_property; + break; + default: + DRM_ERROR("Wrong connector type for this property\n"); + return 0; + } + + if (!prop) { + DRM_ERROR("Unable to find select subconnector property\n"); + return 0; + } + + ret = drm_connector_property_get_value(connector, prop, &subconnector); + if (ret) + return 0; + + return snprintf(buf, PAGE_SIZE, "%s", drm_get_select_subconnector_name((int)subconnector)); +} + static struct device_attribute connector_attrs[] = { __ATTR_RO(status), __ATTR_RO(enabled), @@ -238,6 +310,12 @@ static struct device_attribute connector_attrs[] = { __ATTR_RO(modes), }; +/* These attributes are for both DVI-I connectors and all types of tv-out. */ +static struct device_attribute connector_attrs_opt1[] = { + __ATTR_RO(subconnector), + __ATTR_RO(select_subconnector), +}; + static struct bin_attribute edid_attr = { .attr.name = "edid", .size = 128, @@ -282,12 +360,32 @@ int drm_sysfs_connector_add(struct drm_connector *connector) goto out; } + /* Standard attributes */ + for (i = 0; i < ARRAY_SIZE(connector_attrs); i++) { ret = device_create_file(&connector->kdev, &connector_attrs[i]); if (ret) goto err_out_files; } + /* Optional attributes */ + /* On the long run it maybe a good idea to make one set of optionals per connector type. */ + + switch (connector->connector_type) { + case DRM_MODE_CONNECTOR_DVII: + case DRM_MODE_CONNECTOR_Composite: + case DRM_MODE_CONNECTOR_SVIDEO: + case DRM_MODE_CONNECTOR_Component: + for (i = 0; i < ARRAY_SIZE(connector_attrs_opt1); i++) { + ret = device_create_file(&connector->kdev, &connector_attrs_opt1[i]); + if (ret) + goto err_out_files; + } + break; + default: + break; + } + ret = sysfs_create_bin_file(&connector->kdev.kobj, &edid_attr); if (ret) goto err_out_files; diff --git a/linux-core/intel_tv.c b/linux-core/intel_tv.c index 39f33d6c..f564fa91 100644 --- a/linux-core/intel_tv.c +++ b/linux-core/intel_tv.c @@ -1713,7 +1713,7 @@ intel_tv_init(struct drm_device *dev) goto out; for (i = 0; i < NUM_TV_MODES; i++) tv_format_names[i] = tv_modes[i].name; - drm_create_tv_properties(dev, NUM_TV_MODES, tv_format_names); + drm_mode_create_tv_properties(dev, NUM_TV_MODES, tv_format_names); drm_connector_attach_property(connector, dev->mode_config.tv_mode_property, initial_mode); diff --git a/linux-core/nv50_connector.h b/linux-core/nv50_connector.h index 484227a0..ebd6eac6 100644 --- a/linux-core/nv50_connector.h +++ b/linux-core/nv50_connector.h @@ -48,7 +48,6 @@ struct nv50_connector { struct nv50_output *output; int scaling_mode; - bool digital; /* last connected output, this has to be set from the outside*/ bool (*detect) (struct nv50_connector *connector); int (*destroy) (struct nv50_connector *connector); diff --git a/linux-core/nv50_kms_wrapper.c b/linux-core/nv50_kms_wrapper.c index f1f5b69f..ee18b36a 100644 --- a/linux-core/nv50_kms_wrapper.c +++ b/linux-core/nv50_kms_wrapper.c @@ -387,7 +387,7 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) } connector = to_nv50_connector(drm_connector); - output = connector->to_output(connector, connector->digital); + output = connector->to_output(connector, nv50_kms_connector_is_digital(drm_connector)); if (!output) { DRM_ERROR("No output\n"); goto out; @@ -447,7 +447,7 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) goto out; } - output = connector->to_output(connector, connector->digital); + output = connector->to_output(connector, nv50_kms_connector_is_digital(drm_connector)); if (!output) { DRM_ERROR("No output\n"); goto out; @@ -806,6 +806,63 @@ static int nv50_kms_encoders_init(struct drm_device *dev) * Connector functions */ +bool nv50_kms_connector_is_digital(struct drm_connector *drm_connector) +{ + struct drm_device *dev = drm_connector->dev; + + switch (drm_connector->connector_type) { + case DRM_MODE_CONNECTOR_VGA: + case DRM_MODE_CONNECTOR_SVIDEO: + return false; + case DRM_MODE_CONNECTOR_DVID: + case DRM_MODE_CONNECTOR_LVDS: + return true; + default: + break; + } + + if (drm_connector->connector_type == DRM_MODE_CONNECTOR_DVII) { + int rval; + uint64_t prop_val; + + rval = drm_connector_property_get_value(drm_connector, dev->mode_config.dvi_i_select_subconnector_property, &prop_val); + if (!rval) { + DRM_ERROR("Unable to find select subconnector property, defaulting to DVI-D\n"); + return true; + } + + /* Is a subconnector explicitly selected? */ + switch (prop_val) { + case DRM_MODE_SUBCONNECTOR_DVID: + return true; + case DRM_MODE_SUBCONNECTOR_DVIA: + return false; + default: + break; + } + + rval = drm_connector_property_get_value(drm_connector, dev->mode_config.dvi_i_subconnector_property, &prop_val); + if (!rval) { + DRM_ERROR("Unable to find subconnector property, defaulting to DVI-D\n"); + return true; + } + + /* Do we know what subconnector we currently have connected? */ + switch (prop_val) { + case DRM_MODE_SUBCONNECTOR_DVID: + return true; + case DRM_MODE_SUBCONNECTOR_DVIA: + return false; + default: + DRM_ERROR("Unknown subconnector value, defaulting to DVI-D\n"); + return true; + } + } + + DRM_ERROR("Unknown connector type, defaulting to analog\n"); + return false; +} + void nv50_kms_connector_detect_all(struct drm_device *dev) { struct drm_connector *drm_connector = NULL; @@ -867,7 +924,8 @@ static struct drm_display_mode std_mode[] = { static void nv50_kms_connector_fill_modes(struct drm_connector *drm_connector, uint32_t maxX, uint32_t maxY) { struct nv50_connector *connector = to_nv50_connector(drm_connector); - int ret = 0; + struct drm_device *dev = drm_connector->dev; + int rval = 0; bool connected; struct drm_display_mode *mode, *t; struct edid *edid = NULL; @@ -896,21 +954,32 @@ static void nv50_kms_connector_fill_modes(struct drm_connector *drm_connector, u if (edid) { drm_mode_connector_update_edid_property(drm_connector, edid); - ret = drm_add_edid_modes(drm_connector, edid); - connector->digital = edid->digital; /* cache */ + rval = drm_add_edid_modes(drm_connector, edid); + + /* 2 encoders per connector */ + /* eventually do this based on load detect and hot plug detect */ + if (drm_connector->connector_type == DRM_MODE_CONNECTOR_DVII) { + uint64_t subtype = 0; + if (edid->digital) + subtype = DRM_MODE_SUBCONNECTOR_DVID; + else + subtype = DRM_MODE_SUBCONNECTOR_DVIA; + drm_connector_property_set_value(drm_connector, dev->mode_config.dvi_i_subconnector_property, subtype); + } + kfree(edid); } - if (ret) /* number of modes > 1 */ + if (rval) /* number of modes > 1 */ drm_mode_connector_list_update(drm_connector); if (maxX && maxY) - drm_mode_validate_size(drm_connector->dev, &drm_connector->modes, maxX, maxY, 0); + drm_mode_validate_size(dev, &drm_connector->modes, maxX, maxY, 0); list_for_each_entry_safe(mode, t, &drm_connector->modes, head) { if (mode->status == MODE_OK) { struct nouveau_hw_mode *hw_mode = nv50_kms_to_hw_mode(mode); - struct nv50_output *output = connector->to_output(connector, connector->digital); + struct nv50_output *output = connector->to_output(connector, nv50_kms_connector_is_digital(drm_connector)); mode->status = output->validate_mode(output, hw_mode); /* find native mode, TODO: also check if we actually found one */ @@ -926,14 +995,14 @@ static void nv50_kms_connector_fill_modes(struct drm_connector *drm_connector, u list_for_each_entry_safe(mode, t, &drm_connector->modes, head) { if (mode->status == MODE_OK) { struct nouveau_hw_mode *hw_mode = nv50_kms_to_hw_mode(mode); - struct nv50_output *output = connector->to_output(connector, connector->digital); + struct nv50_output *output = connector->to_output(connector, nv50_kms_connector_is_digital(drm_connector)); mode->status = output->validate_mode(output, hw_mode); kfree(hw_mode); } } - drm_mode_prune_invalid(drm_connector->dev, &drm_connector->modes, true); + drm_mode_prune_invalid(dev, &drm_connector->modes, true); if (list_empty(&drm_connector->modes)) { struct drm_display_mode *stdmode; @@ -947,14 +1016,14 @@ static void nv50_kms_connector_fill_modes(struct drm_connector *drm_connector, u * here and bailed in the past, now we add a standard * 640x480@60Hz mode and carry on. */ - stdmode = drm_mode_duplicate(drm_connector->dev, &std_mode[0]); + stdmode = drm_mode_duplicate(dev, &std_mode[0]); drm_mode_probed_add(drm_connector, stdmode); drm_mode_list_concat(&drm_connector->probed_modes, &drm_connector->modes); /* also add it as native mode */ hw_mode = nv50_kms_to_hw_mode(mode); - output = connector->to_output(connector, connector->digital); + output = connector->to_output(connector, nv50_kms_connector_is_digital(drm_connector)); if (hw_mode) *output->native_mode = *hw_mode; @@ -1045,6 +1114,13 @@ static int nv50_kms_connectors_init(struct drm_device *dev) drm_connector_init(dev, drm_connector, &nv50_kms_connector_funcs, type); + /* Init DVI-I specific properties */ + if (type == DRM_MODE_CONNECTOR_DVII) { + drm_mode_create_dvi_i_properties(dev); + drm_connector_attach_property(drm_connector, dev->mode_config.dvi_i_subconnector_property, 0); + drm_connector_attach_property(drm_connector, dev->mode_config.dvi_i_select_subconnector_property, 0); + } + /* attach encoders, possibilities are analog + digital */ for (i = 0; i < 2; i++) { struct drm_encoder *drm_encoder = NULL; diff --git a/linux-core/nv50_kms_wrapper.h b/linux-core/nv50_kms_wrapper.h index f224f1bb..5ac66522 100644 --- a/linux-core/nv50_kms_wrapper.h +++ b/linux-core/nv50_kms_wrapper.h @@ -87,6 +87,7 @@ struct nv50_kms_priv { struct nv50_kms_priv *nv50_get_kms_priv(struct drm_device *dev); void nv50_kms_connector_detect_all(struct drm_device *dev); +bool nv50_kms_connector_is_digital(struct drm_connector *drm_connector); int nv50_kms_init(struct drm_device *dev); int nv50_kms_destroy(struct drm_device *dev); -- cgit v1.2.3 From c9915d695dad8e4f75b4f551f9f78ff3d64dc666 Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Fri, 4 Jul 2008 17:28:04 +0200 Subject: modesetting-101: Move some defines used for enumeration into the public header. - Otherwise userspace has no idea of the meaning. --- linux-core/drm_crtc.h | 47 ++---------------------------------------- shared-core/drm.h | 56 ++++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 53 insertions(+), 50 deletions(-) diff --git a/linux-core/drm_crtc.h b/linux-core/drm_crtc.h index caceb650..d4bb8794 100644 --- a/linux-core/drm_crtc.h +++ b/linux-core/drm_crtc.h @@ -90,6 +90,8 @@ enum drm_mode_status { .vsync_start = (vss), .vsync_end = (vse), .vtotal = (vt), \ .vscan = (vs), .flags = (f), .vrefresh = 0 +#define CRTC_INTERLACE_HALVE_V 0x1 /* halve V values for interlacing */ + struct drm_display_mode { /* Header */ struct list_head head; @@ -147,51 +149,6 @@ struct drm_display_mode { float hsync; }; -/* Video mode flags */ -#define V_PHSYNC (1<<0) -#define V_NHSYNC (1<<1) -#define V_PVSYNC (1<<2) -#define V_NVSYNC (1<<3) -#define V_INTERLACE (1<<4) -#define V_DBLSCAN (1<<5) -#define V_CSYNC (1<<6) -#define V_PCSYNC (1<<7) -#define V_NCSYNC (1<<8) -#define V_HSKEW (1<<9) /* hskew provided */ -#define V_BCAST (1<<10) -#define V_PIXMUX (1<<11) -#define V_DBLCLK (1<<12) -#define V_CLKDIV2 (1<<13) - -#define CRTC_INTERLACE_HALVE_V 0x1 /* halve V values for interlacing */ - -#define DPMSModeOn 0 -#define DPMSModeStandby 1 -#define DPMSModeSuspend 2 -#define DPMSModeOff 3 - -#define DRM_MODE_SUBCONNECTOR_Automatic 0 -#define DRM_MODE_SUBCONNECTOR_Unknown 0 -#define DRM_MODE_SUBCONNECTOR_DVID 3 -#define DRM_MODE_SUBCONNECTOR_DVIA 4 -#define DRM_MODE_SUBCONNECTOR_Composite 5 -#define DRM_MODE_SUBCONNECTOR_SVIDEO 6 -#define DRM_MODE_SUBCONNECTOR_Component 8 - -#define DRM_MODE_CONNECTOR_Unknown 0 -#define DRM_MODE_CONNECTOR_VGA 1 -#define DRM_MODE_CONNECTOR_DVII 2 -#define DRM_MODE_CONNECTOR_DVID 3 -#define DRM_MODE_CONNECTOR_DVIA 4 -#define DRM_MODE_CONNECTOR_Composite 5 -#define DRM_MODE_CONNECTOR_SVIDEO 6 -#define DRM_MODE_CONNECTOR_LVDS 7 -#define DRM_MODE_CONNECTOR_Component 8 -#define DRM_MODE_CONNECTOR_9PinDIN 9 -#define DRM_MODE_CONNECTOR_DisplayPort 10 -#define DRM_MODE_CONNECTOR_HDMIA 11 -#define DRM_MODE_CONNECTOR_HDMIB 12 - enum drm_connector_status { connector_status_connected = 1, connector_status_disconnected = 2, diff --git a/shared-core/drm.h b/shared-core/drm.h index 132c7746..c9b40e78 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -1010,6 +1010,28 @@ struct drm_mm_info_arg { #define DRM_MODE_TYPE_USERDEF (1<<5) #define DRM_MODE_TYPE_DRIVER (1<<6) +/* Video mode flags */ +#define V_PHSYNC (1<<0) +#define V_NHSYNC (1<<1) +#define V_PVSYNC (1<<2) +#define V_NVSYNC (1<<3) +#define V_INTERLACE (1<<4) +#define V_DBLSCAN (1<<5) +#define V_CSYNC (1<<6) +#define V_PCSYNC (1<<7) +#define V_NCSYNC (1<<8) +#define V_HSKEW (1<<9) /* hskew provided */ +#define V_BCAST (1<<10) +#define V_PIXMUX (1<<11) +#define V_DBLCLK (1<<12) +#define V_CLKDIV2 (1<<13) + +/* DPMS flags */ +#define DPMSModeOn 0 +#define DPMSModeStandby 1 +#define DPMSModeSuspend 2 +#define DPMSModeOff 3 + struct drm_mode_modeinfo { unsigned int clock; unsigned short hdisplay, hsync_start, hsync_end, htotal, hskew; @@ -1053,6 +1075,12 @@ struct drm_mode_crtc { struct drm_mode_modeinfo mode; }; +#define DRM_MODE_ENCODER_NONE 0 +#define DRM_MODE_ENCODER_DAC 1 +#define DRM_MODE_ENCODER_TMDS 2 +#define DRM_MODE_ENCODER_LVDS 3 +#define DRM_MODE_ENCODER_TVDAC 4 + struct drm_mode_get_encoder { uint32_t encoder_type; @@ -1063,11 +1091,29 @@ struct drm_mode_get_encoder { uint32_t clones; }; -#define DRM_MODE_ENCODER_NONE 0 -#define DRM_MODE_ENCODER_DAC 1 -#define DRM_MODE_ENCODER_TMDS 2 -#define DRM_MODE_ENCODER_LVDS 3 -#define DRM_MODE_ENCODER_TVDAC 4 +/* This is for connectors with multiple signal types. */ +/* Try to match DRM_MODE_CONNECTOR_X as closely as possible. */ +#define DRM_MODE_SUBCONNECTOR_Automatic 0 +#define DRM_MODE_SUBCONNECTOR_Unknown 0 +#define DRM_MODE_SUBCONNECTOR_DVID 3 +#define DRM_MODE_SUBCONNECTOR_DVIA 4 +#define DRM_MODE_SUBCONNECTOR_Composite 5 +#define DRM_MODE_SUBCONNECTOR_SVIDEO 6 +#define DRM_MODE_SUBCONNECTOR_Component 8 + +#define DRM_MODE_CONNECTOR_Unknown 0 +#define DRM_MODE_CONNECTOR_VGA 1 +#define DRM_MODE_CONNECTOR_DVII 2 +#define DRM_MODE_CONNECTOR_DVID 3 +#define DRM_MODE_CONNECTOR_DVIA 4 +#define DRM_MODE_CONNECTOR_Composite 5 +#define DRM_MODE_CONNECTOR_SVIDEO 6 +#define DRM_MODE_CONNECTOR_LVDS 7 +#define DRM_MODE_CONNECTOR_Component 8 +#define DRM_MODE_CONNECTOR_9PinDIN 9 +#define DRM_MODE_CONNECTOR_DisplayPort 10 +#define DRM_MODE_CONNECTOR_HDMIA 11 +#define DRM_MODE_CONNECTOR_HDMIB 12 struct drm_mode_get_connector { -- cgit v1.2.3 From 0028ca33e90d3405bd47a554e9398e0c2aa6099b Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Fri, 4 Jul 2008 17:37:45 +0200 Subject: Forgot the 0'th element for the tv property. --- linux-core/drm_crtc.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 1a381abe..095d44fa 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -592,6 +592,9 @@ int drm_mode_create_tv_properties(struct drm_device *dev, int num_modes, dev->mode_config.tv_select_subconnector_property = drm_property_create(dev, DRM_MODE_PROP_ENUM, "select subconnector", 4); + /* add enum element 0 */ + drm_property_add_enum(dev->mode_config.tv_select_subconnector_property, 0, drm_select_subconnector_enum_list[0].type, + drm_select_subconnector_enum_list[0].name); /* add enum element 3-5 */ for (i = 1; i < 4; i++) drm_property_add_enum(dev->mode_config.tv_select_subconnector_property, i, drm_select_subconnector_enum_list[i + 2].type, @@ -600,6 +603,9 @@ int drm_mode_create_tv_properties(struct drm_device *dev, int num_modes, /* This is a property which indicates the most likely thing to be connected. */ dev->mode_config.tv_subconnector_property = drm_property_create(dev, DRM_MODE_PROP_ENUM | DRM_MODE_PROP_IMMUTABLE, "subconnector", 4); + /* add enum element 0 */ + drm_property_add_enum(dev->mode_config.tv_subconnector_property, 0, drm_subconnector_enum_list[0].type, + drm_subconnector_enum_list[0].name); /* add enum element 3-5 */ for (i = 1; i < 4; i++) drm_property_add_enum(dev->mode_config.tv_subconnector_property, i, drm_subconnector_enum_list[i + 2].type, -- cgit v1.2.3 From be31a0fa73272b9c727668096ba652ea748a9735 Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Fri, 4 Jul 2008 18:47:59 +0200 Subject: modesetting-101: tv_left_margin_property shouldn't be immutable. --- linux-core/drm_crtc.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 095d44fa..3ee0f86c 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -612,8 +612,7 @@ int drm_mode_create_tv_properties(struct drm_device *dev, int num_modes, drm_subconnector_enum_list[i + 2].name); dev->mode_config.tv_left_margin_property = - drm_property_create(dev, DRM_MODE_PROP_RANGE | - DRM_MODE_PROP_IMMUTABLE, + drm_property_create(dev, DRM_MODE_PROP_RANGE, "left margin", 2); dev->mode_config.tv_left_margin_property->values[0] = 0; dev->mode_config.tv_left_margin_property->values[1] = 100; -- cgit v1.2.3 From 7cbc5f6145046f3775e3b3ca2862bfb71831ec44 Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Sat, 5 Jul 2008 12:04:07 +0200 Subject: modesetting-101: Make the interface variable names a little more consistent + modeprint changes. - All things are now called _id when they are id's. - modeprint now accepts driver name as first argument. --- libdrm/xf86drmMode.c | 21 ++++++++------------- libdrm/xf86drmMode.h | 10 +++++----- linux-core/drm_crtc.c | 18 +++++++++--------- shared-core/drm.h | 21 +++++++++------------ tests/modeprint/modetest.c | 25 +++++++++++++++++-------- 5 files changed, 48 insertions(+), 47 deletions(-) diff --git a/libdrm/xf86drmMode.c b/libdrm/xf86drmMode.c index ca21a961..c3921ee9 100644 --- a/libdrm/xf86drmMode.c +++ b/libdrm/xf86drmMode.c @@ -284,11 +284,6 @@ int drmModeSetCrtc(int fd, uint32_t crtcId, uint32_t bufferId, { struct drm_mode_crtc crtc; - crtc.count_connectors = 0; - crtc.connectors = 0; - crtc.count_possibles = 0; - crtc.possibles = 0; - crtc.x = x; crtc.y = y; crtc.crtc_id = crtcId; @@ -343,8 +338,8 @@ drmModeEncoderPtr drmModeGetEncoder(int fd, uint32_t encoder_id) enc.encoder_id = encoder_id; enc.encoder_type = 0; - enc.crtcs = 0; - enc.clones = 0; + enc.possible_crtcs = 0; + enc.possible_clones = 0; if (ioctl(fd, DRM_IOCTL_MODE_GETENCODER, &enc)) return 0; @@ -353,10 +348,10 @@ drmModeEncoderPtr drmModeGetEncoder(int fd, uint32_t encoder_id) return 0; r->encoder_id = enc.encoder_id; - r->crtc = enc.crtc; + r->crtc_id = enc.crtc_id; r->encoder_type = enc.encoder_type; - r->crtcs = enc.crtcs; - r->clones = enc.clones; + r->possible_crtcs = enc.possible_crtcs; + r->possible_clones = enc.possible_clones; return r; } @@ -370,7 +365,7 @@ drmModeConnectorPtr drmModeGetConnector(int fd, uint32_t connector_id) struct drm_mode_get_connector conn; drmModeConnectorPtr r = NULL; - conn.connector = connector_id; + conn.connector_id = connector_id; conn.connector_type_id = 0; conn.connector_type = 0; conn.count_modes = 0; @@ -402,8 +397,8 @@ drmModeConnectorPtr drmModeGetConnector(int fd, uint32_t connector_id) goto err_allocs; } - r->connector_id = conn.connector; - r->encoder = conn.encoder; + r->connector_id = conn.connector_id; + r->encoder_id = conn.encoder_id; r->connection = conn.connection; r->mmWidth = conn.mm_width; r->mmHeight = conn.mm_height; diff --git a/libdrm/xf86drmMode.h b/libdrm/xf86drmMode.h index 3e2f5c0e..59612a94 100644 --- a/libdrm/xf86drmMode.h +++ b/libdrm/xf86drmMode.h @@ -92,7 +92,7 @@ typedef struct _drmModeCrtc { unsigned int crtc_id; unsigned int buffer_id; /**< FB id to connect to 0 = disconnect */ - uint32_t x, y; /**< Position on the frameuffer */ + uint32_t x, y; /**< Position on the framebuffer */ uint32_t width, height; int mode_valid; struct drm_mode_modeinfo mode; @@ -104,9 +104,9 @@ typedef struct _drmModeCrtc { typedef struct _drmModeEncoder { unsigned int encoder_id; unsigned int encoder_type; - uint32_t crtc; - uint32_t crtcs; - uint32_t clones; + unsigned int crtc_id; + uint32_t possible_crtcs; + uint32_t possible_clones; } drmModeEncoder, *drmModeEncoderPtr; typedef enum { @@ -126,7 +126,7 @@ typedef enum { typedef struct _drmModeConnector { unsigned int connector_id; - unsigned int encoder; /**< Encoder currently connected to */ + unsigned int encoder_id; /**< Encoder currently connected to */ unsigned int connector_type; unsigned int connector_type_id; drmModeConnection connection; diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 3ee0f86c..f8e09a8c 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -1046,7 +1046,6 @@ int drm_mode_getcrtc(struct drm_device *dev, else crtc_resp->fb_id = 0; - crtc_resp->connectors = 0; if (crtc->enabled) { drm_crtc_convert_to_umode(&crtc_resp->mode, &crtc->mode); @@ -1099,11 +1098,11 @@ int drm_mode_getconnector(struct drm_device *dev, memset(&u_mode, 0, sizeof(struct drm_mode_modeinfo)); - DRM_DEBUG("connector id %d:\n", out_resp->connector); + DRM_DEBUG("connector id %d:\n", out_resp->connector_id); mutex_lock(&dev->mode_config.mutex); - obj = drm_mode_object_find(dev, out_resp->connector, DRM_MODE_OBJECT_CONNECTOR); + obj = drm_mode_object_find(dev, out_resp->connector_id, DRM_MODE_OBJECT_CONNECTOR); if (!obj) { ret = -EINVAL; goto out; @@ -1130,6 +1129,7 @@ int drm_mode_getconnector(struct drm_device *dev, list_for_each_entry(mode, &connector->modes, head) mode_count++; + out_resp->connector_id = connector->base.id; out_resp->connector_type = connector->connector_type; out_resp->connector_type_id = connector->connector_type_id; out_resp->mm_width = connector->display_info.width_mm; @@ -1137,9 +1137,9 @@ int drm_mode_getconnector(struct drm_device *dev, out_resp->subpixel = connector->display_info.subpixel_order; out_resp->connection = connector->status; if (connector->encoder) - out_resp->encoder = connector->encoder->base.id; + out_resp->encoder_id = connector->encoder->base.id; else - out_resp->encoder = 0; + out_resp->encoder_id = 0; /* this ioctl is called twice, once to determine how much space is needed, and the 2nd time to fill it */ if ((out_resp->count_modes >= mode_count) && mode_count) { @@ -1215,13 +1215,13 @@ int drm_mode_getencoder(struct drm_device *dev, encoder = obj_to_encoder(obj); if (encoder->crtc) - enc_resp->crtc = encoder->crtc->base.id; + enc_resp->crtc_id = encoder->crtc->base.id; else - enc_resp->crtc = 0; + enc_resp->crtc_id = 0; enc_resp->encoder_type = encoder->encoder_type; enc_resp->encoder_id = encoder->base.id; - enc_resp->crtcs = encoder->possible_crtcs; - enc_resp->clones = encoder->possible_clones; + enc_resp->possible_crtcs = encoder->possible_crtcs; + enc_resp->possible_clones = encoder->possible_clones; out: mutex_unlock(&dev->mode_config.mutex); diff --git a/shared-core/drm.h b/shared-core/drm.h index c9b40e78..b64e265d 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -1059,17 +1059,13 @@ struct drm_mode_card_res { struct drm_mode_crtc { uint64_t set_connectors_ptr; + int count_connectors; unsigned int crtc_id; /**< Id */ unsigned int fb_id; /**< Id of framebuffer */ int x, y; /**< Position on the frameuffer */ - int count_connectors; - unsigned int connectors; /**< Connectors that are connected */ - - int count_possibles; - unsigned int possibles; /**< Connectors that can be connected */ uint32_t gamma_size; int mode_valid; struct drm_mode_modeinfo mode; @@ -1083,12 +1079,13 @@ struct drm_mode_crtc { struct drm_mode_get_encoder { - uint32_t encoder_type; - uint32_t encoder_id; + unsigned int encoder_type; + unsigned int encoder_id; + + unsigned int crtc_id; /**< Id of crtc */ - unsigned int crtc; /**< Id of crtc */ - uint32_t crtcs; - uint32_t clones; + uint32_t possible_crtcs; + uint32_t possible_clones; }; /* This is for connectors with multiple signal types. */ @@ -1126,8 +1123,8 @@ struct drm_mode_get_connector { int count_props; int count_encoders; - unsigned int encoder; /**< Current Encoder */ - unsigned int connector; /**< Id */ + unsigned int encoder_id; /**< Current Encoder */ + unsigned int connector_id; /**< Id */ unsigned int connector_type; unsigned int connector_type_id; diff --git a/tests/modeprint/modetest.c b/tests/modeprint/modetest.c index d5cbbc56..cefa5262 100644 --- a/tests/modeprint/modetest.c +++ b/tests/modeprint/modetest.c @@ -17,6 +17,7 @@ int full_modes; int encoders; int crtcs; int fbs; +char *module_name; const char* getConnectionText(drmModeConnection conn) { @@ -115,7 +116,7 @@ int printConnector(int fd, drmModeResPtr res, drmModeConnectorPtr connector, uin printf("Connector: %d-%d\n", connector->connector_type, connector->connector_type_id); printf("\tid : %i\n", id); - printf("\tencoder id : %i\n", connector->encoder); + printf("\tencoder id : %i\n", connector->encoder_id); printf("\tconn : %s\n", getConnectionText(connector->connection)); printf("\tsize : %ix%i (mm)\n", connector->mmWidth, connector->mmHeight); printf("\tcount_modes : %i\n", connector->count_modes); @@ -159,10 +160,10 @@ int printEncoder(int fd, drmModeResPtr res, drmModeEncoderPtr encoder, uint32_t { printf("Encoder\n"); printf("\tid :%i\n", id); - printf("\tcrtc :%d\n", encoder->crtc); + printf("\tcrtc_id :%d\n", encoder->crtc_id); printf("\ttype :%d\n", encoder->encoder_type); - printf("\tcrtcs :%d\n", encoder->crtcs); - printf("\tclones :%d\n", encoder->clones); + printf("\tpossible_crtcs :%d\n", encoder->possible_crtcs); + printf("\tpossible_clones :%d\n", encoder->possible_clones); return 0; } @@ -283,7 +284,9 @@ void args(int argc, char **argv) full_props = 0; connectors = 0; - for (i = 1; i < argc; i++) { + module_name = argv[1]; + + for (i = 2; i < argc; i++) { if (strcmp(argv[i], "-fb") == 0) { fbs = 1; } else if (strcmp(argv[i], "-crtcs") == 0) { @@ -316,9 +319,9 @@ void args(int argc, char **argv) full_props = 1; connectors = 1; } - } + } - if (argc == 1) { + if (argc == 2) { fbs = 1; edid = 1; crtcs = 1; @@ -329,16 +332,22 @@ void args(int argc, char **argv) connectors = 1; } } + int main(int argc, char **argv) { int fd; drmModeResPtr res; + if (argc == 1) { + printf("Please add modulename as first argument\n"); + return 1; + } + args(argc, argv); printf("Starting test\n"); - fd = drmOpen("i915", NULL); + fd = drmOpen(module_name, NULL); if (fd < 0) { printf("Failed to open the card fd (%d)\n",fd); -- cgit v1.2.3 From c48cddc7ef984c1e05ed4f64a7fc182b6a5031f5 Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Sat, 5 Jul 2008 16:54:26 +0200 Subject: NV50: fix switch_fb and connector_is_digital --- linux-core/nv50_kms_wrapper.c | 52 ++++++++++++++++++++++++++++++------------- 1 file changed, 37 insertions(+), 15 deletions(-) diff --git a/linux-core/nv50_kms_wrapper.c b/linux-core/nv50_kms_wrapper.c index ee18b36a..520028aa 100644 --- a/linux-core/nv50_kms_wrapper.c +++ b/linux-core/nv50_kms_wrapper.c @@ -348,7 +348,7 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) blank = true; } - if (!set->connectors && modeset) { + if (!set->connectors && (modeset || switch_fb)) { DRM_ERROR("Sanity check failed\n"); goto out; } @@ -368,7 +368,8 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) * Wiring up the encoders and connectors. */ - if (modeset) { + /* for switch_fb we verify if any important changes happened */ + if (modeset || switch_fb) { /* Mode validation */ hw_mode = nv50_kms_to_hw_mode(set->mode); @@ -398,10 +399,18 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) DRM_ERROR("Mode not ok\n"); goto out; } - } - /* Validation done, move on to cleaning of existing structures. */ + /* verify if any "sneaky" changes happened */ + if (output != connector->output) + modeset = true; + + if (output->crtc != crtc) + modeset = true; + } + } + /* Validation done, move on to cleaning of existing structures. */ + if (modeset) { /* find encoders that use this crtc. */ list_for_each_entry(drm_encoder, &dev->mode_config.encoder_list, head) { if (drm_encoder->crtc == set->crtc) { @@ -474,8 +483,18 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) if (blank) { crtc = to_nv50_crtc(set->crtc); - /* keeping the encoders and connectors attached, so they can be tracked */ set->crtc->enabled = false; + + /* disconnect encoders and connectors */ + for (i = 0; i < set->num_connectors; i++) { + drm_connector = set->connectors[i]; + + if (!drm_connector->encoder) + continue; + + drm_connector->encoder->crtc = NULL; + drm_connector->encoder = NULL; + } } /** @@ -535,9 +554,9 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) goto out; } - /* detach any outputs that are currently running on this crtc */ + /* detach any outputs that are currently unused */ list_for_each_entry(drm_encoder, &dev->mode_config.encoder_list, head) { - if (drm_encoder->crtc == set->crtc) { + if (!drm_encoder->crtc) { output = to_nv50_output(drm_encoder); rval = output->execute_mode(output, true); @@ -556,12 +575,6 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) if (switch_fb && !modeset && !blank) { crtc = to_nv50_crtc(set->crtc); - rval = crtc->blank(crtc, true); - if (rval != 0) { - DRM_ERROR("blanking failed\n"); - goto out; - } - rval = crtc->set_fb(crtc); if (rval != 0) { DRM_ERROR("set_fb failed\n"); @@ -657,7 +670,9 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) /* next line changes crtc, so putting it here is important */ display->last_crtc = crtc->index; + } + if (switch_fb || modeset) { /* this is executed immediately */ list_for_each_entry(output, &display->outputs, item) { if (output->crtc != crtc) @@ -690,6 +705,13 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) display->update(display); + /* Update the current mode, now that all has gone well. */ + if (modeset) { + set->crtc->mode = *(set->mode); + set->crtc->x = set->x; + set->crtc->y = set->y; + } + kfree(hw_mode); return 0; @@ -826,7 +848,7 @@ bool nv50_kms_connector_is_digital(struct drm_connector *drm_connector) uint64_t prop_val; rval = drm_connector_property_get_value(drm_connector, dev->mode_config.dvi_i_select_subconnector_property, &prop_val); - if (!rval) { + if (rval) { DRM_ERROR("Unable to find select subconnector property, defaulting to DVI-D\n"); return true; } @@ -842,7 +864,7 @@ bool nv50_kms_connector_is_digital(struct drm_connector *drm_connector) } rval = drm_connector_property_get_value(drm_connector, dev->mode_config.dvi_i_subconnector_property, &prop_val); - if (!rval) { + if (rval) { DRM_ERROR("Unable to find subconnector property, defaulting to DVI-D\n"); return true; } -- cgit v1.2.3 From e1cd21bcc8747fcc573708bd4d74df39b60c476a Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Sat, 5 Jul 2008 20:17:49 +0200 Subject: NV50: remove edid when monitor is gone, improve fbcon, misc fixes - This should avoid switching crtc's when going to fbcon. --- linux-core/drm_crtc.c | 7 +++++++ linux-core/nv50_fbcon.c | 46 ++++++++++++++++++++++++++++++++++--------- linux-core/nv50_kms_wrapper.c | 31 ++++++++++++++++++----------- 3 files changed, 64 insertions(+), 20 deletions(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index f8e09a8c..47885a07 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -2046,6 +2046,13 @@ int drm_mode_connector_update_edid_property(struct drm_connector *connector, str if (connector->edid_blob_ptr) drm_property_destroy_blob(dev, connector->edid_blob_ptr); + /* Delete edid, when there is none. */ + if (!edid) { + connector->edid_blob_ptr = NULL; + ret = drm_connector_property_set_value(connector, dev->mode_config.edid_property, 0); + return ret; + } + connector->edid_blob_ptr = drm_property_create_blob(connector->dev, 128, edid); ret = drm_connector_property_set_value(connector, dev->mode_config.edid_property, connector->edid_blob_ptr->base.id); diff --git a/linux-core/nv50_fbcon.c b/linux-core/nv50_fbcon.c index c428ff94..8969860b 100644 --- a/linux-core/nv50_fbcon.c +++ b/linux-core/nv50_fbcon.c @@ -284,16 +284,21 @@ static int nv50_fbcon_set_par(struct fb_info *info) } mode_set.mode = drm_mode; - list_for_each_entry(drm_crtc, &dev->mode_config.crtc_list, head) { - if (crtc_used[crtc_count]) { - crtc_count++; - continue; + /* choose crtc it already has, if possible */ + if (drm_connector->encoder) { + struct drm_encoder *drm_encoder = drm_connector->encoder; + + if (drm_encoder->crtc) { + list_for_each_entry(drm_crtc, &dev->mode_config.crtc_list, head) { + crtc_count++; + + if (drm_crtc == drm_encoder->crtc) { + if (!crtc_used[crtc_count]) /* still available? */ + mode_set.crtc = drm_crtc; + break; + } + } } - - /* found a crtc */ - mode_set.crtc = drm_crtc; - - break; } /* proceed as planned */ @@ -302,6 +307,29 @@ static int nv50_fbcon_set_par(struct fb_info *info) crtc_used[crtc_count] = true; } + if (!mode_set.crtc) { + crtc_count = 0; /* reset */ + + /* choose a "random" crtc */ + list_for_each_entry(drm_crtc, &dev->mode_config.crtc_list, head) { + if (crtc_used[crtc_count]) { + crtc_count++; + continue; + } + + /* found a crtc */ + mode_set.crtc = drm_crtc; + + break; + } + + /* proceed as planned */ + if (mode_set.crtc) { + mode_set.crtc->funcs->set_config(&mode_set); + crtc_used[crtc_count] = true; + } + } + kfree(mode_set.connectors); } diff --git a/linux-core/nv50_kms_wrapper.c b/linux-core/nv50_kms_wrapper.c index 520028aa..03c60c1f 100644 --- a/linux-core/nv50_kms_wrapper.c +++ b/linux-core/nv50_kms_wrapper.c @@ -348,16 +348,11 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) blank = true; } - if (!set->connectors && (modeset || switch_fb)) { + if (!set->connectors && !blank) { DRM_ERROR("Sanity check failed\n"); goto out; } - if (!modeset && !switch_fb && !blank) { - DRM_ERROR("There is nothing to do, bad input.\n"); - goto out; - } - /* Basic variable setting */ dev = set->crtc->dev; dev_priv = dev->dev_private; @@ -369,7 +364,7 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) */ /* for switch_fb we verify if any important changes happened */ - if (modeset || switch_fb) { + if (!blank) { /* Mode validation */ hw_mode = nv50_kms_to_hw_mode(set->mode); @@ -388,6 +383,9 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) } connector = to_nv50_connector(drm_connector); + /* This is to ensure it knows the connector subtype. */ + drm_connector->funcs->fill_modes(drm_connector, 0, 0); + output = connector->to_output(connector, nv50_kms_connector_is_digital(drm_connector)); if (!output) { DRM_ERROR("No output\n"); @@ -409,6 +407,12 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) } } + /* Now we verified if anything changed, fail if nothing has. */ + if (!modeset && !switch_fb && !blank) { + DRM_ERROR("There is nothing to do, bad input.\n"); + goto out; + } + /* Validation done, move on to cleaning of existing structures. */ if (modeset) { /* find encoders that use this crtc. */ @@ -913,6 +917,7 @@ static enum drm_connector_status nv50_kms_connector_detect(struct drm_connector /* update our modes whenever there is reason to */ if (old_status != drm_connector->status) { drm_connector->funcs->fill_modes(drm_connector, 0, 0); + /* notify fb of changes */ dev->mode_config.funcs->fb_changed(dev); } @@ -966,16 +971,16 @@ static void nv50_kms_connector_fill_modes(struct drm_connector *drm_connector, u if (!connected) { NV50_DEBUG("%s is disconnected\n", drm_get_connector_name(drm_connector)); - /* TODO set EDID to NULL */ - return; } /* Not all connnectors have an i2c channel. */ - if (connector->i2c_chan) + if (connected && connector->i2c_chan) edid = (struct edid *) drm_do_probe_ddc_edid(&connector->i2c_chan->adapter); + /* This will remove edid if needed. */ + drm_mode_connector_update_edid_property(drm_connector, edid); + if (edid) { - drm_mode_connector_update_edid_property(drm_connector, edid); rval = drm_add_edid_modes(drm_connector, edid); /* 2 encoders per connector */ @@ -1026,6 +1031,10 @@ static void nv50_kms_connector_fill_modes(struct drm_connector *drm_connector, u drm_mode_prune_invalid(dev, &drm_connector->modes, true); + /* pruning is done, so bail out. */ + if (!connected) + return; + if (list_empty(&drm_connector->modes)) { struct drm_display_mode *stdmode; struct nouveau_hw_mode *hw_mode; -- cgit v1.2.3 From d495a6e28f7fe5428c1ceb75378cad31b51a517a Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Sun, 6 Jul 2008 10:11:33 +0200 Subject: NV50: minor fix --- linux-core/nv50_kms_wrapper.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/linux-core/nv50_kms_wrapper.c b/linux-core/nv50_kms_wrapper.c index 03c60c1f..0954f0e8 100644 --- a/linux-core/nv50_kms_wrapper.c +++ b/linux-core/nv50_kms_wrapper.c @@ -408,10 +408,8 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) } /* Now we verified if anything changed, fail if nothing has. */ - if (!modeset && !switch_fb && !blank) { - DRM_ERROR("There is nothing to do, bad input.\n"); - goto out; - } + if (!modeset && !switch_fb && !blank) + DRM_INFO("A seemingly empty modeset encountered, this could be a bug.\n"); /* Validation done, move on to cleaning of existing structures. */ if (modeset) { @@ -676,7 +674,8 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) display->last_crtc = crtc->index; } - if (switch_fb || modeset) { + /* always reset dpms, regardless if any other modesetting is done. */ + if (!blank) { /* this is executed immediately */ list_for_each_entry(output, &display->outputs, item) { if (output->crtc != crtc) -- cgit v1.2.3 From e810cb9243fe6c4905182869d9e3272d861a14cb Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Sun, 6 Jul 2008 10:52:25 +0200 Subject: modesetting-101: rename modeflags, as to avoid conflicts with the xorg definitions --- linux-core/drm_crtc_helper.c | 2 +- linux-core/drm_edid.c | 40 ++++++++++++++++++++-------------------- linux-core/drm_modes.c | 8 ++++---- linux-core/dvo_ch7xxx.c | 4 ++-- linux-core/intel_crt.c | 6 +++--- linux-core/intel_display.c | 2 +- linux-core/intel_dvo.c | 10 +++++----- linux-core/intel_fb.c | 4 ++-- linux-core/intel_sdvo.c | 6 +++--- linux-core/nv50_crtc.c | 10 +++++----- linux-core/nv50_dac.c | 4 ++-- linux-core/nv50_fbcon.c | 4 ++-- linux-core/nv50_kms_wrapper.c | 4 ++-- linux-core/nv50_sor.c | 4 ++-- shared-core/drm.h | 29 +++++++++++++++-------------- 15 files changed, 69 insertions(+), 68 deletions(-) diff --git a/linux-core/drm_crtc_helper.c b/linux-core/drm_crtc_helper.c index bfddab99..d5a9f279 100644 --- a/linux-core/drm_crtc_helper.c +++ b/linux-core/drm_crtc_helper.c @@ -38,7 +38,7 @@ static struct drm_display_mode std_mode[] = { { DRM_MODE("640x480", DRM_MODE_TYPE_DEFAULT, 25200, 640, 656, 752, 800, 0, 480, 490, 492, 525, 0, - V_NHSYNC | V_NVSYNC) }, /* 640x480@60Hz */ + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 640x480@60Hz */ }; /** diff --git a/linux-core/drm_edid.c b/linux-core/drm_edid.c index 22c6e3bf..a3d9861f 100644 --- a/linux-core/drm_edid.c +++ b/linux-core/drm_edid.c @@ -335,15 +335,15 @@ static struct drm_display_mode *drm_mode_detailed(struct drm_device *dev, drm_mode_set_name(mode); if (pt->interlaced) - mode->flags |= V_INTERLACE; + mode->flags |= DRM_MODE_FLAG_INTERLACE; if (quirks & EDID_QUIRK_DETAILED_SYNC_PP) { pt->hsync_positive = 1; pt->vsync_positive = 1; } - mode->flags |= pt->hsync_positive ? V_PHSYNC : V_NHSYNC; - mode->flags |= pt->vsync_positive ? V_PVSYNC : V_NVSYNC; + mode->flags |= pt->hsync_positive ? DRM_MODE_FLAG_PHSYNC : DRM_MODE_FLAG_NHSYNC; + mode->flags |= pt->vsync_positive ? DRM_MODE_FLAG_PVSYNC : DRM_MODE_FLAG_NVSYNC; mode->width_mm = pt->width_mm_lo | (pt->width_mm_hi << 8); mode->height_mm = pt->height_mm_lo | (pt->height_mm_hi << 8); @@ -367,55 +367,55 @@ static struct drm_display_mode *drm_mode_detailed(struct drm_device *dev, static struct drm_display_mode edid_est_modes[] = { { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 40000, 800, 840, 968, 1056, 0, 600, 601, 605, 628, 0, - V_PHSYNC | V_PVSYNC) }, /* 800x600@60Hz */ + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 800x600@60Hz */ { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 36000, 800, 824, 896, 1024, 0, 600, 601, 603, 625, 0, - V_PHSYNC | V_PVSYNC) }, /* 800x600@56Hz */ + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 800x600@56Hz */ { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 31500, 640, 656, 720, 840, 0, 480, 481, 484, 500, 0, - V_NHSYNC | V_NVSYNC) }, /* 640x480@75Hz */ + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 640x480@75Hz */ { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 31500, 640, 664, 704, 832, 0, 480, 489, 491, 520, 0, - V_NHSYNC | V_NVSYNC) }, /* 640x480@72Hz */ + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 640x480@72Hz */ { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 30240, 640, 704, 768, 864, 0, 480, 483, 486, 525, 0, - V_NHSYNC | V_NVSYNC) }, /* 640x480@67Hz */ + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 640x480@67Hz */ { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25200, 640, 656, 752, 800, 0, 480, 490, 492, 525, 0, - V_NHSYNC | V_NVSYNC) }, /* 640x480@60Hz */ + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 640x480@60Hz */ { DRM_MODE("720x400", DRM_MODE_TYPE_DRIVER, 35500, 720, 738, 846, 900, 0, 400, 421, 423, 449, 0, - V_NHSYNC | V_NVSYNC) }, /* 720x400@88Hz */ + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 720x400@88Hz */ { DRM_MODE("720x400", DRM_MODE_TYPE_DRIVER, 28320, 720, 738, 846, 900, 0, 400, 412, 414, 449, 0, - V_NHSYNC | V_PVSYNC) }, /* 720x400@70Hz */ + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 720x400@70Hz */ { DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 135000, 1280, 1296, 1440, 1688, 0, 1024, 1025, 1028, 1066, 0, - V_PHSYNC | V_PVSYNC) }, /* 1280x1024@75Hz */ + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 1280x1024@75Hz */ { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 78800, 1024, 1040, 1136, 1312, 0, 768, 769, 772, 800, 0, - V_PHSYNC | V_PVSYNC) }, /* 1024x768@75Hz */ + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 1024x768@75Hz */ { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 75000, 1024, 1048, 1184, 1328, 0, 768, 771, 777, 806, 0, - V_NHSYNC | V_NVSYNC) }, /* 1024x768@70Hz */ + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 1024x768@70Hz */ { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 65000, 1024, 1048, 1184, 1344, 0, 768, 771, 777, 806, 0, - V_NHSYNC | V_NVSYNC) }, /* 1024x768@60Hz */ + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 1024x768@60Hz */ { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER,44900, 1024, 1032, 1208, 1264, 0, 768, 768, 776, 817, 0, - V_PHSYNC | V_PVSYNC | V_INTERLACE) }, /* 1024x768@43Hz */ + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC | DRM_MODE_FLAG_INTERLACE) }, /* 1024x768@43Hz */ { DRM_MODE("832x624", DRM_MODE_TYPE_DRIVER, 57284, 832, 864, 928, 1152, 0, 624, 625, 628, 667, 0, - V_NHSYNC | V_NVSYNC) }, /* 832x624@75Hz */ + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) }, /* 832x624@75Hz */ { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 49500, 800, 816, 896, 1056, 0, 600, 601, 604, 625, 0, - V_PHSYNC | V_PVSYNC) }, /* 800x600@75Hz */ + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 800x600@75Hz */ { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 50000, 800, 856, 976, 1040, 0, 600, 637, 643, 666, 0, - V_PHSYNC | V_PVSYNC) }, /* 800x600@72Hz */ + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 800x600@72Hz */ { DRM_MODE("1152x864", DRM_MODE_TYPE_DRIVER, 108000, 1152, 1216, 1344, 1600, 0, 864, 865, 868, 900, 0, - V_PHSYNC | V_PVSYNC) }, /* 1152x864@75Hz */ + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 1152x864@75Hz */ }; #define EDID_EST_TIMINGS 16 diff --git a/linux-core/drm_modes.c b/linux-core/drm_modes.c index df670c74..4ee00305 100644 --- a/linux-core/drm_modes.c +++ b/linux-core/drm_modes.c @@ -162,9 +162,9 @@ int drm_mode_vrefresh(struct drm_display_mode *mode) calc_val /= mode->vtotal; refresh = calc_val; - if (mode->flags & V_INTERLACE) + if (mode->flags & DRM_MODE_FLAG_INTERLACE) refresh *= 2; - if (mode->flags & V_DBLSCAN) + if (mode->flags & DRM_MODE_FLAG_DBLSCAN) refresh /= 2; if (mode->vscan > 1) refresh /= mode->vscan; @@ -198,7 +198,7 @@ void drm_mode_set_crtcinfo(struct drm_display_mode *p, int adjust_flags) p->crtc_vsync_end = p->vsync_end; p->crtc_vtotal = p->vtotal; - if (p->flags & V_INTERLACE) { + if (p->flags & DRM_MODE_FLAG_INTERLACE) { if (adjust_flags & CRTC_INTERLACE_HALVE_V) { p->crtc_vdisplay /= 2; p->crtc_vsync_start /= 2; @@ -209,7 +209,7 @@ void drm_mode_set_crtcinfo(struct drm_display_mode *p, int adjust_flags) p->crtc_vtotal |= 1; } - if (p->flags & V_DBLSCAN) { + if (p->flags & DRM_MODE_FLAG_DBLSCAN) { p->crtc_vdisplay *= 2; p->crtc_vsync_start *= 2; p->crtc_vsync_end *= 2; diff --git a/linux-core/dvo_ch7xxx.c b/linux-core/dvo_ch7xxx.c index 18922556..1fe9eb0f 100644 --- a/linux-core/dvo_ch7xxx.c +++ b/linux-core/dvo_ch7xxx.c @@ -289,10 +289,10 @@ static void ch7xxx_mode_set(struct intel_dvo_device *dvo, ch7xxx_readb(dvo, CH7xxx_IDF, &idf); idf &= ~(CH7xxx_IDF_HSP | CH7xxx_IDF_VSP); - if (mode->flags & V_PHSYNC) + if (mode->flags & DRM_MODE_FLAG_PHSYNC) idf |= CH7xxx_IDF_HSP; - if (mode->flags & V_PVSYNC) + if (mode->flags & DRM_MODE_FLAG_PVSYNC) idf |= CH7xxx_IDF_HSP; ch7xxx_writeb(dvo, CH7xxx_IDF, idf); diff --git a/linux-core/intel_crt.c b/linux-core/intel_crt.c index b9e8ee63..4326aef9 100644 --- a/linux-core/intel_crt.c +++ b/linux-core/intel_crt.c @@ -74,7 +74,7 @@ static void intel_crt_restore(struct drm_connector *connector) static int intel_crt_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { - if (mode->flags & V_DBLSCAN) + if (mode->flags & DRM_MODE_FLAG_DBLSCAN) return MODE_NO_DBLESCAN; if (mode->clock > 400000 || mode->clock < 25000) @@ -118,9 +118,9 @@ static void intel_crt_mode_set(struct drm_encoder *encoder, } adpa = 0; - if (adjusted_mode->flags & V_PHSYNC) + if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) adpa |= ADPA_HSYNC_ACTIVE_HIGH; - if (adjusted_mode->flags & V_PVSYNC) + if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) adpa |= ADPA_VSYNC_ACTIVE_HIGH; if (intel_crtc->pipe == 0) diff --git a/linux-core/intel_display.c b/linux-core/intel_display.c index 0a2854a2..b82993fc 100644 --- a/linux-core/intel_display.c +++ b/linux-core/intel_display.c @@ -1112,7 +1112,7 @@ static void intel_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green, /* VESA 640x480x72Hz mode to set on the pipe */ static struct drm_display_mode load_detect_mode = { DRM_MODE("640x480", DRM_MODE_TYPE_DEFAULT, 31500, 640, 664, - 704, 832, 0, 480, 489, 491, 520, 0, V_NHSYNC | V_NVSYNC), + 704, 832, 0, 480, 489, 491, 520, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC), }; struct drm_crtc *intel_get_load_detect_pipe(struct intel_output *intel_output, diff --git a/linux-core/intel_dvo.c b/linux-core/intel_dvo.c index e6df8fdd..a3842a91 100644 --- a/linux-core/intel_dvo.c +++ b/linux-core/intel_dvo.c @@ -139,7 +139,7 @@ static int intel_dvo_mode_valid(struct drm_connector *connector, struct intel_output *intel_output = to_intel_output(connector); struct intel_dvo_device *dvo = intel_output->dev_priv; - if (mode->flags & V_DBLSCAN) + if (mode->flags & DRM_MODE_FLAG_DBLSCAN) return MODE_NO_DBLESCAN; /* XXX: Validate clock range */ @@ -225,9 +225,9 @@ static void intel_dvo_mode_set(struct drm_encoder *encoder, if (pipe == 1) dvo_val |= DVO_PIPE_B_SELECT; dvo_val |= DVO_PIPE_STALL; - if (adjusted_mode->flags & V_PHSYNC) + if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) dvo_val |= DVO_HSYNC_ACTIVE_HIGH; - if (adjusted_mode->flags & V_PVSYNC) + if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) dvo_val |= DVO_VSYNC_ACTIVE_HIGH; I915_WRITE(dpll_reg, I915_READ(dpll_reg) | DPLL_DVO_HIGH_SPEED); @@ -387,9 +387,9 @@ intel_dvo_get_current_mode (struct drm_connector *connector) if (mode) { mode->type |= DRM_MODE_TYPE_PREFERRED; if (dvo_val & DVO_HSYNC_ACTIVE_HIGH) - mode->flags |= V_PHSYNC; + mode->flags |= DRM_MODE_FLAG_PHSYNC; if (dvo_val & DVO_VSYNC_ACTIVE_HIGH) - mode->flags |= V_PVSYNC; + mode->flags |= DRM_MODE_FLAG_PVSYNC; } } } diff --git a/linux-core/intel_fb.c b/linux-core/intel_fb.c index cbd22ba6..5637ea2f 100644 --- a/linux-core/intel_fb.c +++ b/linux-core/intel_fb.c @@ -263,8 +263,8 @@ static int intelfb_set_par(struct fb_info *info) drm_mode->clock = PICOS2KHZ(var->pixclock); drm_mode->vrefresh = drm_mode_vrefresh(drm_mode); drm_mode->flags = 0; - drm_mode->flags |= var->sync & FB_SYNC_HOR_HIGH_ACT ? V_PHSYNC : V_NHSYNC; - drm_mode->flags |= var->sync & FB_SYNC_VERT_HIGH_ACT ? V_PVSYNC : V_NVSYNC; + drm_mode->flags |= var->sync & FB_SYNC_HOR_HIGH_ACT ? DRM_MODE_FLAG_PHSYNC : DRM_MODE_FLAG_NHSYNC; + drm_mode->flags |= var->sync & FB_SYNC_VERT_HIGH_ACT ? DRM_MODE_FLAG_PVSYNC : DRM_MODE_FLAG_NVSYNC; drm_mode_set_name(drm_mode); drm_mode_set_crtcinfo(drm_mode, CRTC_INTERLACE_HALVE_V); diff --git a/linux-core/intel_sdvo.c b/linux-core/intel_sdvo.c index f0a47e2e..2143bdc0 100644 --- a/linux-core/intel_sdvo.c +++ b/linux-core/intel_sdvo.c @@ -602,9 +602,9 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder, ((v_sync_len & 0x30) >> 4); output_dtd.part2.dtd_flags = 0x18; - if (mode->flags & V_PHSYNC) + if (mode->flags & DRM_MODE_FLAG_PHSYNC) output_dtd.part2.dtd_flags |= 0x2; - if (mode->flags & V_PVSYNC) + if (mode->flags & DRM_MODE_FLAG_PVSYNC) output_dtd.part2.dtd_flags |= 0x4; output_dtd.part2.sdvo_flags = 0; @@ -825,7 +825,7 @@ static int intel_sdvo_mode_valid(struct drm_connector *connector, struct intel_output *intel_output = to_intel_output(connector); struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; - if (mode->flags & V_DBLSCAN) + if (mode->flags & DRM_MODE_FLAG_DBLSCAN) return MODE_NO_DBLESCAN; if (sdvo_priv->pixel_clock_min > mode->clock) diff --git a/linux-core/nv50_crtc.c b/linux-core/nv50_crtc.c index c9745e08..6c3d404f 100644 --- a/linux-core/nv50_crtc.c +++ b/linux-core/nv50_crtc.c @@ -92,14 +92,14 @@ static int nv50_crtc_execute_mode(struct nv50_crtc *crtc) vunk2a = 2*hw_mode->vtotal - hw_mode->vsync_start + hw_mode->vblank_start; vunk2b = hw_mode->vtotal - hw_mode->vsync_start + hw_mode->vblank_end; - if (hw_mode->flags & V_INTERLACE) { + if (hw_mode->flags & DRM_MODE_FLAG_INTERLACE) { vsync_dur /= 2; vsync_start_to_end /= 2; vunk1 /= 2; vunk2a /= 2; vunk2b /= 2; /* magic */ - if (hw_mode->flags & V_DBLSCAN) { + if (hw_mode->flags & DRM_MODE_FLAG_DBLSCAN) { vsync_start_to_end -= 1; vunk1 -= 1; vunk2a -= 1; @@ -108,14 +108,14 @@ static int nv50_crtc_execute_mode(struct nv50_crtc *crtc) } OUT_MODE(NV50_CRTC0_CLOCK + offset, hw_mode->clock | 0x800000); - OUT_MODE(NV50_CRTC0_INTERLACE + offset, (hw_mode->flags & V_INTERLACE) ? 2 : 0); + OUT_MODE(NV50_CRTC0_INTERLACE + offset, (hw_mode->flags & DRM_MODE_FLAG_INTERLACE) ? 2 : 0); OUT_MODE(NV50_CRTC0_DISPLAY_START + offset, 0); OUT_MODE(NV50_CRTC0_UNK82C + offset, 0); OUT_MODE(NV50_CRTC0_DISPLAY_TOTAL + offset, hw_mode->vtotal << 16 | hw_mode->htotal); OUT_MODE(NV50_CRTC0_SYNC_DURATION + offset, (vsync_dur - 1) << 16 | (hsync_dur - 1)); OUT_MODE(NV50_CRTC0_SYNC_START_TO_BLANK_END + offset, (vsync_start_to_end - 1) << 16 | (hsync_start_to_end - 1)); OUT_MODE(NV50_CRTC0_MODE_UNK1 + offset, (vunk1 - 1) << 16 | (hunk1 - 1)); - if (hw_mode->flags & V_INTERLACE) { + if (hw_mode->flags & DRM_MODE_FLAG_INTERLACE) { OUT_MODE(NV50_CRTC0_MODE_UNK2 + offset, (vunk2b - 1) << 16 | (vunk2a - 1)); } @@ -273,7 +273,7 @@ static int nv50_crtc_set_scale(struct nv50_crtc *crtc) /* Got a better name for SCALER_ACTIVE? */ /* One day i've got to really figure out why this is needed. */ - if ((crtc->mode->flags & V_DBLSCAN) || (crtc->mode->flags & V_INTERLACE) || + if ((crtc->mode->flags & DRM_MODE_FLAG_DBLSCAN) || (crtc->mode->flags & DRM_MODE_FLAG_INTERLACE) || crtc->mode->hdisplay != outX || crtc->mode->vdisplay != outY) { OUT_MODE(NV50_CRTC0_SCALE_CTRL + offset, NV50_CRTC0_SCALE_CTRL_SCALER_ACTIVE); } else { diff --git a/linux-core/nv50_dac.c b/linux-core/nv50_dac.c index 34b54902..ce01d573 100644 --- a/linux-core/nv50_dac.c +++ b/linux-core/nv50_dac.c @@ -73,10 +73,10 @@ static int nv50_dac_execute_mode(struct nv50_output *output, bool disconnect) mode_ctl |= 0x100; } - if (desired_mode->flags & V_NHSYNC) + if (desired_mode->flags & DRM_MODE_FLAG_NHSYNC) mode_ctl2 |= NV50_DAC_MODE_CTRL2_NHSYNC; - if (desired_mode->flags & V_NVSYNC) + if (desired_mode->flags & DRM_MODE_FLAG_NVSYNC) mode_ctl2 |= NV50_DAC_MODE_CTRL2_NVSYNC; OUT_MODE(NV50_DAC0_MODE_CTRL + offset, mode_ctl); diff --git a/linux-core/nv50_fbcon.c b/linux-core/nv50_fbcon.c index 8969860b..80597a76 100644 --- a/linux-core/nv50_fbcon.c +++ b/linux-core/nv50_fbcon.c @@ -239,8 +239,8 @@ static int nv50_fbcon_set_par(struct fb_info *info) drm_mode->clock = PICOS2KHZ(var->pixclock); drm_mode->vrefresh = drm_mode_vrefresh(drm_mode); drm_mode->flags = 0; - drm_mode->flags |= var->sync & FB_SYNC_HOR_HIGH_ACT ? V_PHSYNC : V_NHSYNC; - drm_mode->flags |= var->sync & FB_SYNC_VERT_HIGH_ACT ? V_PVSYNC : V_NVSYNC; + drm_mode->flags |= var->sync & FB_SYNC_HOR_HIGH_ACT ? DRM_MODE_FLAG_PHSYNC : DRM_MODE_FLAG_NHSYNC; + drm_mode->flags |= var->sync & FB_SYNC_VERT_HIGH_ACT ? DRM_MODE_FLAG_PVSYNC : DRM_MODE_FLAG_NVSYNC; drm_mode_set_name(drm_mode); drm_mode_set_crtcinfo(drm_mode, CRTC_INTERLACE_HALVE_V); diff --git a/linux-core/nv50_kms_wrapper.c b/linux-core/nv50_kms_wrapper.c index 0954f0e8..b7ba7b00 100644 --- a/linux-core/nv50_kms_wrapper.c +++ b/linux-core/nv50_kms_wrapper.c @@ -941,10 +941,10 @@ static void nv50_kms_connector_destroy(struct drm_connector *drm_connector) static struct drm_display_mode std_mode[] = { /*{ DRM_MODE("640x480", DRM_MODE_TYPE_DEFAULT, 25200, 640, 656, 752, 800, 0, 480, 490, 492, 525, 0, - V_NHSYNC | V_NVSYNC) },*/ /* 640x480@60Hz */ + DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },*/ /* 640x480@60Hz */ { DRM_MODE("1280x1024", DRM_MODE_TYPE_DEFAULT, 135000, 1280, 1296, 1440, 1688, 0, 1024, 1025, 1028, 1066, 0, - V_PHSYNC | V_PVSYNC) }, /* 1280x1024@75Hz */ + DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 1280x1024@75Hz */ }; static void nv50_kms_connector_fill_modes(struct drm_connector *drm_connector, uint32_t maxX, uint32_t maxY) diff --git a/linux-core/nv50_sor.c b/linux-core/nv50_sor.c index 4d82697e..021a45bf 100644 --- a/linux-core/nv50_sor.c +++ b/linux-core/nv50_sor.c @@ -77,10 +77,10 @@ static int nv50_sor_execute_mode(struct nv50_output *output, bool disconnect) else mode_ctl |= NV50_SOR_MODE_CTRL_CRTC0; - if (desired_mode->flags & V_NHSYNC) + if (desired_mode->flags & DRM_MODE_FLAG_NHSYNC) mode_ctl |= NV50_SOR_MODE_CTRL_NHSYNC; - if (desired_mode->flags & V_NVSYNC) + if (desired_mode->flags & DRM_MODE_FLAG_NVSYNC) mode_ctl |= NV50_SOR_MODE_CTRL_NVSYNC; OUT_MODE(NV50_SOR0_MODE_CTRL + offset, mode_ctl); diff --git a/shared-core/drm.h b/shared-core/drm.h index b64e265d..c7c7f13c 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -1011,20 +1011,21 @@ struct drm_mm_info_arg { #define DRM_MODE_TYPE_DRIVER (1<<6) /* Video mode flags */ -#define V_PHSYNC (1<<0) -#define V_NHSYNC (1<<1) -#define V_PVSYNC (1<<2) -#define V_NVSYNC (1<<3) -#define V_INTERLACE (1<<4) -#define V_DBLSCAN (1<<5) -#define V_CSYNC (1<<6) -#define V_PCSYNC (1<<7) -#define V_NCSYNC (1<<8) -#define V_HSKEW (1<<9) /* hskew provided */ -#define V_BCAST (1<<10) -#define V_PIXMUX (1<<11) -#define V_DBLCLK (1<<12) -#define V_CLKDIV2 (1<<13) +/* bit compatible with the xorg definitions. */ +#define DRM_MODE_FLAG_PHSYNC (1<<0) +#define DRM_MODE_FLAG_NHSYNC (1<<1) +#define DRM_MODE_FLAG_PVSYNC (1<<2) +#define DRM_MODE_FLAG_NVSYNC (1<<3) +#define DRM_MODE_FLAG_INTERLACE (1<<4) +#define DRM_MODE_FLAG_DBLSCAN (1<<5) +#define DRM_MODE_FLAG_CSYNC (1<<6) +#define DRM_MODE_FLAG_PCSYNC (1<<7) +#define DRM_MODE_FLAG_NCSYNC (1<<8) +#define DRM_MODE_FLAG_HSKEW (1<<9) /* hskew provided */ +#define DRM_MODE_FLAG_BCAST (1<<10) +#define DRM_MODE_FLAG_PIXMUX (1<<11) +#define DRM_MODE_FLAG_DBLCLK (1<<12) +#define DRM_MODE_FLAG_CLKDIV2 (1<<13) /* DPMS flags */ #define DPMSModeOn 0 -- cgit v1.2.3 From 6738e7b00bf05529303ed690873495db6d83337c Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Sun, 6 Jul 2008 11:08:49 +0200 Subject: modesetting-101: Rename DPMS modes to avoid compatibility issues with xorg definitions. --- linux-core/drm_crtc.c | 8 ++++---- linux-core/drm_crtc_helper.c | 4 ++-- linux-core/dvo_ch7017.c | 6 +++--- linux-core/dvo_ch7xxx.c | 2 +- linux-core/dvo_ivch.c | 6 +++--- linux-core/dvo_sil164.c | 2 +- linux-core/dvo_tfp410.c | 2 +- linux-core/intel_crt.c | 8 ++++---- linux-core/intel_display.c | 34 +++++++++++++++++----------------- linux-core/intel_dvo.c | 2 +- linux-core/intel_lvds.c | 2 +- linux-core/intel_sdvo.c | 12 ++++++------ linux-core/intel_tv.c | 8 ++++---- linux-core/nv50_dac.c | 8 ++++---- linux-core/nv50_kms_wrapper.c | 4 ++-- linux-core/nv50_sor.c | 2 +- shared-core/drm.h | 9 +++++---- 17 files changed, 60 insertions(+), 59 deletions(-) diff --git a/linux-core/drm_crtc.c b/linux-core/drm_crtc.c index 47885a07..fc8d1fe8 100644 --- a/linux-core/drm_crtc.c +++ b/linux-core/drm_crtc.c @@ -43,10 +43,10 @@ struct drm_prop_enum_list { * Global properties */ static struct drm_prop_enum_list drm_dpms_enum_list[] = -{ { DPMSModeOn, "On" }, - { DPMSModeStandby, "Standby" }, - { DPMSModeSuspend, "Suspend" }, - { DPMSModeOff, "Off" } +{ { DRM_MODE_DPMS_ON, "On" }, + { DRM_MODE_DPMS_STANDBY, "Standby" }, + { DRM_MODE_DPMS_SUSPEND, "Suspend" }, + { DRM_MODE_DPMS_OFF, "Off" } }; char *drm_get_dpms_name(int val) diff --git a/linux-core/drm_crtc_helper.c b/linux-core/drm_crtc_helper.c index d5a9f279..18fc9d98 100644 --- a/linux-core/drm_crtc_helper.c +++ b/linux-core/drm_crtc_helper.c @@ -182,14 +182,14 @@ void drm_helper_disable_unused_functions(struct drm_device *dev) list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { encoder_funcs = encoder->helper_private; if (!encoder->crtc) - (*encoder_funcs->dpms)(encoder, DPMSModeOff); + (*encoder_funcs->dpms)(encoder, DRM_MODE_DPMS_OFF); } list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; crtc->enabled = drm_helper_crtc_in_use(crtc); if (!crtc->enabled) { - crtc_funcs->dpms(crtc, DPMSModeOff); + crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF); crtc->fb = NULL; } } diff --git a/linux-core/dvo_ch7017.c b/linux-core/dvo_ch7017.c index 194a7af1..b10e0388 100644 --- a/linux-core/dvo_ch7017.c +++ b/linux-core/dvo_ch7017.c @@ -327,7 +327,7 @@ static void ch7017_mode_set(struct intel_dvo_device *dvo, lvds_power_down = CH7017_LVDS_POWER_DOWN_DEFAULT_RESERVED | (mode->hdisplay & 0x0700) >> 8; - ch7017_dpms(dvo, DPMSModeOff); + ch7017_dpms(dvo, DRM_MODE_DPMS_OFF); ch7017_write(dvo, CH7017_HORIZONTAL_ACTIVE_PIXEL_INPUT, horizontal_active_pixel_input); ch7017_write(dvo, CH7017_HORIZONTAL_ACTIVE_PIXEL_OUTPUT, @@ -363,7 +363,7 @@ static void ch7017_dpms(struct intel_dvo_device *dvo, int mode) CH7017_DAC3_POWER_DOWN | CH7017_TV_POWER_DOWN_EN); - if (mode == DPMSModeOn) { + if (mode == DRM_MODE_DPMS_ON) { /* Turn on the LVDS */ ch7017_write(dvo, CH7017_LVDS_POWER_DOWN, val & ~CH7017_LVDS_POWER_DOWN_EN); @@ -418,7 +418,7 @@ static void ch7017_restore(struct intel_dvo_device *dvo) struct ch7017_priv *priv = dvo->dev_priv; /* Power down before changing mode */ - ch7017_dpms(dvo, DPMSModeOff); + ch7017_dpms(dvo, DRM_MODE_DPMS_OFF); ch7017_write(dvo, CH7017_HORIZONTAL_ACTIVE_PIXEL_INPUT, priv->save_hapi); ch7017_write(dvo, CH7017_VERTICAL_ACTIVE_LINE_OUTPUT, priv->save_valo); diff --git a/linux-core/dvo_ch7xxx.c b/linux-core/dvo_ch7xxx.c index 1fe9eb0f..ebf54bff 100644 --- a/linux-core/dvo_ch7xxx.c +++ b/linux-core/dvo_ch7xxx.c @@ -301,7 +301,7 @@ static void ch7xxx_mode_set(struct intel_dvo_device *dvo, /* set the CH7xxx power state */ static void ch7xxx_dpms(struct intel_dvo_device *dvo, int mode) { - if (mode == DPMSModeOn) + if (mode == DRM_MODE_DPMS_ON) ch7xxx_writeb(dvo, CH7xxx_PM, CH7xxx_PM_DVIL | CH7xxx_PM_DVIP); else ch7xxx_writeb(dvo, CH7xxx_PM, CH7xxx_PM_FPD); diff --git a/linux-core/dvo_ivch.c b/linux-core/dvo_ivch.c index 7ba00b34..3a29ab6a 100644 --- a/linux-core/dvo_ivch.c +++ b/linux-core/dvo_ivch.c @@ -321,13 +321,13 @@ static void ivch_dpms(struct intel_dvo_device *dvo, int mode) if (!ivch_read(dvo, VR01, &vr01)) return; - if (mode == DPMSModeOn) + if (mode == DRM_MODE_DPMS_ON) backlight = 1; else backlight = 0; ivch_write(dvo, VR80, backlight); - if (mode == DPMSModeOn) + if (mode == DRM_MODE_DPMS_ON) vr01 |= VR01_LCD_ENABLE | VR01_DVO_ENABLE; else vr01 &= ~(VR01_LCD_ENABLE | VR01_DVO_ENABLE); @@ -339,7 +339,7 @@ static void ivch_dpms(struct intel_dvo_device *dvo, int mode) if (!ivch_read(dvo, VR30, &vr30)) break; - if (((vr30 & VR30_PANEL_ON) != 0) == (mode == DPMSModeOn)) + if (((vr30 & VR30_PANEL_ON) != 0) == (mode == DRM_MODE_DPMS_ON)) break; udelay(1000); } diff --git a/linux-core/dvo_sil164.c b/linux-core/dvo_sil164.c index d0fa4913..033a4bb0 100644 --- a/linux-core/dvo_sil164.c +++ b/linux-core/dvo_sil164.c @@ -226,7 +226,7 @@ static void sil164_dpms(struct intel_dvo_device *dvo, int mode) if (ret == false) return; - if (mode == DPMSModeOn) + if (mode == DRM_MODE_DPMS_ON) ch |= SIL164_8_PD; else ch &= ~SIL164_8_PD; diff --git a/linux-core/dvo_tfp410.c b/linux-core/dvo_tfp410.c index c1d1aa96..8e26235c 100644 --- a/linux-core/dvo_tfp410.c +++ b/linux-core/dvo_tfp410.c @@ -248,7 +248,7 @@ static void tfp410_dpms(struct intel_dvo_device *dvo, int mode) if (!tfp410_readb(dvo, TFP410_CTL_1, &ctl1)) return; - if (mode == DPMSModeOn) + if (mode == DRM_MODE_DPMS_ON) ctl1 |= TFP410_CTL_1_PD; else ctl1 &= ~TFP410_CTL_1_PD; diff --git a/linux-core/intel_crt.c b/linux-core/intel_crt.c index 4326aef9..1b2b5b7e 100644 --- a/linux-core/intel_crt.c +++ b/linux-core/intel_crt.c @@ -44,16 +44,16 @@ static void intel_crt_dpms(struct drm_encoder *encoder, int mode) temp &= ~ADPA_DAC_ENABLE; switch(mode) { - case DPMSModeOn: + case DRM_MODE_DPMS_ON: temp |= ADPA_DAC_ENABLE; break; - case DPMSModeStandby: + case DRM_MODE_DPMS_STANDBY: temp |= ADPA_DAC_ENABLE | ADPA_HSYNC_CNTL_DISABLE; break; - case DPMSModeSuspend: + case DRM_MODE_DPMS_SUSPEND: temp |= ADPA_DAC_ENABLE | ADPA_VSYNC_CNTL_DISABLE; break; - case DPMSModeOff: + case DRM_MODE_DPMS_OFF: temp |= ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE; break; } diff --git a/linux-core/intel_display.c b/linux-core/intel_display.c index b82993fc..29aae169 100644 --- a/linux-core/intel_display.c +++ b/linux-core/intel_display.c @@ -468,12 +468,12 @@ static void intel_crtc_dpms(struct drm_crtc *crtc, int mode) bool enabled; /* XXX: When our outputs are all unaware of DPMS modes other than off - * and on, we should map those modes to DPMSModeOff in the CRTC. + * and on, we should map those modes to DRM_MODE_DPMS_OFF in the CRTC. */ switch (mode) { - case DPMSModeOn: - case DPMSModeStandby: - case DPMSModeSuspend: + case DRM_MODE_DPMS_ON: + case DRM_MODE_DPMS_STANDBY: + case DRM_MODE_DPMS_SUSPEND: /* Enable the DPLL */ temp = I915_READ(dpll_reg); if ((temp & DPLL_VCO_ENABLE) == 0) { @@ -509,7 +509,7 @@ static void intel_crtc_dpms(struct drm_crtc *crtc, int mode) /* Give the overlay scaler a chance to enable if it's on this pipe */ //intel_crtc_dpms_video(crtc, TRUE); TODO break; - case DPMSModeOff: + case DRM_MODE_DPMS_OFF: /* Give the overlay scaler a chance to disable if it's on this pipe */ //intel_crtc_dpms_video(crtc, FALSE); TODO @@ -558,7 +558,7 @@ static void intel_crtc_dpms(struct drm_crtc *crtc, int mode) if (!master_priv->sarea_priv) return; - enabled = crtc->enabled && mode != DPMSModeOff; + enabled = crtc->enabled && mode != DRM_MODE_DPMS_OFF; switch (pipe) { case 0: @@ -580,27 +580,27 @@ static void intel_crtc_dpms(struct drm_crtc *crtc, int mode) static void intel_crtc_prepare (struct drm_crtc *crtc) { struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; - crtc_funcs->dpms(crtc, DPMSModeOff); + crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF); } static void intel_crtc_commit (struct drm_crtc *crtc) { struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; - crtc_funcs->dpms(crtc, DPMSModeOn); + crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON); } void intel_encoder_prepare (struct drm_encoder *encoder) { struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private; /* lvds has its own version of prepare see intel_lvds_prepare */ - encoder_funcs->dpms(encoder, DPMSModeOff); + encoder_funcs->dpms(encoder, DRM_MODE_DPMS_OFF); } void intel_encoder_commit (struct drm_encoder *encoder) { struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private; /* lvds has its own version of commit see intel_lvds_commit */ - encoder_funcs->dpms(encoder, DPMSModeOn); + encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON); } static bool intel_crtc_mode_fixup(struct drm_crtc *crtc, @@ -1145,10 +1145,10 @@ struct drm_crtc *intel_get_load_detect_pipe(struct intel_output *intel_output, /* Make sure the crtc and connector are running */ intel_crtc = to_intel_crtc(crtc); *dpms_mode = intel_crtc->dpms_mode; - if (intel_crtc->dpms_mode != DPMSModeOn) { + if (intel_crtc->dpms_mode != DRM_MODE_DPMS_ON) { crtc_funcs = crtc->helper_private; - crtc_funcs->dpms(crtc, DPMSModeOn); - encoder_funcs->dpms(encoder, DPMSModeOn); + crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON); + encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON); } return crtc; } @@ -1184,9 +1184,9 @@ struct drm_crtc *intel_get_load_detect_pipe(struct intel_output *intel_output, mode = &load_detect_mode; drm_crtc_helper_set_mode(crtc, mode, 0, 0); } else { - if (intel_crtc->dpms_mode != DPMSModeOn) { + if (intel_crtc->dpms_mode != DRM_MODE_DPMS_ON) { crtc_funcs = crtc->helper_private; - crtc_funcs->dpms(crtc, DPMSModeOn); + crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON); } /* Add this connector to the crtc */ @@ -1215,7 +1215,7 @@ void intel_release_load_detect_pipe(struct intel_output *intel_output, int dpms_ } /* Switch crtc and output back off if necessary */ - if (crtc->enabled && dpms_mode != DPMSModeOn) { + if (crtc->enabled && dpms_mode != DRM_MODE_DPMS_ON) { if (encoder->crtc == crtc) encoder_funcs->dpms(encoder, dpms_mode); crtc_funcs->dpms(crtc, dpms_mode); @@ -1378,7 +1378,7 @@ void intel_crtc_init(struct drm_device *dev, int pipe) } intel_crtc->cursor_addr = 0; - intel_crtc->dpms_mode = DPMSModeOff; + intel_crtc->dpms_mode = DRM_MODE_DPMS_OFF; drm_crtc_helper_add(&intel_crtc->base, &intel_helper_funcs); intel_crtc->mode_set.crtc = &intel_crtc->base; diff --git a/linux-core/intel_dvo.c b/linux-core/intel_dvo.c index a3842a91..39ec65d2 100644 --- a/linux-core/intel_dvo.c +++ b/linux-core/intel_dvo.c @@ -93,7 +93,7 @@ static void intel_dvo_dpms(struct drm_encoder *encoder, int mode) u32 dvo_reg = dvo->dvo_reg; u32 temp = I915_READ(dvo_reg); - if (mode == DPMSModeOn) { + if (mode == DRM_MODE_DPMS_ON) { I915_WRITE(dvo_reg, temp | DVO_ENABLE); I915_READ(dvo_reg); dvo->dev_ops->dpms(dvo, mode); diff --git a/linux-core/intel_lvds.c b/linux-core/intel_lvds.c index 04e110e4..06b99867 100644 --- a/linux-core/intel_lvds.c +++ b/linux-core/intel_lvds.c @@ -93,7 +93,7 @@ static void intel_lvds_dpms(struct drm_encoder *encoder, int mode) { struct drm_device *dev = encoder->dev; - if (mode == DPMSModeOn) + if (mode == DRM_MODE_DPMS_ON) intel_lvds_set_power(dev, true); else intel_lvds_set_power(dev, false); diff --git a/linux-core/intel_sdvo.c b/linux-core/intel_sdvo.c index 2143bdc0..6624bde2 100644 --- a/linux-core/intel_sdvo.c +++ b/linux-core/intel_sdvo.c @@ -363,16 +363,16 @@ static bool intel_sdvo_set_encoder_power_state(struct intel_output *intel_output u8 status, state = SDVO_ENCODER_STATE_ON; switch (mode) { - case DPMSModeOn: + case DRM_MODE_DPMS_ON: state = SDVO_ENCODER_STATE_ON; break; - case DPMSModeStandby: + case DRM_MODE_DPMS_STANDBY: state = SDVO_ENCODER_STATE_STANDBY; break; - case DPMSModeSuspend: + case DRM_MODE_DPMS_SUSPEND: state = SDVO_ENCODER_STATE_SUSPEND; break; - case DPMSModeOff: + case DRM_MODE_DPMS_OFF: state = SDVO_ENCODER_STATE_OFF; break; } @@ -691,12 +691,12 @@ static void intel_sdvo_dpms(struct drm_encoder *encoder, int mode) struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; u32 temp; - if (mode != DPMSModeOn) { + if (mode != DRM_MODE_DPMS_ON) { intel_sdvo_set_active_outputs(intel_output, 0); if (0) intel_sdvo_set_encoder_power_state(intel_output, mode); - if (mode == DPMSModeOff) { + if (mode == DRM_MODE_DPMS_OFF) { temp = I915_READ(sdvo_priv->output_device); if ((temp & SDVO_ENABLE) != 0) { intel_sdvo_write_sdvox(intel_output, temp & ~SDVO_ENABLE); diff --git a/linux-core/intel_tv.c b/linux-core/intel_tv.c index f564fa91..389487bb 100644 --- a/linux-core/intel_tv.c +++ b/linux-core/intel_tv.c @@ -904,12 +904,12 @@ intel_tv_dpms(struct drm_encoder *encoder, int mode) struct drm_i915_private *dev_priv = dev->dev_private; switch(mode) { - case DPMSModeOn: + case DRM_MODE_DPMS_ON: I915_WRITE(TV_CTL, I915_READ(TV_CTL) | TV_ENC_ENABLE); break; - case DPMSModeStandby: - case DPMSModeSuspend: - case DPMSModeOff: + case DRM_MODE_DPMS_STANDBY: + case DRM_MODE_DPMS_SUSPEND: + case DRM_MODE_DPMS_OFF: I915_WRITE(TV_CTL, I915_READ(TV_CTL) & ~TV_ENC_ENABLE); break; } diff --git a/linux-core/nv50_dac.c b/linux-core/nv50_dac.c index ce01d573..ca4bb5e1 100644 --- a/linux-core/nv50_dac.c +++ b/linux-core/nv50_dac.c @@ -109,17 +109,17 @@ static int nv50_dac_set_power_mode(struct nv50_output *output, int mode) val = NV_READ(NV50_PDISPLAY_DAC_REGS_DPMS_CTRL(or)) & ~0x7F; - if (mode != DPMSModeOn) + if (mode != DRM_MODE_DPMS_ON) val |= NV50_PDISPLAY_DAC_REGS_DPMS_CTRL_BLANKED; switch (mode) { - case DPMSModeStandby: + case DRM_MODE_DPMS_STANDBY: val |= NV50_PDISPLAY_DAC_REGS_DPMS_CTRL_HSYNC_OFF; break; - case DPMSModeSuspend: + case DRM_MODE_DPMS_SUSPEND: val |= NV50_PDISPLAY_DAC_REGS_DPMS_CTRL_VSYNC_OFF; break; - case DPMSModeOff: + case DRM_MODE_DPMS_OFF: val |= NV50_PDISPLAY_DAC_REGS_DPMS_CTRL_OFF; val |= NV50_PDISPLAY_DAC_REGS_DPMS_CTRL_HSYNC_OFF; val |= NV50_PDISPLAY_DAC_REGS_DPMS_CTRL_VSYNC_OFF; diff --git a/linux-core/nv50_kms_wrapper.c b/linux-core/nv50_kms_wrapper.c index b7ba7b00..8f71e649 100644 --- a/linux-core/nv50_kms_wrapper.c +++ b/linux-core/nv50_kms_wrapper.c @@ -681,7 +681,7 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) if (output->crtc != crtc) continue; - rval = output->set_power_mode(output, DPMSModeOn); + rval = output->set_power_mode(output, DRM_MODE_DPMS_ON); if (rval != 0) { DRM_ERROR("output set power mode failed\n"); goto out; @@ -698,7 +698,7 @@ int nv50_kms_crtc_set_config(struct drm_mode_set *set) rval = drm_connector_property_set_value(drm_connector, dev->mode_config.dpms_property, - DPMSModeOn); + DRM_MODE_DPMS_ON); if (rval != 0) { DRM_ERROR("failed to update dpms state\n"); goto out; diff --git a/linux-core/nv50_sor.c b/linux-core/nv50_sor.c index 021a45bf..41116923 100644 --- a/linux-core/nv50_sor.c +++ b/linux-core/nv50_sor.c @@ -127,7 +127,7 @@ static int nv50_sor_set_power_mode(struct nv50_output *output, int mode) val = NV_READ(NV50_PDISPLAY_SOR_REGS_DPMS_CTRL(or)); - if (mode == DPMSModeOn) + if (mode == DRM_MODE_DPMS_ON) val |= NV50_PDISPLAY_SOR_REGS_DPMS_CTRL_ON; else val &= ~NV50_PDISPLAY_SOR_REGS_DPMS_CTRL_ON; diff --git a/shared-core/drm.h b/shared-core/drm.h index c7c7f13c..2e4d2a94 100644 --- a/shared-core/drm.h +++ b/shared-core/drm.h @@ -1028,10 +1028,11 @@ struct drm_mm_info_arg { #define DRM_MODE_FLAG_CLKDIV2 (1<<13) /* DPMS flags */ -#define DPMSModeOn 0 -#define DPMSModeStandby 1 -#define DPMSModeSuspend 2 -#define DPMSModeOff 3 +/* bit compatible with the xorg definitions. */ +#define DRM_MODE_DPMS_ON 0 +#define DRM_MODE_DPMS_STANDBY 1 +#define DRM_MODE_DPMS_SUSPEND 2 +#define DRM_MODE_DPMS_OFF 3 struct drm_mode_modeinfo { unsigned int clock; -- cgit v1.2.3 From 88f668a0b91a9961d599c46392f3acbb5573ed9d Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Sun, 6 Jul 2008 11:23:17 +0200 Subject: NV50: fix minor bug in fbcon crtc selection --- linux-core/nv50_fbcon.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/linux-core/nv50_fbcon.c b/linux-core/nv50_fbcon.c index 80597a76..3dd73062 100644 --- a/linux-core/nv50_fbcon.c +++ b/linux-core/nv50_fbcon.c @@ -290,13 +290,13 @@ static int nv50_fbcon_set_par(struct fb_info *info) if (drm_encoder->crtc) { list_for_each_entry(drm_crtc, &dev->mode_config.crtc_list, head) { - crtc_count++; - if (drm_crtc == drm_encoder->crtc) { if (!crtc_used[crtc_count]) /* still available? */ mode_set.crtc = drm_crtc; break; } + + crtc_count++; } } } -- cgit v1.2.3 From d5d3f31b108c8514a820bb50a5736ba06fc33275 Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Sun, 6 Jul 2008 12:51:43 +0200 Subject: NV50: init gamma storage --- linux-core/nv50_kms_wrapper.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/linux-core/nv50_kms_wrapper.c b/linux-core/nv50_kms_wrapper.c index 8f71e649..a7966e9a 100644 --- a/linux-core/nv50_kms_wrapper.c +++ b/linux-core/nv50_kms_wrapper.c @@ -762,6 +762,9 @@ static int nv50_kms_crtcs_init(struct drm_device *dev) struct drm_crtc *drm_crtc = to_nv50_kms_crtc(crtc); drm_crtc_init(dev, drm_crtc, &nv50_kms_crtc_funcs); + + /* init lut storage */ + drm_mode_crtc_set_gamma_size(drm_crtc, 256); } return 0; -- cgit v1.2.3 From 0b7d9a97bd2383fe4382fc1b1b266542020f0c4e Mon Sep 17 00:00:00 2001 From: Alan Hourihane Date: Mon, 7 Jul 2008 15:11:48 +0100 Subject: Synchronize the DDC EDID read to it's fb_ddc.c counterpart --- linux-core/drm_edid.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/linux-core/drm_edid.c b/linux-core/drm_edid.c index a3d9861f..07894720 100644 --- a/linux-core/drm_edid.c +++ b/linux-core/drm_edid.c @@ -595,21 +595,13 @@ static unsigned char *drm_ddc_read(struct i2c_adapter *adapter) unsigned char *edid = NULL; int i, j; - /* - * Startup the bus: - * Set clock line high (but give it time to come up) - * Then set clock & data low - */ algo_data->setscl(algo_data->data, 1); - udelay(550); /* startup delay */ - algo_data->setscl(algo_data->data, 0); - algo_data->setsda(algo_data->data, 0); for (i = 0; i < 3; i++) { /* For some old monitors we need the * following process to initialize/stop DDC */ - algo_data->setsda(algo_data->data, 0); + algo_data->setsda(algo_data->data, 1); msleep(13); algo_data->setscl(algo_data->data, 1); @@ -644,6 +636,7 @@ static unsigned char *drm_ddc_read(struct i2c_adapter *adapter) algo_data->setsda(algo_data->data, 1); msleep(15); algo_data->setscl(algo_data->data, 0); + algo_data->setsda(algo_data->data, 0); if (edid) break; } -- cgit v1.2.3