diff options
Diffstat (limited to 'drivers')
312 files changed, 12526 insertions, 5516 deletions
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index e9a8026..eead3f5 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -164,7 +164,7 @@ static void lapic_timer_check_state(int state, struct acpi_processor *pr, if (cpu_has(&cpu_data(pr->id), X86_FEATURE_ARAT)) return; - if (boot_cpu_has(X86_FEATURE_AMDC1E)) + if (c1e_detected) type = ACPI_STATE_C1; /* diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index aa85a98..8fae6af 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -187,6 +187,15 @@ config ATA_PIIX If unsure, say N. +config SATA_DWC + tristate "DesignWare Cores SATA support" + depends on 460EX + help + This option enables support for the on-chip SATA controller of the + AppliedMicro processor 460EX. + + If unsure, say N. + config SATA_MV tristate "Marvell SATA support" help @@ -796,6 +805,15 @@ config PATA_RZ1000 If unsure, say N. +config PATA_SAMSUNG_CF + tristate "Samsung SoC PATA support" + depends on SAMSUNG_DEV_IDE + help + This option enables basic support for Samsung's S3C/S5P board + PATA controllers via the new ATA layer + + If unsure, say N. + config PATA_WINBOND_VLB tristate "Winbond W83759A VLB PATA support (Experimental)" depends on ISA && EXPERIMENTAL diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile index 7ef89d7..6540632 100644 --- a/drivers/ata/Makefile +++ b/drivers/ata/Makefile @@ -7,6 +7,7 @@ obj-$(CONFIG_SATA_AHCI_PLATFORM) += ahci_platform.o libahci.o obj-$(CONFIG_SATA_FSL) += sata_fsl.o obj-$(CONFIG_SATA_INIC162X) += sata_inic162x.o obj-$(CONFIG_SATA_SIL24) += sata_sil24.o +obj-$(CONFIG_SATA_DWC) += sata_dwc_460ex.o # SFF w/ custom DMA obj-$(CONFIG_PDC_ADMA) += pdc_adma.o @@ -87,6 +88,7 @@ obj-$(CONFIG_PATA_OF_PLATFORM) += pata_of_platform.o obj-$(CONFIG_PATA_QDI) += pata_qdi.o obj-$(CONFIG_PATA_RB532) += pata_rb532_cf.o obj-$(CONFIG_PATA_RZ1000) += pata_rz1000.o +obj-$(CONFIG_PATA_SAMSUNG_CF) += pata_samsung_cf.o obj-$(CONFIG_PATA_WINBOND_VLB) += pata_winbond.o # Should be last but two libata driver diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index f252253..fe75d8b 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -1042,7 +1042,7 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) VPRINTK("ENTER\n"); - WARN_ON(ATA_MAX_QUEUE > AHCI_MAX_CMDS); + WARN_ON((int)ATA_MAX_QUEUE > AHCI_MAX_CMDS); if (!printed_version++) dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c index 5e11b16..4e97f33 100644 --- a/drivers/ata/ahci_platform.c +++ b/drivers/ata/ahci_platform.c @@ -54,19 +54,13 @@ static int __init ahci_probe(struct platform_device *pdev) return -EINVAL; } - if (pdata && pdata->init) { - rc = pdata->init(dev); - if (rc) - return rc; - } - if (pdata && pdata->ata_port_info) pi = *pdata->ata_port_info; hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL); if (!hpriv) { - rc = -ENOMEM; - goto err0; + dev_err(dev, "can't alloc ahci_host_priv\n"); + return -ENOMEM; } hpriv->flags |= (unsigned long)pi.private_data; @@ -74,8 +68,19 @@ static int __init ahci_probe(struct platform_device *pdev) hpriv->mmio = devm_ioremap(dev, mem->start, resource_size(mem)); if (!hpriv->mmio) { dev_err(dev, "can't map %pR\n", mem); - rc = -ENOMEM; - goto err0; + return -ENOMEM; + } + + /* + * Some platforms might need to prepare for mmio region access, + * which could be done in the following init call. So, the mmio + * region shouldn't be accessed before init (if provided) has + * returned successfully. + */ + if (pdata && pdata->init) { + rc = pdata->init(dev, hpriv->mmio); + if (rc) + return rc; } ahci_save_initial_config(dev, hpriv, @@ -166,7 +171,6 @@ static int __devexit ahci_remove(struct platform_device *pdev) } static struct platform_driver ahci_driver = { - .probe = ahci_probe, .remove = __devexit_p(ahci_remove), .driver = { .name = "ahci", diff --git a/drivers/ata/ata_generic.c b/drivers/ata/ata_generic.c index 7107a69..cc5f772 100644 --- a/drivers/ata/ata_generic.c +++ b/drivers/ata/ata_generic.c @@ -54,7 +54,6 @@ static int generic_set_mode(struct ata_link *link, struct ata_device **unused) const struct pci_device_id *id = ap->host->private_data; int dma_enabled = 0; struct ata_device *dev; - struct pci_dev *pdev = to_pci_dev(ap->host->dev); if (id->driver_data & ATA_GEN_FORCE_DMA) { dma_enabled = 0xff; @@ -63,9 +62,6 @@ static int generic_set_mode(struct ata_link *link, struct ata_device **unused) dma_enabled = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS); } - if (pdev->vendor == PCI_VENDOR_ID_CENATEK) - dma_enabled = 0xFF; - ata_for_each_dev(dev, link, ENABLED) { /* We don't really care */ dev->pio_mode = XFER_PIO_0; diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c index 7409f98..3971bc0 100644 --- a/drivers/ata/ata_piix.c +++ b/drivers/ata/ata_piix.c @@ -158,6 +158,7 @@ struct piix_map_db { struct piix_host_priv { const int *map; u32 saved_iocfg; + spinlock_t sidpr_lock; /* FIXME: remove once locking in EH is fixed */ void __iomem *sidpr; }; @@ -951,12 +952,15 @@ static int piix_sidpr_scr_read(struct ata_link *link, unsigned int reg, u32 *val) { struct piix_host_priv *hpriv = link->ap->host->private_data; + unsigned long flags; if (reg >= ARRAY_SIZE(piix_sidx_map)) return -EINVAL; + spin_lock_irqsave(&hpriv->sidpr_lock, flags); piix_sidpr_sel(link, reg); *val = ioread32(hpriv->sidpr + PIIX_SIDPR_DATA); + spin_unlock_irqrestore(&hpriv->sidpr_lock, flags); return 0; } @@ -964,12 +968,15 @@ static int piix_sidpr_scr_write(struct ata_link *link, unsigned int reg, u32 val) { struct piix_host_priv *hpriv = link->ap->host->private_data; + unsigned long flags; if (reg >= ARRAY_SIZE(piix_sidx_map)) return -EINVAL; + spin_lock_irqsave(&hpriv->sidpr_lock, flags); piix_sidpr_sel(link, reg); iowrite32(val, hpriv->sidpr + PIIX_SIDPR_DATA); + spin_unlock_irqrestore(&hpriv->sidpr_lock, flags); return 0; } @@ -1566,6 +1573,7 @@ static int __devinit piix_init_one(struct pci_dev *pdev, hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL); if (!hpriv) return -ENOMEM; + spin_lock_init(&hpriv->sidpr_lock); /* Save IOCFG, this will be used for cable detection, quirk * detection and restoration on detach. This is necessary diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index ddf8e48..a0a4d69 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -4167,15 +4167,13 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { { "WDC AC23200L", "21.10N21", ATA_HORKAGE_NODMA }, { "Compaq CRD-8241B", NULL, ATA_HORKAGE_NODMA }, { "CRD-8400B", NULL, ATA_HORKAGE_NODMA }, - { "CRD-8480B", NULL, ATA_HORKAGE_NODMA }, - { "CRD-8482B", NULL, ATA_HORKAGE_NODMA }, + { "CRD-848[02]B", NULL, ATA_HORKAGE_NODMA }, { "CRD-84", NULL, ATA_HORKAGE_NODMA }, { "SanDisk SDP3B", NULL, ATA_HORKAGE_NODMA }, { "SanDisk SDP3B-64", NULL, ATA_HORKAGE_NODMA }, { "SANYO CD-ROM CRD", NULL, ATA_HORKAGE_NODMA }, { "HITACHI CDR-8", NULL, ATA_HORKAGE_NODMA }, - { "HITACHI CDR-8335", NULL, ATA_HORKAGE_NODMA }, - { "HITACHI CDR-8435", NULL, ATA_HORKAGE_NODMA }, + { "HITACHI CDR-8[34]35",NULL, ATA_HORKAGE_NODMA }, { "Toshiba CD-ROM XM-6202B", NULL, ATA_HORKAGE_NODMA }, { "TOSHIBA CD-ROM XM-1702BC", NULL, ATA_HORKAGE_NODMA }, { "CD-532E-A", NULL, ATA_HORKAGE_NODMA }, @@ -4211,70 +4209,16 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { { "OCZ CORE_SSD", "02.10104", ATA_HORKAGE_NONCQ }, /* Seagate NCQ + FLUSH CACHE firmware bug */ - { "ST31500341AS", "SD15", ATA_HORKAGE_NONCQ | - ATA_HORKAGE_FIRMWARE_WARN }, - { "ST31500341AS", "SD16", ATA_HORKAGE_NONCQ | - ATA_HORKAGE_FIRMWARE_WARN }, - { "ST31500341AS", "SD17", ATA_HORKAGE_NONCQ | - ATA_HORKAGE_FIRMWARE_WARN }, - { "ST31500341AS", "SD18", ATA_HORKAGE_NONCQ | - ATA_HORKAGE_FIRMWARE_WARN }, - { "ST31500341AS", "SD19", ATA_HORKAGE_NONCQ | + { "ST31500341AS", "SD1[5-9]", ATA_HORKAGE_NONCQ | ATA_HORKAGE_FIRMWARE_WARN }, - { "ST31000333AS", "SD15", ATA_HORKAGE_NONCQ | - ATA_HORKAGE_FIRMWARE_WARN }, - { "ST31000333AS", "SD16", ATA_HORKAGE_NONCQ | - ATA_HORKAGE_FIRMWARE_WARN }, - { "ST31000333AS", "SD17", ATA_HORKAGE_NONCQ | - ATA_HORKAGE_FIRMWARE_WARN }, - { "ST31000333AS", "SD18", ATA_HORKAGE_NONCQ | - ATA_HORKAGE_FIRMWARE_WARN }, - { "ST31000333AS", "SD19", ATA_HORKAGE_NONCQ | + { "ST31000333AS", "SD1[5-9]", ATA_HORKAGE_NONCQ | ATA_HORKAGE_FIRMWARE_WARN }, - { "ST3640623AS", "SD15", ATA_HORKAGE_NONCQ | - ATA_HORKAGE_FIRMWARE_WARN }, - { "ST3640623AS", "SD16", ATA_HORKAGE_NONCQ | - ATA_HORKAGE_FIRMWARE_WARN }, - { "ST3640623AS", "SD17", ATA_HORKAGE_NONCQ | - ATA_HORKAGE_FIRMWARE_WARN }, - { "ST3640623AS", "SD18", ATA_HORKAGE_NONCQ | - ATA_HORKAGE_FIRMWARE_WARN }, - { "ST3640623AS", "SD19", ATA_HORKAGE_NONCQ | + { "ST3640[36]23AS", "SD1[5-9]", ATA_HORKAGE_NONCQ | ATA_HORKAGE_FIRMWARE_WARN }, - { "ST3640323AS", "SD15", ATA_HORKAGE_NONCQ | - ATA_HORKAGE_FIRMWARE_WARN }, - { "ST3640323AS", "SD16", ATA_HORKAGE_NONCQ | - ATA_HORKAGE_FIRMWARE_WARN }, - { "ST3640323AS", "SD17", ATA_HORKAGE_NONCQ | - ATA_HORKAGE_FIRMWARE_WARN }, - { "ST3640323AS", "SD18", ATA_HORKAGE_NONCQ | - ATA_HORKAGE_FIRMWARE_WARN }, - { "ST3640323AS", "SD19", ATA_HORKAGE_NONCQ | - ATA_HORKAGE_FIRMWARE_WARN }, - - { "ST3320813AS", "SD15", ATA_HORKAGE_NONCQ | - ATA_HORKAGE_FIRMWARE_WARN }, - { "ST3320813AS", "SD16", ATA_HORKAGE_NONCQ | - ATA_HORKAGE_FIRMWARE_WARN }, - { "ST3320813AS", "SD17", ATA_HORKAGE_NONCQ | - ATA_HORKAGE_FIRMWARE_WARN }, - { "ST3320813AS", "SD18", ATA_HORKAGE_NONCQ | - ATA_HORKAGE_FIRMWARE_WARN }, - { "ST3320813AS", "SD19", ATA_HORKAGE_NONCQ | - ATA_HORKAGE_FIRMWARE_WARN }, - - { "ST3320613AS", "SD15", ATA_HORKAGE_NONCQ | - ATA_HORKAGE_FIRMWARE_WARN }, - { "ST3320613AS", "SD16", ATA_HORKAGE_NONCQ | - ATA_HORKAGE_FIRMWARE_WARN }, - { "ST3320613AS", "SD17", ATA_HORKAGE_NONCQ | - ATA_HORKAGE_FIRMWARE_WARN }, - { "ST3320613AS", "SD18", ATA_HORKAGE_NONCQ | - ATA_HORKAGE_FIRMWARE_WARN }, - { "ST3320613AS", "SD19", ATA_HORKAGE_NONCQ | + { "ST3320[68]13AS", "SD1[5-9]", ATA_HORKAGE_NONCQ | ATA_HORKAGE_FIRMWARE_WARN }, /* Blacklist entries taken from Silicon Image 3124/3132 @@ -4303,12 +4247,7 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { /* Devices which get the IVB wrong */ { "QUANTUM FIREBALLlct10 05", "A03.0900", ATA_HORKAGE_IVB, }, /* Maybe we should just blacklist TSSTcorp... */ - { "TSSTcorp CDDVDW SH-S202H", "SB00", ATA_HORKAGE_IVB, }, - { "TSSTcorp CDDVDW SH-S202H", "SB01", ATA_HORKAGE_IVB, }, - { "TSSTcorp CDDVDW SH-S202J", "SB00", ATA_HORKAGE_IVB, }, - { "TSSTcorp CDDVDW SH-S202J", "SB01", ATA_HORKAGE_IVB, }, - { "TSSTcorp CDDVDW SH-S202N", "SB00", ATA_HORKAGE_IVB, }, - { "TSSTcorp CDDVDW SH-S202N", "SB01", ATA_HORKAGE_IVB, }, + { "TSSTcorp CDDVDW SH-S202[HJN]", "SB0[01]", ATA_HORKAGE_IVB, }, /* Devices that do not need bridging limits applied */ { "MTRON MSP-SATA*", NULL, ATA_HORKAGE_BRIDGE_OK, }, @@ -4326,29 +4265,73 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { { } }; -static int strn_pattern_cmp(const char *patt, const char *name, int wildchar) +/** + * glob_match - match a text string against a glob-style pattern + * @text: the string to be examined + * @pattern: the glob-style pattern to be matched against + * + * Either/both of text and pattern can be empty strings. + * + * Match text against a glob-style pattern, with wildcards and simple sets: + * + * ? matches any single character. + * * matches any run of characters. + * [xyz] matches a single character from the set: x, y, or z. + * [a-d] matches a single character from the range: a, b, c, or d. + * [a-d0-9] matches a single character from either range. + * + * The special characters ?, [, -, or *, can be matched using a set, eg. [*] + * Behaviour with malformed patterns is undefined, though generally reasonable. + * + * Example patterns: "SD1?", "SD1[0-5]", "*R0", SD*1?[012]*xx" + * + * This function uses one level of recursion per '*' in pattern. + * Since it calls _nothing_ else, and has _no_ explicit local variables, + * this will not cause stack problems for any reasonable use here. + * + * RETURNS: + * 0 on match, 1 otherwise. + */ +static int glob_match (const char *text, const char *pattern) { - const char *p; - int len; - - /* - * check for trailing wildcard: *\0 - */ - p = strchr(patt, wildchar); - if (p && ((*(p + 1)) == 0)) - len = p - patt; - else { - len = strlen(name); - if (!len) { - if (!*patt) - return 0; - return -1; + do { + /* Match single character or a '?' wildcard */ + if (*text == *pattern || *pattern == '?') { + if (!*pattern++) + return 0; /* End of both strings: match */ + } else { + /* Match single char against a '[' bracketed ']' pattern set */ + if (!*text || *pattern != '[') + break; /* Not a pattern set */ + while (*++pattern && *pattern != ']' && *text != *pattern) { + if (*pattern == '-' && *(pattern - 1) != '[') + if (*text > *(pattern - 1) && *text < *(pattern + 1)) { + ++pattern; + break; + } + } + if (!*pattern || *pattern == ']') + return 1; /* No match */ + while (*pattern && *pattern++ != ']'); + } + } while (*++text && *pattern); + + /* Match any run of chars against a '*' wildcard */ + if (*pattern == '*') { + if (!*++pattern) + return 0; /* Match: avoid recursion at end of pattern */ + /* Loop to handle additional pattern chars after the wildcard */ + while (*text) { + if (glob_match(text, pattern) == 0) + return 0; /* Remainder matched */ + ++text; /* Absorb (match) this char and try again */ } } - - return strncmp(patt, name, len); + if (!*text && !*pattern) + return 0; /* End of both strings: match */ + return 1; /* No match */ } - + static unsigned long ata_dev_blacklisted(const struct ata_device *dev) { unsigned char model_num[ATA_ID_PROD_LEN + 1]; @@ -4359,10 +4342,10 @@ static unsigned long ata_dev_blacklisted(const struct ata_device *dev) ata_id_c_string(dev->id, model_rev, ATA_ID_FW_REV, sizeof(model_rev)); while (ad->model_num) { - if (!strn_pattern_cmp(ad->model_num, model_num, '*')) { + if (!glob_match(model_num, ad->model_num)) { if (ad->model_rev == NULL) return ad->horkage; - if (!strn_pattern_cmp(ad->model_rev, model_rev, '*')) + if (!glob_match(model_rev, ad->model_rev)) return ad->horkage; } ad++; diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index f77a673..697474b 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -2214,6 +2214,7 @@ const char *ata_get_cmd_descript(u8 command) { ATA_CMD_SMART, "SMART" }, { ATA_CMD_MEDIA_LOCK, "DOOR LOCK" }, { ATA_CMD_MEDIA_UNLOCK, "DOOR UNLOCK" }, + { ATA_CMD_DSM, "DATA SET MANAGEMENT" }, { ATA_CMD_CHK_MED_CRD_TYP, "CHECK MEDIA CARD TYPE" }, { ATA_CMD_CFA_REQ_EXT_ERR, "CFA REQUEST EXTENDED ERROR" }, { ATA_CMD_CFA_WRITE_NE, "CFA WRITE SECTORS WITHOUT ERASE" }, diff --git a/drivers/ata/pata_samsung_cf.c b/drivers/ata/pata_samsung_cf.c new file mode 100644 index 0000000..6f9cfb2 --- /dev/null +++ b/drivers/ata/pata_samsung_cf.c @@ -0,0 +1,683 @@ +/* + * Copyright (c) 2010 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * PATA driver for Samsung SoCs. + * Supports CF Interface in True IDE mode. Currently only PIO mode has been + * implemented; UDMA support has to be added. + * + * Based on: + * PATA driver for AT91SAM9260 Static Memory Controller + * PATA driver for Toshiba SCC controller + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. +*/ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/clk.h> +#include <linux/libata.h> +#include <linux/platform_device.h> +#include <linux/slab.h> + +#include <plat/ata.h> +#include <plat/regs-ata.h> + +#define DRV_NAME "pata_samsung_cf" +#define DRV_VERSION "0.1" + +enum s3c_cpu_type { + TYPE_S3C64XX, + TYPE_S5PC100, + TYPE_S5PV210, +}; + +/* + * struct s3c_ide_info - S3C PATA instance. + * @clk: The clock resource for this controller. + * @ide_addr: The area mapped for the hardware registers. + * @sfr_addr: The area mapped for the special function registers. + * @irq: The IRQ number we are using. + * @cpu_type: The exact type of this controller. + * @fifo_status_reg: The ATA_FIFO_STATUS register offset. + */ +struct s3c_ide_info { + struct clk *clk; + void __iomem *ide_addr; + void __iomem *sfr_addr; + unsigned int irq; + enum s3c_cpu_type cpu_type; + unsigned int fifo_status_reg; +}; + +static void pata_s3c_set_endian(void __iomem *s3c_ide_regbase, u8 mode) +{ + u32 reg = readl(s3c_ide_regbase + S3C_ATA_CFG); + reg = mode ? (reg & ~S3C_ATA_CFG_SWAP) : (reg | S3C_ATA_CFG_SWAP); + writel(reg, s3c_ide_regbase + S3C_ATA_CFG); +} + +static void pata_s3c_cfg_mode(void __iomem *s3c_ide_sfrbase) +{ + /* Select true-ide as the internal operating mode */ + writel(readl(s3c_ide_sfrbase + S3C_CFATA_MUX) | S3C_CFATA_MUX_TRUEIDE, + s3c_ide_sfrbase + S3C_CFATA_MUX); +} + +static unsigned long +pata_s3c_setup_timing(struct s3c_ide_info *info, const struct ata_timing *ata) +{ + int t1 = ata->setup; + int t2 = ata->act8b; + int t2i = ata->rec8b; + ulong piotime; + + piotime = ((t2i & 0xff) << 12) | ((t2 & 0xff) << 4) | (t1 & 0xf); + + return piotime; +} + +static void pata_s3c_set_piomode(struct ata_port *ap, struct ata_device *adev) +{ + struct s3c_ide_info *info = ap->host->private_data; + struct ata_timing timing; + int cycle_time; + ulong ata_cfg = readl(info->ide_addr + S3C_ATA_CFG); + ulong piotime; + + /* Enables IORDY if mode requires it */ + if (ata_pio_need_iordy(adev)) + ata_cfg |= S3C_ATA_CFG_IORDYEN; + else + ata_cfg &= ~S3C_ATA_CFG_IORDYEN; + + cycle_time = (int)(1000000000UL / clk_get_rate(info->clk)); + + ata_timing_compute(adev, adev->pio_mode, &timing, + cycle_time * 1000, 0); + + piotime = pata_s3c_setup_timing(info, &timing); + + writel(ata_cfg, info->ide_addr + S3C_ATA_CFG); + writel(piotime, info->ide_addr + S3C_ATA_PIO_TIME); +} + +/* + * Waits until the IDE controller is able to perform next read/write + * operation to the disk. Needed for 64XX series boards only. + */ +static int wait_for_host_ready(struct s3c_ide_info *info) +{ + ulong timeout; + void __iomem *fifo_reg = info->ide_addr + info->fifo_status_reg; + + /* wait for maximum of 20 msec */ + timeout = jiffies + msecs_to_jiffies(20); + while (time_before(jiffies, timeout)) { + if ((readl(fifo_reg) >> 28) == 0) + return 0; + } + return -EBUSY; +} + +/* + * Writes to one of the task file registers. + */ +static void ata_outb(struct ata_host *host, u8 addr, void __iomem *reg) +{ + struct s3c_ide_info *info = host->private_data; + + wait_for_host_ready(info); + writeb(addr, reg); +} + +/* + * Reads from one of the task file registers. + */ +static u8 ata_inb(struct ata_host *host, void __iomem *reg) +{ + struct s3c_ide_info *info = host->private_data; + u8 temp; + + wait_for_host_ready(info); + (void) readb(reg); + wait_for_host_ready(info); + temp = readb(info->ide_addr + S3C_ATA_PIO_RDATA); + return temp; +} + +/* + * pata_s3c_tf_load - send taskfile registers to host controller + */ +static void pata_s3c_tf_load(struct ata_port *ap, + const struct ata_taskfile *tf) +{ + struct ata_ioports *ioaddr = &ap->ioaddr; + unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR; + + if (tf->ctl != ap->last_ctl) { + ata_outb(ap->host, tf->ctl, ioaddr->ctl_addr); + ap->last_ctl = tf->ctl; + ata_wait_idle(ap); + } + + if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) { + ata_outb(ap->host, tf->hob_feature, ioaddr->feature_addr); + ata_outb(ap->host, tf->hob_nsect, ioaddr->nsect_addr); + ata_outb(ap->host, tf->hob_lbal, ioaddr->lbal_addr); + ata_outb(ap->host, tf->hob_lbam, ioaddr->lbam_addr); + ata_outb(ap->host, tf->hob_lbah, ioaddr->lbah_addr); + } + + if (is_addr) { + ata_outb(ap->host, tf->feature, ioaddr->feature_addr); + ata_outb(ap->host, tf->nsect, ioaddr->nsect_addr); + ata_outb(ap->host, tf->lbal, ioaddr->lbal_addr); + ata_outb(ap->host, tf->lbam, ioaddr->lbam_addr); + ata_outb(ap->host, tf->lbah, ioaddr->lbah_addr); + } + + if (tf->flags & ATA_TFLAG_DEVICE) + ata_outb(ap->host, tf->device, ioaddr->device_addr); + + ata_wait_idle(ap); +} + +/* + * pata_s3c_tf_read - input device's ATA taskfile shadow registers + */ +static void pata_s3c_tf_read(struct ata_port *ap, struct ata_taskfile *tf) +{ + struct ata_ioports *ioaddr = &ap->ioaddr; + + tf->feature = ata_inb(ap->host, ioaddr->error_addr); + tf->nsect = ata_inb(ap->host, ioaddr->nsect_addr); + tf->lbal = ata_inb(ap->host, ioaddr->lbal_addr); + tf->lbam = ata_inb(ap->host, ioaddr->lbam_addr); + tf->lbah = ata_inb(ap->host, ioaddr->lbah_addr); + tf->device = ata_inb(ap->host, ioaddr->device_addr); + + if (tf->flags & ATA_TFLAG_LBA48) { + ata_outb(ap->host, tf->ctl | ATA_HOB, ioaddr->ctl_addr); + tf->hob_feature = ata_inb(ap->host, ioaddr->error_addr); + tf->hob_nsect = ata_inb(ap->host, ioaddr->nsect_addr); + tf->hob_lbal = ata_inb(ap->host, ioaddr->lbal_addr); + tf->hob_lbam = ata_inb(ap->host, ioaddr->lbam_addr); + tf->hob_lbah = ata_inb(ap->host, ioaddr->lbah_addr); + ata_outb(ap->host, tf->ctl, ioaddr->ctl_addr); + ap->last_ctl = tf->ctl; + } +} + +/* + * pata_s3c_exec_command - issue ATA command to host controller + */ +static void pata_s3c_exec_command(struct ata_port *ap, + const struct ata_taskfile *tf) +{ + ata_outb(ap->host, tf->command, ap->ioaddr.command_addr); + ata_sff_pause(ap); +} + +/* + * pata_s3c_check_status - Read device status register + */ +static u8 pata_s3c_check_status(struct ata_port *ap) +{ + return ata_inb(ap->host, ap->ioaddr.status_addr); +} + +/* + * pata_s3c_check_altstatus - Read alternate device status register + */ +static u8 pata_s3c_check_altstatus(struct ata_port *ap) +{ + return ata_inb(ap->host, ap->ioaddr.altstatus_addr); +} + +/* + * pata_s3c_data_xfer - Transfer data by PIO + */ +unsigned int pata_s3c_data_xfer(struct ata_device *dev, unsigned char *buf, + unsigned int buflen, int rw) +{ + struct ata_port *ap = dev->link->ap; + struct s3c_ide_info *info = ap->host->private_data; + void __iomem *data_addr = ap->ioaddr.data_addr; + unsigned int words = buflen >> 1, i; + u16 *data_ptr = (u16 *)buf; + + /* Requires wait same as in ata_inb/ata_outb */ + if (rw == READ) + for (i = 0; i < words; i++, data_ptr++) { + wait_for_host_ready(info); + (void) readw(data_addr); + wait_for_host_ready(info); + *data_ptr = readw(info->ide_addr + + S3C_ATA_PIO_RDATA); + } + else + for (i = 0; i < words; i++, data_ptr++) { + wait_for_host_ready(info); + writew(*data_ptr, data_addr); + } + + if (buflen & 0x01) + dev_err(ap->dev, "unexpected trailing data\n"); + + return words << 1; +} + +/* + * pata_s3c_dev_select - Select device on ATA bus + */ +static void pata_s3c_dev_select(struct ata_port *ap, unsigned int device) +{ + u8 tmp = ATA_DEVICE_OBS; + + if (device != 0) + tmp |= ATA_DEV1; + + ata_outb(ap->host, tmp, ap->ioaddr.device_addr); + ata_sff_pause(ap); +} + +/* + * pata_s3c_devchk - PATA device presence detection + */ +static unsigned int pata_s3c_devchk(struct ata_port *ap, + unsigned int device) +{ + struct ata_ioports *ioaddr = &ap->ioaddr; + u8 nsect, lbal; + + pata_s3c_dev_select(ap, device); + + ata_outb(ap->host, 0x55, ioaddr->nsect_addr); + ata_outb(ap->host, 0xaa, ioaddr->lbal_addr); + + ata_outb(ap->host, 0xaa, ioaddr->nsect_addr); + ata_outb(ap->host, 0x55, ioaddr->lbal_addr); + + ata_outb(ap->host, 0x55, ioaddr->nsect_addr); + ata_outb(ap->host, 0xaa, ioaddr->lbal_addr); + + nsect = ata_inb(ap->host, ioaddr->nsect_addr); + lbal = ata_inb(ap->host, ioaddr->lbal_addr); + + if ((nsect == 0x55) && (lbal == 0xaa)) + return 1; /* we found a device */ + + return 0; /* nothing found */ +} + +/* + * pata_s3c_wait_after_reset - wait for devices to become ready after reset + */ +static int pata_s3c_wait_after_reset(struct ata_link *link, + unsigned long deadline) +{ + int rc; + + msleep(ATA_WAIT_AFTER_RESET); + + /* always check readiness of the master device */ + rc = ata_sff_wait_ready(link, deadline); + /* -ENODEV means the odd clown forgot the D7 pulldown resistor + * and TF status is 0xff, bail out on it too. + */ + if (rc) + return rc; + + return 0; +} + +/* + * pata_s3c_bus_softreset - PATA device software reset + */ +static unsigned int pata_s3c_bus_softreset(struct ata_port *ap, + unsigned long deadline) +{ + struct ata_ioports *ioaddr = &ap->ioaddr; + + /* software reset. causes dev0 to be selected */ + ata_outb(ap->host, ap->ctl, ioaddr->ctl_addr); + udelay(20); + ata_outb(ap->host, ap->ctl | ATA_SRST, ioaddr->ctl_addr); + udelay(20); + ata_outb(ap->host, ap->ctl, ioaddr->ctl_addr); + ap->last_ctl = ap->ctl; + + return pata_s3c_wait_after_reset(&ap->link, deadline); +} + +/* + * pata_s3c_softreset - reset host port via ATA SRST + */ +static int pata_s3c_softreset(struct ata_link *link, unsigned int *classes, + unsigned long deadline) +{ + struct ata_port *ap = link->ap; + unsigned int devmask = 0; + int rc; + u8 err; + + /* determine if device 0 is present */ + if (pata_s3c_devchk(ap, 0)) + devmask |= (1 << 0); + + /* select device 0 again */ + pata_s3c_dev_select(ap, 0); + + /* issue bus reset */ + rc = pata_s3c_bus_softreset(ap, deadline); + /* if link is occupied, -ENODEV too is an error */ + if (rc && rc != -ENODEV) { + ata_link_printk(link, KERN_ERR, "SRST failed (errno=%d)\n", rc); + return rc; + } + + /* determine by signature whether we have ATA or ATAPI devices */ + classes[0] = ata_sff_dev_classify(&ap->link.device[0], + devmask & (1 << 0), &err); + + return 0; +} + +/* + * pata_s3c_set_devctl - Write device control register + */ +static void pata_s3c_set_devctl(struct ata_port *ap, u8 ctl) +{ + ata_outb(ap->host, ctl, ap->ioaddr.ctl_addr); +} + +static struct scsi_host_template pata_s3c_sht = { + ATA_PIO_SHT(DRV_NAME), +}; + +static struct ata_port_operations pata_s3c_port_ops = { + .inherits = &ata_sff_port_ops, + .sff_check_status = pata_s3c_check_status, + .sff_check_altstatus = pata_s3c_check_altstatus, + .sff_tf_load = pata_s3c_tf_load, + .sff_tf_read = pata_s3c_tf_read, + .sff_data_xfer = pata_s3c_data_xfer, + .sff_exec_command = pata_s3c_exec_command, + .sff_dev_select = pata_s3c_dev_select, + .sff_set_devctl = pata_s3c_set_devctl, + .softreset = pata_s3c_softreset, + .set_piomode = pata_s3c_set_piomode, +}; + +static struct ata_port_operations pata_s5p_port_ops = { + .inherits = &ata_sff_port_ops, + .set_piomode = pata_s3c_set_piomode, +}; + +static void pata_s3c_enable(void *s3c_ide_regbase, bool state) +{ + u32 temp = readl(s3c_ide_regbase + S3C_ATA_CTRL); + temp = state ? (temp | 1) : (temp & ~1); + writel(temp, s3c_ide_regbase + S3C_ATA_CTRL); +} + +static irqreturn_t pata_s3c_irq(int irq, void *dev_instance) +{ + struct ata_host *host = dev_instance; + struct s3c_ide_info *info = host->private_data; + u32 reg; + + reg = readl(info->ide_addr + S3C_ATA_IRQ); + writel(reg, info->ide_addr + S3C_ATA_IRQ); + + return ata_sff_interrupt(irq, dev_instance); +} + +static void pata_s3c_hwinit(struct s3c_ide_info *info, + struct s3c_ide_platdata *pdata) +{ + switch (info->cpu_type) { + case TYPE_S3C64XX: + /* Configure as big endian */ + pata_s3c_cfg_mode(info->sfr_addr); + pata_s3c_set_endian(info->ide_addr, 1); + pata_s3c_enable(info->ide_addr, true); + msleep(100); + + /* Remove IRQ Status */ + writel(0x1f, info->ide_addr + S3C_ATA_IRQ); + writel(0x1b, info->ide_addr + S3C_ATA_IRQ_MSK); + break; + + case TYPE_S5PC100: + pata_s3c_cfg_mode(info->sfr_addr); + /* FALLTHROUGH */ + + case TYPE_S5PV210: + /* Configure as little endian */ + pata_s3c_set_endian(info->ide_addr, 0); + pata_s3c_enable(info->ide_addr, true); + msleep(100); + + /* Remove IRQ Status */ + writel(0x3f, info->ide_addr + S3C_ATA_IRQ); + writel(0x3f, info->ide_addr + S3C_ATA_IRQ_MSK); + break; + + default: + BUG(); + } +} + +static int __init pata_s3c_probe(struct platform_device *pdev) +{ + struct s3c_ide_platdata *pdata = pdev->dev.platform_data; + struct device *dev = &pdev->dev; + struct s3c_ide_info *info; + struct resource *res; + struct ata_port *ap; + struct ata_host *host; + enum s3c_cpu_type cpu_type; + int ret; + + cpu_type = platform_get_device_id(pdev)->driver_data; + + info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL); + if (!info) { + dev_err(dev, "failed to allocate memory for device data\n"); + return -ENOMEM; + } + + info->irq = platform_get_irq(pdev, 0); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res == NULL) { + dev_err(dev, "failed to get mem resource\n"); + return -EINVAL; + } + + if (!devm_request_mem_region(dev, res->start, + resource_size(res), DRV_NAME)) { + dev_err(dev, "error requesting register region\n"); + return -EBUSY; + } + + info->ide_addr = devm_ioremap(dev, res->start, resource_size(res)); + if (!info->ide_addr) { + dev_err(dev, "failed to map IO base address\n"); + return -ENOMEM; + } + + info->clk = clk_get(&pdev->dev, "cfcon"); + if (IS_ERR(info->clk)) { + dev_err(dev, "failed to get access to cf controller clock\n"); + ret = PTR_ERR(info->clk); + info->clk = NULL; + return ret; + } + + clk_enable(info->clk); + + /* init ata host */ + host = ata_host_alloc(dev, 1); + if (!host) { + dev_err(dev, "failed to allocate ide host\n"); + ret = -ENOMEM; + goto stop_clk; + } + + ap = host->ports[0]; + ap->flags |= ATA_FLAG_MMIO; + ap->pio_mask = ATA_PIO4; + + if (cpu_type == TYPE_S3C64XX) { + ap->ops = &pata_s3c_port_ops; + info->sfr_addr = info->ide_addr + 0x1800; + info->ide_addr += 0x1900; + info->fifo_status_reg = 0x94; + } else if (cpu_type == TYPE_S5PC100) { + ap->ops = &pata_s5p_port_ops; + info->sfr_addr = info->ide_addr + 0x1800; + info->ide_addr += 0x1900; + info->fifo_status_reg = 0x84; + } else { + ap->ops = &pata_s5p_port_ops; + info->fifo_status_reg = 0x84; + } + + info->cpu_type = cpu_type; + + if (info->irq <= 0) { + ap->flags |= ATA_FLAG_PIO_POLLING; + info->irq = 0; + ata_port_desc(ap, "no IRQ, using PIO polling\n"); + } + + ap->ioaddr.cmd_addr = info->ide_addr + S3C_ATA_CMD; + ap->ioaddr.data_addr = info->ide_addr + S3C_ATA_PIO_DTR; + ap->ioaddr.error_addr = info->ide_addr + S3C_ATA_PIO_FED; + ap->ioaddr.feature_addr = info->ide_addr + S3C_ATA_PIO_FED; + ap->ioaddr.nsect_addr = info->ide_addr + S3C_ATA_PIO_SCR; + ap->ioaddr.lbal_addr = info->ide_addr + S3C_ATA_PIO_LLR; + ap->ioaddr.lbam_addr = info->ide_addr + S3C_ATA_PIO_LMR; + ap->ioaddr.lbah_addr = info->ide_addr + S3C_ATA_PIO_LHR; + ap->ioaddr.device_addr = info->ide_addr + S3C_ATA_PIO_DVR; + ap->ioaddr.status_addr = info->ide_addr + S3C_ATA_PIO_CSD; + ap->ioaddr.command_addr = info->ide_addr + S3C_ATA_PIO_CSD; + ap->ioaddr.altstatus_addr = info->ide_addr + S3C_ATA_PIO_DAD; + ap->ioaddr.ctl_addr = info->ide_addr + S3C_ATA_PIO_DAD; + + ata_port_desc(ap, "mmio cmd 0x%llx ", + (unsigned long long)res->start); + + host->private_data = info; + + if (pdata && pdata->setup_gpio) + pdata->setup_gpio(); + + /* Set endianness and enable the interface */ + pata_s3c_hwinit(info, pdata); + + platform_set_drvdata(pdev, host); + + return ata_host_activate(host, info->irq, + info->irq ? pata_s3c_irq : NULL, + 0, &pata_s3c_sht); + +stop_clk: + clk_disable(info->clk); + clk_put(info->clk); + return ret; +} + +static int __exit pata_s3c_remove(struct platform_device *pdev) +{ + struct ata_host *host = platform_get_drvdata(pdev); + struct s3c_ide_info *info = host->private_data; + + ata_host_detach(host); + + clk_disable(info->clk); + clk_put(info->clk); + + return 0; +} + +#ifdef CONFIG_PM +static int pata_s3c_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct ata_host *host = platform_get_drvdata(pdev); + + return ata_host_suspend(host, PMSG_SUSPEND); +} + +static int pata_s3c_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct ata_host *host = platform_get_drvdata(pdev); + struct s3c_ide_platdata *pdata = pdev->dev.platform_data; + struct s3c_ide_info *info = host->private_data; + + pata_s3c_hwinit(info, pdata); + ata_host_resume(host); + + return 0; +} + +static const struct dev_pm_ops pata_s3c_pm_ops = { + .suspend = pata_s3c_suspend, + .resume = pata_s3c_resume, +}; +#endif + +/* driver device registration */ +static struct platform_device_id pata_s3c_driver_ids[] = { + { + .name = "s3c64xx-pata", + .driver_data = TYPE_S3C64XX, + }, { + .name = "s5pc100-pata", + .driver_data = TYPE_S5PC100, + }, { + .name = "s5pv210-pata", + .driver_data = TYPE_S5PV210, + }, + { } +}; + +MODULE_DEVICE_TABLE(platform, pata_s3c_driver_ids); + +static struct platform_driver pata_s3c_driver = { + .remove = __exit_p(pata_s3c_remove), + .id_table = pata_s3c_driver_ids, + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, +#ifdef CONFIG_PM + .pm = &pata_s3c_pm_ops, +#endif + }, +}; + +static int __init pata_s3c_init(void) +{ + return platform_driver_probe(&pata_s3c_driver, pata_s3c_probe); +} + +static void __exit pata_s3c_exit(void) +{ + platform_driver_unregister(&pata_s3c_driver); +} + +module_init(pata_s3c_init); +module_exit(pata_s3c_exit); + +MODULE_AUTHOR("Abhilash Kesavan, <a.kesavan@samsung.com>"); +MODULE_DESCRIPTION("low-level driver for Samsung PATA controller"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(DRV_VERSION); diff --git a/drivers/ata/pata_scc.c b/drivers/ata/pata_scc.c index d9db3f8..fe36966 100644 --- a/drivers/ata/pata_scc.c +++ b/drivers/ata/pata_scc.c @@ -168,8 +168,7 @@ static const unsigned long JCACTSELtbl[2][7] = { }; static const struct pci_device_id scc_pci_tbl[] = { - {PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_SCC_ATA, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + { PCI_VDEVICE(TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_SCC_ATA), 0}, { } /* terminate list */ }; diff --git a/drivers/ata/sata_dwc_460ex.c b/drivers/ata/sata_dwc_460ex.c new file mode 100644 index 0000000..ea24c1e --- /dev/null +++ b/drivers/ata/sata_dwc_460ex.c @@ -0,0 +1,1756 @@ +/* + * drivers/ata/sata_dwc_460ex.c + * + * Synopsys DesignWare Cores (DWC) SATA host driver + * + * Author: Mark Miesfeld <mmiesfeld@amcc.com> + * + * Ported from 2.6.19.2 to 2.6.25/26 by Stefan Roese <sr@denx.de> + * Copyright 2008 DENX Software Engineering + * + * Based on versions provided by AMCC and Synopsys which are: + * Copyright 2006 Applied Micro Circuits Corporation + * COPYRIGHT (C) 2005 SYNOPSYS, INC. ALL RIGHTS RESERVED + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifdef CONFIG_SATA_DWC_DEBUG +#define DEBUG +#endif + +#ifdef CONFIG_SATA_DWC_VDEBUG +#define VERBOSE_DEBUG +#define DEBUG_NCQ +#endif + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/device.h> +#include <linux/of_platform.h> +#include <linux/platform_device.h> +#include <linux/libata.h> +#include <linux/slab.h> +#include "libata.h" + +#include <scsi/scsi_host.h> +#include <scsi/scsi_cmnd.h> + +#define DRV_NAME "sata-dwc" +#define DRV_VERSION "1.0" + +/* SATA DMA driver Globals */ +#define DMA_NUM_CHANS 1 +#define DMA_NUM_CHAN_REGS 8 + +/* SATA DMA Register definitions */ +#define AHB_DMA_BRST_DFLT 64 /* 16 data items burst length*/ + +struct dmareg { + u32 low; /* Low bits 0-31 */ + u32 high; /* High bits 32-63 */ +}; + +/* DMA Per Channel registers */ +struct dma_chan_regs { + struct dmareg sar; /* Source Address */ + struct dmareg dar; /* Destination address */ + struct dmareg llp; /* Linked List Pointer */ + struct dmareg ctl; /* Control */ + struct dmareg sstat; /* Source Status not implemented in core */ + struct dmareg dstat; /* Destination Status not implemented in core*/ + struct dmareg sstatar; /* Source Status Address not impl in core */ + struct dmareg dstatar; /* Destination Status Address not implemente */ + struct dmareg cfg; /* Config */ + struct dmareg sgr; /* Source Gather */ + struct dmareg dsr; /* Destination Scatter */ +}; + +/* Generic Interrupt Registers */ +struct dma_interrupt_regs { + struct dmareg tfr; /* Transfer Interrupt */ + struct dmareg block; /* Block Interrupt */ + struct dmareg srctran; /* Source Transfer Interrupt */ + struct dmareg dsttran; /* Dest Transfer Interrupt */ + struct dmareg error; /* Error */ +}; + +struct ahb_dma_regs { + struct dma_chan_regs chan_regs[DMA_NUM_CHAN_REGS]; + struct dma_interrupt_regs interrupt_raw; /* Raw Interrupt */ + struct dma_interrupt_regs interrupt_status; /* Interrupt Status */ + struct dma_interrupt_regs interrupt_mask; /* Interrupt Mask */ + struct dma_interrupt_regs interrupt_clear; /* Interrupt Clear */ + struct dmareg statusInt; /* Interrupt combined*/ + struct dmareg rq_srcreg; /* Src Trans Req */ + struct dmareg rq_dstreg; /* Dst Trans Req */ + struct dmareg rq_sgl_srcreg; /* Sngl Src Trans Req*/ + struct dmareg rq_sgl_dstreg; /* Sngl Dst Trans Req*/ + struct dmareg rq_lst_srcreg; /* Last Src Trans Req*/ + struct dmareg rq_lst_dstreg; /* Last Dst Trans Req*/ + struct dmareg dma_cfg; /* DMA Config */ + struct dmareg dma_chan_en; /* DMA Channel Enable*/ + struct dmareg dma_id; /* DMA ID */ + struct dmareg dma_test; /* DMA Test */ + struct dmareg res1; /* reserved */ + struct dmareg res2; /* reserved */ + /* + * DMA Comp Params + * Param 6 = dma_param[0], Param 5 = dma_param[1], + * Param 4 = dma_param[2] ... + */ + struct dmareg dma_params[6]; +}; + +/* Data structure for linked list item */ +struct lli { + u32 sar; /* Source Address */ + u32 dar; /* Destination address */ + u32 llp; /* Linked List Pointer */ + struct dmareg ctl; /* Control */ + struct dmareg dstat; /* Destination Status */ +}; + +enum { + SATA_DWC_DMAC_LLI_SZ = (sizeof(struct lli)), + SATA_DWC_DMAC_LLI_NUM = 256, + SATA_DWC_DMAC_LLI_TBL_SZ = (SATA_DWC_DMAC_LLI_SZ * \ + SATA_DWC_DMAC_LLI_NUM), + SATA_DWC_DMAC_TWIDTH_BYTES = 4, + SATA_DWC_DMAC_CTRL_TSIZE_MAX = (0x00000800 * \ + SATA_DWC_DMAC_TWIDTH_BYTES), +}; + +/* DMA Register Operation Bits */ +enum { + DMA_EN = 0x00000001, /* Enable AHB DMA */ + DMA_CTL_LLP_SRCEN = 0x10000000, /* Blk chain enable Src */ + DMA_CTL_LLP_DSTEN = 0x08000000, /* Blk chain enable Dst */ +}; + +#define DMA_CTL_BLK_TS(size) ((size) & 0x000000FFF) /* Blk Transfer size */ +#define DMA_CHANNEL(ch) (0x00000001 << (ch)) /* Select channel */ + /* Enable channel */ +#define DMA_ENABLE_CHAN(ch) ((0x00000001 << (ch)) | \ + ((0x000000001 << (ch)) << 8)) + /* Disable channel */ +#define DMA_DISABLE_CHAN(ch) (0x00000000 | ((0x000000001 << (ch)) << 8)) + /* Transfer Type & Flow Controller */ +#define DMA_CTL_TTFC(type) (((type) & 0x7) << 20) +#define DMA_CTL_SMS(num) (((num) & 0x3) << 25) /* Src Master Select */ +#define DMA_CTL_DMS(num) (((num) & 0x3) << 23)/* Dst Master Select */ + /* Src Burst Transaction Length */ +#define DMA_CTL_SRC_MSIZE(size) (((size) & 0x7) << 14) + /* Dst Burst Transaction Length */ +#define DMA_CTL_DST_MSIZE(size) (((size) & 0x7) << 11) + /* Source Transfer Width */ +#define DMA_CTL_SRC_TRWID(size) (((size) & 0x7) << 4) + /* Destination Transfer Width */ +#define DMA_CTL_DST_TRWID(size) (((size) & 0x7) << 1) + +/* Assign HW handshaking interface (x) to destination / source peripheral */ +#define DMA_CFG_HW_HS_DEST(int_num) (((int_num) & 0xF) << 11) +#define DMA_CFG_HW_HS_SRC(int_num) (((int_num) & 0xF) << 7) +#define DMA_LLP_LMS(addr, master) (((addr) & 0xfffffffc) | (master)) + +/* + * This define is used to set block chaining disabled in the control low + * register. It is already in little endian format so it can be &'d dirctly. + * It is essentially: cpu_to_le32(~(DMA_CTL_LLP_SRCEN | DMA_CTL_LLP_DSTEN)) + */ +enum { + DMA_CTL_LLP_DISABLE_LE32 = 0xffffffe7, + DMA_CTL_TTFC_P2M_DMAC = 0x00000002, /* Per to mem, DMAC cntr */ + DMA_CTL_TTFC_M2P_PER = 0x00000003, /* Mem to per, peripheral cntr */ + DMA_CTL_SINC_INC = 0x00000000, /* Source Address Increment */ + DMA_CTL_SINC_DEC = 0x00000200, + DMA_CTL_SINC_NOCHANGE = 0x00000400, + DMA_CTL_DINC_INC = 0x00000000, /* Destination Address Increment */ + DMA_CTL_DINC_DEC = 0x00000080, + DMA_CTL_DINC_NOCHANGE = 0x00000100, + DMA_CTL_INT_EN = 0x00000001, /* Interrupt Enable */ + +/* Channel Configuration Register high bits */ + DMA_CFG_FCMOD_REQ = 0x00000001, /* Flow Control - request based */ + DMA_CFG_PROTCTL = (0x00000003 << 2),/* Protection Control */ + +/* Channel Configuration Register low bits */ + DMA_CFG_RELD_DST = 0x80000000, /* Reload Dest / Src Addr */ + DMA_CFG_RELD_SRC = 0x40000000, + DMA_CFG_HS_SELSRC = 0x00000800, /* Software handshake Src/ Dest */ + DMA_CFG_HS_SELDST = 0x00000400, + DMA_CFG_FIFOEMPTY = (0x00000001 << 9), /* FIFO Empty bit */ + +/* Channel Linked List Pointer Register */ + DMA_LLP_AHBMASTER1 = 0, /* List Master Select */ + DMA_LLP_AHBMASTER2 = 1, + + SATA_DWC_MAX_PORTS = 1, + + SATA_DWC_SCR_OFFSET = 0x24, + SATA_DWC_REG_OFFSET = 0x64, +}; + +/* DWC SATA Registers */ +struct sata_dwc_regs { + u32 fptagr; /* 1st party DMA tag */ + u32 fpbor; /* 1st party DMA buffer offset */ + u32 fptcr; /* 1st party DMA Xfr count */ + u32 dmacr; /* DMA Control */ + u32 dbtsr; /* DMA Burst Transac size */ + u32 intpr; /* Interrupt Pending */ + u32 intmr; /* Interrupt Mask */ + u32 errmr; /* Error Mask */ + u32 llcr; /* Link Layer Control */ + u32 phycr; /* PHY Control */ + u32 physr; /* PHY Status */ + u32 rxbistpd; /* Recvd BIST pattern def register */ + u32 rxbistpd1; /* Recvd BIST data dword1 */ + u32 rxbistpd2; /* Recvd BIST pattern data dword2 */ + u32 txbistpd; /* Trans BIST pattern def register */ + u32 txbistpd1; /* Trans BIST data dword1 */ + u32 txbistpd2; /* Trans BIST data dword2 */ + u32 bistcr; /* BIST Control Register */ + u32 bistfctr; /* BIST FIS Count Register */ + u32 bistsr; /* BIST Status Register */ + u32 bistdecr; /* BIST Dword Error count register */ + u32 res[15]; /* Reserved locations */ + u32 testr; /* Test Register */ + u32 versionr; /* Version Register */ + u32 idr; /* ID Register */ + u32 unimpl[192]; /* Unimplemented */ + u32 dmadr[256]; /* FIFO Locations in DMA Mode */ +}; + +enum { + SCR_SCONTROL_DET_ENABLE = 0x00000001, + SCR_SSTATUS_DET_PRESENT = 0x00000001, + SCR_SERROR_DIAG_X = 0x04000000, +/* DWC SATA Register Operations */ + SATA_DWC_TXFIFO_DEPTH = 0x01FF, + SATA_DWC_RXFIFO_DEPTH = 0x01FF, + SATA_DWC_DMACR_TMOD_TXCHEN = 0x00000004, + SATA_DWC_DMACR_TXCHEN = (0x00000001 | SATA_DWC_DMACR_TMOD_TXCHEN), + SATA_DWC_DMACR_RXCHEN = (0x00000002 | SATA_DWC_DMACR_TMOD_TXCHEN), + SATA_DWC_DMACR_TXRXCH_CLEAR = SATA_DWC_DMACR_TMOD_TXCHEN, + SATA_DWC_INTPR_DMAT = 0x00000001, + SATA_DWC_INTPR_NEWFP = 0x00000002, + SATA_DWC_INTPR_PMABRT = 0x00000004, + SATA_DWC_INTPR_ERR = 0x00000008, + SATA_DWC_INTPR_NEWBIST = 0x00000010, + SATA_DWC_INTPR_IPF = 0x10000000, + SATA_DWC_INTMR_DMATM = 0x00000001, + SATA_DWC_INTMR_NEWFPM = 0x00000002, + SATA_DWC_INTMR_PMABRTM = 0x00000004, + SATA_DWC_INTMR_ERRM = 0x00000008, + SATA_DWC_INTMR_NEWBISTM = 0x00000010, + SATA_DWC_LLCR_SCRAMEN = 0x00000001, + SATA_DWC_LLCR_DESCRAMEN = 0x00000002, + SATA_DWC_LLCR_RPDEN = 0x00000004, +/* This is all error bits, zero's are reserved fields. */ + SATA_DWC_SERROR_ERR_BITS = 0x0FFF0F03 +}; + +#define SATA_DWC_SCR0_SPD_GET(v) (((v) >> 4) & 0x0000000F) +#define SATA_DWC_DMACR_TX_CLEAR(v) (((v) & ~SATA_DWC_DMACR_TXCHEN) |\ + SATA_DWC_DMACR_TMOD_TXCHEN) +#define SATA_DWC_DMACR_RX_CLEAR(v) (((v) & ~SATA_DWC_DMACR_RXCHEN) |\ + SATA_DWC_DMACR_TMOD_TXCHEN) +#define SATA_DWC_DBTSR_MWR(size) (((size)/4) & SATA_DWC_TXFIFO_DEPTH) +#define SATA_DWC_DBTSR_MRD(size) ((((size)/4) & SATA_DWC_RXFIFO_DEPTH)\ + << 16) +struct sata_dwc_device { + struct device *dev; /* generic device struct */ + struct ata_probe_ent *pe; /* ptr to probe-ent */ + struct ata_host *host; + u8 *reg_base; + struct sata_dwc_regs *sata_dwc_regs; /* DW Synopsys SATA specific */ + int irq_dma; +}; + +#define SATA_DWC_QCMD_MAX 32 + +struct sata_dwc_device_port { + struct sata_dwc_device *hsdev; + int cmd_issued[SATA_DWC_QCMD_MAX]; + struct lli *llit[SATA_DWC_QCMD_MAX]; /* DMA LLI table */ + dma_addr_t llit_dma[SATA_DWC_QCMD_MAX]; + u32 dma_chan[SATA_DWC_QCMD_MAX]; + int dma_pending[SATA_DWC_QCMD_MAX]; +}; + +/* + * Commonly used DWC SATA driver Macros + */ +#define HSDEV_FROM_HOST(host) ((struct sata_dwc_device *)\ + (host)->private_data) +#define HSDEV_FROM_AP(ap) ((struct sata_dwc_device *)\ + (ap)->host->private_data) +#define HSDEVP_FROM_AP(ap) ((struct sata_dwc_device_port *)\ + (ap)->private_data) +#define HSDEV_FROM_QC(qc) ((struct sata_dwc_device *)\ + (qc)->ap->host->private_data) +#define HSDEV_FROM_HSDEVP(p) ((struct sata_dwc_device *)\ + (hsdevp)->hsdev) + +enum { + SATA_DWC_CMD_ISSUED_NOT = 0, + SATA_DWC_CMD_ISSUED_PEND = 1, + SATA_DWC_CMD_ISSUED_EXEC = 2, + SATA_DWC_CMD_ISSUED_NODATA = 3, + + SATA_DWC_DMA_PENDING_NONE = 0, + SATA_DWC_DMA_PENDING_TX = 1, + SATA_DWC_DMA_PENDING_RX = 2, +}; + +struct sata_dwc_host_priv { + void __iomem *scr_addr_sstatus; + u32 sata_dwc_sactive_issued ; + u32 sata_dwc_sactive_queued ; + u32 dma_interrupt_count; + struct ahb_dma_regs *sata_dma_regs; + struct device *dwc_dev; +}; +struct sata_dwc_host_priv host_pvt; +/* + * Prototypes + */ +static void sata_dwc_bmdma_start_by_tag(struct ata_queued_cmd *qc, u8 tag); +static int sata_dwc_qc_complete(struct ata_port *ap, struct ata_queued_cmd *qc, + u32 check_status); +static void sata_dwc_dma_xfer_complete(struct ata_port *ap, u32 check_status); +static void sata_dwc_port_stop(struct ata_port *ap); +static void sata_dwc_clear_dmacr(struct sata_dwc_device_port *hsdevp, u8 tag); +static int dma_dwc_init(struct sata_dwc_device *hsdev, int irq); +static void dma_dwc_exit(struct sata_dwc_device *hsdev); +static int dma_dwc_xfer_setup(struct scatterlist *sg, int num_elems, + struct lli *lli, dma_addr_t dma_lli, + void __iomem *addr, int dir); +static void dma_dwc_xfer_start(int dma_ch); + +static void sata_dwc_tf_dump(struct ata_taskfile *tf) +{ + dev_vdbg(host_pvt.dwc_dev, "taskfile cmd: 0x%02x protocol: %s flags:" + "0x%lx device: %x\n", tf->command, ata_get_cmd_descript\ + (tf->protocol), tf->flags, tf->device); + dev_vdbg(host_pvt.dwc_dev, "feature: 0x%02x nsect: 0x%x lbal: 0x%x " + "lbam: 0x%x lbah: 0x%x\n", tf->feature, tf->nsect, tf->lbal, + tf->lbam, tf->lbah); + dev_vdbg(host_pvt.dwc_dev, "hob_feature: 0x%02x hob_nsect: 0x%x " + "hob_lbal: 0x%x hob_lbam: 0x%x hob_lbah: 0x%x\n", + tf->hob_feature, tf->hob_nsect, tf->hob_lbal, tf->hob_lbam, + tf->hob_lbah); +} + +/* + * Function: get_burst_length_encode + * arguments: datalength: length in bytes of data + * returns value to be programmed in register corrresponding to data length + * This value is effectively the log(base 2) of the length + */ +static int get_burst_length_encode(int datalength) +{ + int items = datalength >> 2; /* div by 4 to get lword count */ + + if (items >= 64) + return 5; + + if (items >= 32) + return 4; + + if (items >= 16) + return 3; + + if (items >= 8) + return 2; + + if (items >= 4) + return 1; + + return 0; +} + +static void clear_chan_interrupts(int c) +{ + out_le32(&(host_pvt.sata_dma_regs->interrupt_clear.tfr.low), + DMA_CHANNEL(c)); + out_le32(&(host_pvt.sata_dma_regs->interrupt_clear.block.low), + DMA_CHANNEL(c)); + out_le32(&(host_pvt.sata_dma_regs->interrupt_clear.srctran.low), + DMA_CHANNEL(c)); + out_le32(&(host_pvt.sata_dma_regs->interrupt_clear.dsttran.low), + DMA_CHANNEL(c)); + out_le32(&(host_pvt.sata_dma_regs->interrupt_clear.error.low), + DMA_CHANNEL(c)); +} + +/* + * Function: dma_request_channel + * arguments: None + * returns channel number if available else -1 + * This function assigns the next available DMA channel from the list to the + * requester + */ +static int dma_request_channel(void) +{ + int i; + + for (i = 0; i < DMA_NUM_CHANS; i++) { + if (!(in_le32(&(host_pvt.sata_dma_regs->dma_chan_en.low)) &\ + DMA_CHANNEL(i))) + return i; + } + dev_err(host_pvt.dwc_dev, "%s NO channel chan_en: 0x%08x\n", __func__, + in_le32(&(host_pvt.sata_dma_regs->dma_chan_en.low))); + return -1; +} + +/* + * Function: dma_dwc_interrupt + * arguments: irq, dev_id, pt_regs + * returns channel number if available else -1 + * Interrupt Handler for DW AHB SATA DMA + */ +static irqreturn_t dma_dwc_interrupt(int irq, void *hsdev_instance) +{ + int chan; + u32 tfr_reg, err_reg; + unsigned long flags; + struct sata_dwc_device *hsdev = + (struct sata_dwc_device *)hsdev_instance; + struct ata_host *host = (struct ata_host *)hsdev->host; + struct ata_port *ap; + struct sata_dwc_device_port *hsdevp; + u8 tag = 0; + unsigned int port = 0; + + spin_lock_irqsave(&host->lock, flags); + ap = host->ports[port]; + hsdevp = HSDEVP_FROM_AP(ap); + tag = ap->link.active_tag; + + tfr_reg = in_le32(&(host_pvt.sata_dma_regs->interrupt_status.tfr\ + .low)); + err_reg = in_le32(&(host_pvt.sata_dma_regs->interrupt_status.error\ + .low)); + + dev_dbg(ap->dev, "eot=0x%08x err=0x%08x pending=%d active port=%d\n", + tfr_reg, err_reg, hsdevp->dma_pending[tag], port); + + for (chan = 0; chan < DMA_NUM_CHANS; chan++) { + /* Check for end-of-transfer interrupt. */ + if (tfr_reg & DMA_CHANNEL(chan)) { + /* + * Each DMA command produces 2 interrupts. Only + * complete the command after both interrupts have been + * seen. (See sata_dwc_isr()) + */ + host_pvt.dma_interrupt_count++; + sata_dwc_clear_dmacr(hsdevp, tag); + + if (hsdevp->dma_pending[tag] == + SATA_DWC_DMA_PENDING_NONE) { + dev_err(ap->dev, "DMA not pending eot=0x%08x " + "err=0x%08x tag=0x%02x pending=%d\n", + tfr_reg, err_reg, tag, + hsdevp->dma_pending[tag]); + } + + if ((host_pvt.dma_interrupt_count % 2) == 0) + sata_dwc_dma_xfer_complete(ap, 1); + + /* Clear the interrupt */ + out_le32(&(host_pvt.sata_dma_regs->interrupt_clear\ + .tfr.low), + DMA_CHANNEL(chan)); + } + + /* Check for error interrupt. */ + if (err_reg & DMA_CHANNEL(chan)) { + /* TODO Need error handler ! */ + dev_err(ap->dev, "error interrupt err_reg=0x%08x\n", + err_reg); + + /* Clear the interrupt. */ + out_le32(&(host_pvt.sata_dma_regs->interrupt_clear\ + .error.low), + DMA_CHANNEL(chan)); + } + } + spin_unlock_irqrestore(&host->lock, flags); + return IRQ_HANDLED; +} + +/* + * Function: dma_request_interrupts + * arguments: hsdev + * returns status + * This function registers ISR for a particular DMA channel interrupt + */ +static int dma_request_interrupts(struct sata_dwc_device *hsdev, int irq) +{ + int retval = 0; + int chan; + + for (chan = 0; chan < DMA_NUM_CHANS; chan++) { + /* Unmask error interrupt */ + out_le32(&(host_pvt.sata_dma_regs)->interrupt_mask.error.low, + DMA_ENABLE_CHAN(chan)); + + /* Unmask end-of-transfer interrupt */ + out_le32(&(host_pvt.sata_dma_regs)->interrupt_mask.tfr.low, + DMA_ENABLE_CHAN(chan)); + } + + retval = request_irq(irq, dma_dwc_interrupt, 0, "SATA DMA", hsdev); + if (retval) { + dev_err(host_pvt.dwc_dev, "%s: could not get IRQ %d\n", + __func__, irq); + return -ENODEV; + } + + /* Mark this interrupt as requested */ + hsdev->irq_dma = irq; + return 0; +} + +/* + * Function: map_sg_to_lli + * The Synopsis driver has a comment proposing that better performance + * is possible by only enabling interrupts on the last item in the linked list. + * However, it seems that could be a problem if an error happened on one of the + * first items. The transfer would halt, but no error interrupt would occur. + * Currently this function sets interrupts enabled for each linked list item: + * DMA_CTL_INT_EN. + */ +static int map_sg_to_lli(struct scatterlist *sg, int num_elems, + struct lli *lli, dma_addr_t dma_lli, + void __iomem *dmadr_addr, int dir) +{ + int i, idx = 0; + int fis_len = 0; + dma_addr_t next_llp; + int bl; + + dev_dbg(host_pvt.dwc_dev, "%s: sg=%p nelem=%d lli=%p dma_lli=0x%08x" + " dmadr=0x%08x\n", __func__, sg, num_elems, lli, (u32)dma_lli, + (u32)dmadr_addr); + + bl = get_burst_length_encode(AHB_DMA_BRST_DFLT); + + for (i = 0; i < num_elems; i++, sg++) { + u32 addr, offset; + u32 sg_len, len; + + addr = (u32) sg_dma_address(sg); + sg_len = sg_dma_len(sg); + + dev_dbg(host_pvt.dwc_dev, "%s: elem=%d sg_addr=0x%x sg_len" + "=%d\n", __func__, i, addr, sg_len); + + while (sg_len) { + if (idx >= SATA_DWC_DMAC_LLI_NUM) { + /* The LLI table is not large enough. */ + dev_err(host_pvt.dwc_dev, "LLI table overrun " + "(idx=%d)\n", idx); + break; + } + len = (sg_len > SATA_DWC_DMAC_CTRL_TSIZE_MAX) ? + SATA_DWC_DMAC_CTRL_TSIZE_MAX : sg_len; + + offset = addr & 0xffff; + if ((offset + sg_len) > 0x10000) + len = 0x10000 - offset; + + /* + * Make sure a LLI block is not created that will span + * 8K max FIS boundary. If the block spans such a FIS + * boundary, there is a chance that a DMA burst will + * cross that boundary -- this results in an error in + * the host controller. + */ + if (fis_len + len > 8192) { + dev_dbg(host_pvt.dwc_dev, "SPLITTING: fis_len=" + "%d(0x%x) len=%d(0x%x)\n", fis_len, + fis_len, len, len); + len = 8192 - fis_len; + fis_len = 0; + } else { + fis_len += len; + } + if (fis_len == 8192) + fis_len = 0; + + /* + * Set DMA addresses and lower half of control register + * based on direction. + */ + if (dir == DMA_FROM_DEVICE) { + lli[idx].dar = cpu_to_le32(addr); + lli[idx].sar = cpu_to_le32((u32)dmadr_addr); + + lli[idx].ctl.low = cpu_to_le32( + DMA_CTL_TTFC(DMA_CTL_TTFC_P2M_DMAC) | + DMA_CTL_SMS(0) | + DMA_CTL_DMS(1) | + DMA_CTL_SRC_MSIZE(bl) | + DMA_CTL_DST_MSIZE(bl) | + DMA_CTL_SINC_NOCHANGE | + DMA_CTL_SRC_TRWID(2) | + DMA_CTL_DST_TRWID(2) | + DMA_CTL_INT_EN | + DMA_CTL_LLP_SRCEN | + DMA_CTL_LLP_DSTEN); + } else { /* DMA_TO_DEVICE */ + lli[idx].sar = cpu_to_le32(addr); + lli[idx].dar = cpu_to_le32((u32)dmadr_addr); + + lli[idx].ctl.low = cpu_to_le32( + DMA_CTL_TTFC(DMA_CTL_TTFC_M2P_PER) | + DMA_CTL_SMS(1) | + DMA_CTL_DMS(0) | + DMA_CTL_SRC_MSIZE(bl) | + DMA_CTL_DST_MSIZE(bl) | + DMA_CTL_DINC_NOCHANGE | + DMA_CTL_SRC_TRWID(2) | + DMA_CTL_DST_TRWID(2) | + DMA_CTL_INT_EN | + DMA_CTL_LLP_SRCEN | + DMA_CTL_LLP_DSTEN); + } + + dev_dbg(host_pvt.dwc_dev, "%s setting ctl.high len: " + "0x%08x val: 0x%08x\n", __func__, + len, DMA_CTL_BLK_TS(len / 4)); + + /* Program the LLI CTL high register */ + lli[idx].ctl.high = cpu_to_le32(DMA_CTL_BLK_TS\ + (len / 4)); + + /* Program the next pointer. The next pointer must be + * the physical address, not the virtual address. + */ + next_llp = (dma_lli + ((idx + 1) * sizeof(struct \ + lli))); + + /* The last 2 bits encode the list master select. */ + next_llp = DMA_LLP_LMS(next_llp, DMA_LLP_AHBMASTER2); + + lli[idx].llp = cpu_to_le32(next_llp); + idx++; + sg_len -= len; + addr += len; + } + } + + /* + * The last next ptr has to be zero and the last control low register + * has to have LLP_SRC_EN and LLP_DST_EN (linked list pointer source + * and destination enable) set back to 0 (disabled.) This is what tells + * the core that this is the last item in the linked list. + */ + if (idx) { + lli[idx-1].llp = 0x00000000; + lli[idx-1].ctl.low &= DMA_CTL_LLP_DISABLE_LE32; + + /* Flush cache to memory */ + dma_cache_sync(NULL, lli, (sizeof(struct lli) * idx), + DMA_BIDIRECTIONAL); + } + + return idx; +} + +/* + * Function: dma_dwc_xfer_start + * arguments: Channel number + * Return : None + * Enables the DMA channel + */ +static void dma_dwc_xfer_start(int dma_ch) +{ + /* Enable the DMA channel */ + out_le32(&(host_pvt.sata_dma_regs->dma_chan_en.low), + in_le32(&(host_pvt.sata_dma_regs->dma_chan_en.low)) | + DMA_ENABLE_CHAN(dma_ch)); +} + +static int dma_dwc_xfer_setup(struct scatterlist *sg, int num_elems, + struct lli *lli, dma_addr_t dma_lli, + void __iomem *addr, int dir) +{ + int dma_ch; + int num_lli; + /* Acquire DMA channel */ + dma_ch = dma_request_channel(); + if (dma_ch == -1) { + dev_err(host_pvt.dwc_dev, "%s: dma channel unavailable\n", + __func__); + return -EAGAIN; + } + + /* Convert SG list to linked list of items (LLIs) for AHB DMA */ + num_lli = map_sg_to_lli(sg, num_elems, lli, dma_lli, addr, dir); + + dev_dbg(host_pvt.dwc_dev, "%s sg: 0x%p, count: %d lli: %p dma_lli:" + " 0x%0xlx addr: %p lli count: %d\n", __func__, sg, num_elems, + lli, (u32)dma_lli, addr, num_lli); + + clear_chan_interrupts(dma_ch); + + /* Program the CFG register. */ + out_le32(&(host_pvt.sata_dma_regs->chan_regs[dma_ch].cfg.high), + DMA_CFG_PROTCTL | DMA_CFG_FCMOD_REQ); + out_le32(&(host_pvt.sata_dma_regs->chan_regs[dma_ch].cfg.low), 0); + + /* Program the address of the linked list */ + out_le32(&(host_pvt.sata_dma_regs->chan_regs[dma_ch].llp.low), + DMA_LLP_LMS(dma_lli, DMA_LLP_AHBMASTER2)); + + /* Program the CTL register with src enable / dst enable */ + out_le32(&(host_pvt.sata_dma_regs->chan_regs[dma_ch].ctl.low), + DMA_CTL_LLP_SRCEN | DMA_CTL_LLP_DSTEN); + return 0; +} + +/* + * Function: dma_dwc_exit + * arguments: None + * returns status + * This function exits the SATA DMA driver + */ +static void dma_dwc_exit(struct sata_dwc_device *hsdev) +{ + dev_dbg(host_pvt.dwc_dev, "%s:\n", __func__); + if (host_pvt.sata_dma_regs) + iounmap(host_pvt.sata_dma_regs); + + if (hsdev->irq_dma) + free_irq(hsdev->irq_dma, hsdev); +} + +/* + * Function: dma_dwc_init + * arguments: hsdev + * returns status + * This function initializes the SATA DMA driver + */ +static int dma_dwc_init(struct sata_dwc_device *hsdev, int irq) +{ + int err; + + err = dma_request_interrupts(hsdev, irq); + if (err) { + dev_err(host_pvt.dwc_dev, "%s: dma_request_interrupts returns" + " %d\n", __func__, err); + goto error_out; + } + + /* Enabe DMA */ + out_le32(&(host_pvt.sata_dma_regs->dma_cfg.low), DMA_EN); + + dev_notice(host_pvt.dwc_dev, "DMA initialized\n"); + dev_dbg(host_pvt.dwc_dev, "SATA DMA registers=0x%p\n", host_pvt.\ + sata_dma_regs); + + return 0; + +error_out: + dma_dwc_exit(hsdev); + + return err; +} + +static int sata_dwc_scr_read(struct ata_link *link, unsigned int scr, u32 *val) +{ + if (scr > SCR_NOTIFICATION) { + dev_err(link->ap->dev, "%s: Incorrect SCR offset 0x%02x\n", + __func__, scr); + return -EINVAL; + } + + *val = in_le32((void *)link->ap->ioaddr.scr_addr + (scr * 4)); + dev_dbg(link->ap->dev, "%s: id=%d reg=%d val=val=0x%08x\n", + __func__, link->ap->print_id, scr, *val); + + return 0; +} + +static int sata_dwc_scr_write(struct ata_link *link, unsigned int scr, u32 val) +{ + dev_dbg(link->ap->dev, "%s: id=%d reg=%d val=val=0x%08x\n", + __func__, link->ap->print_id, scr, val); + if (scr > SCR_NOTIFICATION) { + dev_err(link->ap->dev, "%s: Incorrect SCR offset 0x%02x\n", + __func__, scr); + return -EINVAL; + } + out_le32((void *)link->ap->ioaddr.scr_addr + (scr * 4), val); + + return 0; +} + +static u32 core_scr_read(unsigned int scr) +{ + return in_le32((void __iomem *)(host_pvt.scr_addr_sstatus) +\ + (scr * 4)); +} + +static void core_scr_write(unsigned int scr, u32 val) +{ + out_le32((void __iomem *)(host_pvt.scr_addr_sstatus) + (scr * 4), + val); +} + +static void clear_serror(void) +{ + u32 val; + val = core_scr_read(SCR_ERROR); + core_scr_write(SCR_ERROR, val); + +} + +static void clear_interrupt_bit(struct sata_dwc_device *hsdev, u32 bit) +{ + out_le32(&hsdev->sata_dwc_regs->intpr, + in_le32(&hsdev->sata_dwc_regs->intpr)); +} + +static u32 qcmd_tag_to_mask(u8 tag) +{ + return 0x00000001 << (tag & 0x1f); +} + +/* See ahci.c */ +static void sata_dwc_error_intr(struct ata_port *ap, + struct sata_dwc_device *hsdev, uint intpr) +{ + struct sata_dwc_device_port *hsdevp = HSDEVP_FROM_AP(ap); + struct ata_eh_info *ehi = &ap->link.eh_info; + unsigned int err_mask = 0, action = 0; + struct ata_queued_cmd *qc; + u32 serror; + u8 status, tag; + u32 err_reg; + + ata_ehi_clear_desc(ehi); + + serror = core_scr_read(SCR_ERROR); + status = ap->ops->sff_check_status(ap); + + err_reg = in_le32(&(host_pvt.sata_dma_regs->interrupt_status.error.\ + low)); + tag = ap->link.active_tag; + + dev_err(ap->dev, "%s SCR_ERROR=0x%08x intpr=0x%08x status=0x%08x " + "dma_intp=%d pending=%d issued=%d dma_err_status=0x%08x\n", + __func__, serror, intpr, status, host_pvt.dma_interrupt_count, + hsdevp->dma_pending[tag], hsdevp->cmd_issued[tag], err_reg); + + /* Clear error register and interrupt bit */ + clear_serror(); + clear_interrupt_bit(hsdev, SATA_DWC_INTPR_ERR); + + /* This is the only error happening now. TODO check for exact error */ + + err_mask |= AC_ERR_HOST_BUS; + action |= ATA_EH_RESET; + + /* Pass this on to EH */ + ehi->serror |= serror; + ehi->action |= action; + + qc = ata_qc_from_tag(ap, tag); + if (qc) + qc->err_mask |= err_mask; + else + ehi->err_mask |= err_mask; + + ata_port_abort(ap); +} + +/* + * Function : sata_dwc_isr + * arguments : irq, void *dev_instance, struct pt_regs *regs + * Return value : irqreturn_t - status of IRQ + * This Interrupt handler called via port ops registered function. + * .irq_handler = sata_dwc_isr + */ +static irqreturn_t sata_dwc_isr(int irq, void *dev_instance) +{ + struct ata_host *host = (struct ata_host *)dev_instance; + struct sata_dwc_device *hsdev = HSDEV_FROM_HOST(host); + struct ata_port *ap; + struct ata_queued_cmd *qc; + unsigned long flags; + u8 status, tag; + int handled, num_processed, port = 0; + uint intpr, sactive, sactive2, tag_mask; + struct sata_dwc_device_port *hsdevp; + host_pvt.sata_dwc_sactive_issued = 0; + + spin_lock_irqsave(&host->lock, flags); + + /* Read the interrupt register */ + intpr = in_le32(&hsdev->sata_dwc_regs->intpr); + + ap = host->ports[port]; + hsdevp = HSDEVP_FROM_AP(ap); + + dev_dbg(ap->dev, "%s intpr=0x%08x active_tag=%d\n", __func__, intpr, + ap->link.active_tag); + + /* Check for error interrupt */ + if (intpr & SATA_DWC_INTPR_ERR) { + sata_dwc_error_intr(ap, hsdev, intpr); + handled = 1; + goto DONE; + } + + /* Check for DMA SETUP FIS (FP DMA) interrupt */ + if (intpr & SATA_DWC_INTPR_NEWFP) { + clear_interrupt_bit(hsdev, SATA_DWC_INTPR_NEWFP); + + tag = (u8)(in_le32(&hsdev->sata_dwc_regs->fptagr)); + dev_dbg(ap->dev, "%s: NEWFP tag=%d\n", __func__, tag); + if (hsdevp->cmd_issued[tag] != SATA_DWC_CMD_ISSUED_PEND) + dev_warn(ap->dev, "CMD tag=%d not pending?\n", tag); + + host_pvt.sata_dwc_sactive_issued |= qcmd_tag_to_mask(tag); + + qc = ata_qc_from_tag(ap, tag); + /* + * Start FP DMA for NCQ command. At this point the tag is the + * active tag. It is the tag that matches the command about to + * be completed. + */ + qc->ap->link.active_tag = tag; + sata_dwc_bmdma_start_by_tag(qc, tag); + + handled = 1; + goto DONE; + } + sactive = core_scr_read(SCR_ACTIVE); + tag_mask = (host_pvt.sata_dwc_sactive_issued | sactive) ^ sactive; + + /* If no sactive issued and tag_mask is zero then this is not NCQ */ + if (host_pvt.sata_dwc_sactive_issued == 0 && tag_mask == 0) { + if (ap->link.active_tag == ATA_TAG_POISON) + tag = 0; + else + tag = ap->link.active_tag; + qc = ata_qc_from_tag(ap, tag); + + /* DEV interrupt w/ no active qc? */ + if (unlikely(!qc || (qc->tf.flags & ATA_TFLAG_POLLING))) { + dev_err(ap->dev, "%s interrupt with no active qc " + "qc=%p\n", __func__, qc); + ap->ops->sff_check_status(ap); + handled = 1; + goto DONE; + } + status = ap->ops->sff_check_status(ap); + + qc->ap->link.active_tag = tag; + hsdevp->cmd_issued[tag] = SATA_DWC_CMD_ISSUED_NOT; + + if (status & ATA_ERR) { + dev_dbg(ap->dev, "interrupt ATA_ERR (0x%x)\n", status); + sata_dwc_qc_complete(ap, qc, 1); + handled = 1; + goto DONE; + } + + dev_dbg(ap->dev, "%s non-NCQ cmd interrupt, protocol: %s\n", + __func__, ata_get_cmd_descript(qc->tf.protocol)); +DRVSTILLBUSY: + if (ata_is_dma(qc->tf.protocol)) { + /* + * Each DMA transaction produces 2 interrupts. The DMAC + * transfer complete interrupt and the SATA controller + * operation done interrupt. The command should be + * completed only after both interrupts are seen. + */ + host_pvt.dma_interrupt_count++; + if (hsdevp->dma_pending[tag] == \ + SATA_DWC_DMA_PENDING_NONE) { + dev_err(ap->dev, "%s: DMA not pending " + "intpr=0x%08x status=0x%08x pending" + "=%d\n", __func__, intpr, status, + hsdevp->dma_pending[tag]); + } + + if ((host_pvt.dma_interrupt_count % 2) == 0) + sata_dwc_dma_xfer_complete(ap, 1); + } else if (ata_is_pio(qc->tf.protocol)) { + ata_sff_hsm_move(ap, qc, status, 0); + handled = 1; + goto DONE; + } else { + if (unlikely(sata_dwc_qc_complete(ap, qc, 1))) + goto DRVSTILLBUSY; + } + + handled = 1; + goto DONE; + } + + /* + * This is a NCQ command. At this point we need to figure out for which + * tags we have gotten a completion interrupt. One interrupt may serve + * as completion for more than one operation when commands are queued + * (NCQ). We need to process each completed command. + */ + + /* process completed commands */ + sactive = core_scr_read(SCR_ACTIVE); + tag_mask = (host_pvt.sata_dwc_sactive_issued | sactive) ^ sactive; + + if (sactive != 0 || (host_pvt.sata_dwc_sactive_issued) > 1 || \ + tag_mask > 1) { + dev_dbg(ap->dev, "%s NCQ:sactive=0x%08x sactive_issued=0x%08x" + "tag_mask=0x%08x\n", __func__, sactive, + host_pvt.sata_dwc_sactive_issued, tag_mask); + } + + if ((tag_mask | (host_pvt.sata_dwc_sactive_issued)) != \ + (host_pvt.sata_dwc_sactive_issued)) { + dev_warn(ap->dev, "Bad tag mask? sactive=0x%08x " + "(host_pvt.sata_dwc_sactive_issued)=0x%08x tag_mask" + "=0x%08x\n", sactive, host_pvt.sata_dwc_sactive_issued, + tag_mask); + } + + /* read just to clear ... not bad if currently still busy */ + status = ap->ops->sff_check_status(ap); + dev_dbg(ap->dev, "%s ATA status register=0x%x\n", __func__, status); + + tag = 0; + num_processed = 0; + while (tag_mask) { + num_processed++; + while (!(tag_mask & 0x00000001)) { + tag++; + tag_mask <<= 1; + } + + tag_mask &= (~0x00000001); + qc = ata_qc_from_tag(ap, tag); + + /* To be picked up by completion functions */ + qc->ap->link.active_tag = tag; + hsdevp->cmd_issued[tag] = SATA_DWC_CMD_ISSUED_NOT; + + /* Let libata/scsi layers handle error */ + if (status & ATA_ERR) { + dev_dbg(ap->dev, "%s ATA_ERR (0x%x)\n", __func__, + status); + sata_dwc_qc_complete(ap, qc, 1); + handled = 1; + goto DONE; + } + + /* Process completed command */ + dev_dbg(ap->dev, "%s NCQ command, protocol: %s\n", __func__, + ata_get_cmd_descript(qc->tf.protocol)); + if (ata_is_dma(qc->tf.protocol)) { + host_pvt.dma_interrupt_count++; + if (hsdevp->dma_pending[tag] == \ + SATA_DWC_DMA_PENDING_NONE) + dev_warn(ap->dev, "%s: DMA not pending?\n", + __func__); + if ((host_pvt.dma_interrupt_count % 2) == 0) + sata_dwc_dma_xfer_complete(ap, 1); + } else { + if (unlikely(sata_dwc_qc_complete(ap, qc, 1))) + goto STILLBUSY; + } + continue; + +STILLBUSY: + ap->stats.idle_irq++; + dev_warn(ap->dev, "STILL BUSY IRQ ata%d: irq trap\n", + ap->print_id); + } /* while tag_mask */ + + /* + * Check to see if any commands completed while we were processing our + * initial set of completed commands (read status clears interrupts, + * so we might miss a completed command interrupt if one came in while + * we were processing --we read status as part of processing a completed + * command). + */ + sactive2 = core_scr_read(SCR_ACTIVE); + if (sactive2 != sactive) { + dev_dbg(ap->dev, "More completed - sactive=0x%x sactive2" + "=0x%x\n", sactive, sactive2); + } + handled = 1; + +DONE: + spin_unlock_irqrestore(&host->lock, flags); + return IRQ_RETVAL(handled); +} + +static void sata_dwc_clear_dmacr(struct sata_dwc_device_port *hsdevp, u8 tag) +{ + struct sata_dwc_device *hsdev = HSDEV_FROM_HSDEVP(hsdevp); + + if (hsdevp->dma_pending[tag] == SATA_DWC_DMA_PENDING_RX) { + out_le32(&(hsdev->sata_dwc_regs->dmacr), + SATA_DWC_DMACR_RX_CLEAR( + in_le32(&(hsdev->sata_dwc_regs->dmacr)))); + } else if (hsdevp->dma_pending[tag] == SATA_DWC_DMA_PENDING_TX) { + out_le32(&(hsdev->sata_dwc_regs->dmacr), + SATA_DWC_DMACR_TX_CLEAR( + in_le32(&(hsdev->sata_dwc_regs->dmacr)))); + } else { + /* + * This should not happen, it indicates the driver is out of + * sync. If it does happen, clear dmacr anyway. + */ + dev_err(host_pvt.dwc_dev, "%s DMA protocol RX and" + "TX DMA not pending tag=0x%02x pending=%d" + " dmacr: 0x%08x\n", __func__, tag, + hsdevp->dma_pending[tag], + in_le32(&(hsdev->sata_dwc_regs->dmacr))); + out_le32(&(hsdev->sata_dwc_regs->dmacr), + SATA_DWC_DMACR_TXRXCH_CLEAR); + } +} + +static void sata_dwc_dma_xfer_complete(struct ata_port *ap, u32 check_status) +{ + struct ata_queued_cmd *qc; + struct sata_dwc_device_port *hsdevp = HSDEVP_FROM_AP(ap); + struct sata_dwc_device *hsdev = HSDEV_FROM_AP(ap); + u8 tag = 0; + + tag = ap->link.active_tag; + qc = ata_qc_from_tag(ap, tag); + if (!qc) { + dev_err(ap->dev, "failed to get qc"); + return; + } + +#ifdef DEBUG_NCQ + if (tag > 0) { + dev_info(ap->dev, "%s tag=%u cmd=0x%02x dma dir=%s proto=%s " + "dmacr=0x%08x\n", __func__, qc->tag, qc->tf.command, + ata_get_cmd_descript(qc->dma_dir), + ata_get_cmd_descript(qc->tf.protocol), + in_le32(&(hsdev->sata_dwc_regs->dmacr))); + } +#endif + + if (ata_is_dma(qc->tf.protocol)) { + if (hsdevp->dma_pending[tag] == SATA_DWC_DMA_PENDING_NONE) { + dev_err(ap->dev, "%s DMA protocol RX and TX DMA not " + "pending dmacr: 0x%08x\n", __func__, + in_le32(&(hsdev->sata_dwc_regs->dmacr))); + } + + hsdevp->dma_pending[tag] = SATA_DWC_DMA_PENDING_NONE; + sata_dwc_qc_complete(ap, qc, check_status); + ap->link.active_tag = ATA_TAG_POISON; + } else { + sata_dwc_qc_complete(ap, qc, check_status); + } +} + +static int sata_dwc_qc_complete(struct ata_port *ap, struct ata_queued_cmd *qc, + u32 check_status) +{ + u8 status = 0; + u32 mask = 0x0; + u8 tag = qc->tag; + struct sata_dwc_device_port *hsdevp = HSDEVP_FROM_AP(ap); + host_pvt.sata_dwc_sactive_queued = 0; + dev_dbg(ap->dev, "%s checkstatus? %x\n", __func__, check_status); + + if (hsdevp->dma_pending[tag] == SATA_DWC_DMA_PENDING_TX) + dev_err(ap->dev, "TX DMA PENDING\n"); + else if (hsdevp->dma_pending[tag] == SATA_DWC_DMA_PENDING_RX) + dev_err(ap->dev, "RX DMA PENDING\n"); + dev_dbg(ap->dev, "QC complete cmd=0x%02x status=0x%02x ata%u:" + " protocol=%d\n", qc->tf.command, status, ap->print_id, + qc->tf.protocol); + + /* clear active bit */ + mask = (~(qcmd_tag_to_mask(tag))); + host_pvt.sata_dwc_sactive_queued = (host_pvt.sata_dwc_sactive_queued) \ + & mask; + host_pvt.sata_dwc_sactive_issued = (host_pvt.sata_dwc_sactive_issued) \ + & mask; + ata_qc_complete(qc); + return 0; +} + +static void sata_dwc_enable_interrupts(struct sata_dwc_device *hsdev) +{ + /* Enable selective interrupts by setting the interrupt maskregister*/ + out_le32(&hsdev->sata_dwc_regs->intmr, + SATA_DWC_INTMR_ERRM | + SATA_DWC_INTMR_NEWFPM | + SATA_DWC_INTMR_PMABRTM | + SATA_DWC_INTMR_DMATM); + /* + * Unmask the error bits that should trigger an error interrupt by + * setting the error mask register. + */ + out_le32(&hsdev->sata_dwc_regs->errmr, SATA_DWC_SERROR_ERR_BITS); + + dev_dbg(host_pvt.dwc_dev, "%s: INTMR = 0x%08x, ERRMR = 0x%08x\n", + __func__, in_le32(&hsdev->sata_dwc_regs->intmr), + in_le32(&hsdev->sata_dwc_regs->errmr)); +} + +static void sata_dwc_setup_port(struct ata_ioports *port, unsigned long base) +{ + port->cmd_addr = (void *)base + 0x00; + port->data_addr = (void *)base + 0x00; + + port->error_addr = (void *)base + 0x04; + port->feature_addr = (void *)base + 0x04; + + port->nsect_addr = (void *)base + 0x08; + + port->lbal_addr = (void *)base + 0x0c; + port->lbam_addr = (void *)base + 0x10; + port->lbah_addr = (void *)base + 0x14; + + port->device_addr = (void *)base + 0x18; + port->command_addr = (void *)base + 0x1c; + port->status_addr = (void *)base + 0x1c; + + port->altstatus_addr = (void *)base + 0x20; + port->ctl_addr = (void *)base + 0x20; +} + +/* + * Function : sata_dwc_port_start + * arguments : struct ata_ioports *port + * Return value : returns 0 if success, error code otherwise + * This function allocates the scatter gather LLI table for AHB DMA + */ +static int sata_dwc_port_start(struct ata_port *ap) +{ + int err = 0; + struct sata_dwc_device *hsdev; + struct sata_dwc_device_port *hsdevp = NULL; + struct device *pdev; + int i; + + hsdev = HSDEV_FROM_AP(ap); + + dev_dbg(ap->dev, "%s: port_no=%d\n", __func__, ap->port_no); + + hsdev->host = ap->host; + pdev = ap->host->dev; + if (!pdev) { + dev_err(ap->dev, "%s: no ap->host->dev\n", __func__); + err = -ENODEV; + goto CLEANUP; + } + + /* Allocate Port Struct */ + hsdevp = kzalloc(sizeof(*hsdevp), GFP_KERNEL); + if (!hsdevp) { + dev_err(ap->dev, "%s: kmalloc failed for hsdevp\n", __func__); + err = -ENOMEM; + goto CLEANUP; + } + hsdevp->hsdev = hsdev; + + for (i = 0; i < SATA_DWC_QCMD_MAX; i++) + hsdevp->cmd_issued[i] = SATA_DWC_CMD_ISSUED_NOT; + + ap->bmdma_prd = 0; /* set these so libata doesn't use them */ + ap->bmdma_prd_dma = 0; + + /* + * DMA - Assign scatter gather LLI table. We can't use the libata + * version since it's PRD is IDE PCI specific. + */ + for (i = 0; i < SATA_DWC_QCMD_MAX; i++) { + hsdevp->llit[i] = dma_alloc_coherent(pdev, + SATA_DWC_DMAC_LLI_TBL_SZ, + &(hsdevp->llit_dma[i]), + GFP_ATOMIC); + if (!hsdevp->llit[i]) { + dev_err(ap->dev, "%s: dma_alloc_coherent failed\n", + __func__); + err = -ENOMEM; + goto CLEANUP; + } + } + + if (ap->port_no == 0) { + dev_dbg(ap->dev, "%s: clearing TXCHEN, RXCHEN in DMAC\n", + __func__); + out_le32(&hsdev->sata_dwc_regs->dmacr, + SATA_DWC_DMACR_TXRXCH_CLEAR); + + dev_dbg(ap->dev, "%s: setting burst size in DBTSR\n", + __func__); + out_le32(&hsdev->sata_dwc_regs->dbtsr, + (SATA_DWC_DBTSR_MWR(AHB_DMA_BRST_DFLT) | + SATA_DWC_DBTSR_MRD(AHB_DMA_BRST_DFLT))); + } + + /* Clear any error bits before libata starts issuing commands */ + clear_serror(); + ap->private_data = hsdevp; + +CLEANUP: + if (err) { + sata_dwc_port_stop(ap); + dev_dbg(ap->dev, "%s: fail\n", __func__); + } else { + dev_dbg(ap->dev, "%s: done\n", __func__); + } + + return err; +} + +static void sata_dwc_port_stop(struct ata_port *ap) +{ + int i; + struct sata_dwc_device *hsdev = HSDEV_FROM_AP(ap); + struct sata_dwc_device_port *hsdevp = HSDEVP_FROM_AP(ap); + + dev_dbg(ap->dev, "%s: ap->id = %d\n", __func__, ap->print_id); + + if (hsdevp && hsdev) { + /* deallocate LLI table */ + for (i = 0; i < SATA_DWC_QCMD_MAX; i++) { + dma_free_coherent(ap->host->dev, + SATA_DWC_DMAC_LLI_TBL_SZ, + hsdevp->llit[i], hsdevp->llit_dma[i]); + } + + kfree(hsdevp); + } + ap->private_data = NULL; +} + +/* + * Function : sata_dwc_exec_command_by_tag + * arguments : ata_port *ap, ata_taskfile *tf, u8 tag, u32 cmd_issued + * Return value : None + * This function keeps track of individual command tag ids and calls + * ata_exec_command in libata + */ +static void sata_dwc_exec_command_by_tag(struct ata_port *ap, + struct ata_taskfile *tf, + u8 tag, u32 cmd_issued) +{ + unsigned long flags; + struct sata_dwc_device_port *hsdevp = HSDEVP_FROM_AP(ap); + + dev_dbg(ap->dev, "%s cmd(0x%02x): %s tag=%d\n", __func__, tf->command, + ata_get_cmd_descript(tf), tag); + + spin_lock_irqsave(&ap->host->lock, flags); + hsdevp->cmd_issued[tag] = cmd_issued; + spin_unlock_irqrestore(&ap->host->lock, flags); + /* + * Clear SError before executing a new command. + * sata_dwc_scr_write and read can not be used here. Clearing the PM + * managed SError register for the disk needs to be done before the + * task file is loaded. + */ + clear_serror(); + ata_sff_exec_command(ap, tf); +} + +static void sata_dwc_bmdma_setup_by_tag(struct ata_queued_cmd *qc, u8 tag) +{ + sata_dwc_exec_command_by_tag(qc->ap, &qc->tf, tag, + SATA_DWC_CMD_ISSUED_PEND); +} + +static void sata_dwc_bmdma_setup(struct ata_queued_cmd *qc) +{ + u8 tag = qc->tag; + + if (ata_is_ncq(qc->tf.protocol)) { + dev_dbg(qc->ap->dev, "%s: ap->link.sactive=0x%08x tag=%d\n", + __func__, qc->ap->link.sactive, tag); + } else { + tag = 0; + } + sata_dwc_bmdma_setup_by_tag(qc, tag); +} + +static void sata_dwc_bmdma_start_by_tag(struct ata_queued_cmd *qc, u8 tag) +{ + int start_dma; + u32 reg, dma_chan; + struct sata_dwc_device *hsdev = HSDEV_FROM_QC(qc); + struct ata_port *ap = qc->ap; + struct sata_dwc_device_port *hsdevp = HSDEVP_FROM_AP(ap); + int dir = qc->dma_dir; + dma_chan = hsdevp->dma_chan[tag]; + + if (hsdevp->cmd_issued[tag] != SATA_DWC_CMD_ISSUED_NOT) { + start_dma = 1; + if (dir == DMA_TO_DEVICE) + hsdevp->dma_pending[tag] = SATA_DWC_DMA_PENDING_TX; + else + hsdevp->dma_pending[tag] = SATA_DWC_DMA_PENDING_RX; + } else { + dev_err(ap->dev, "%s: Command not pending cmd_issued=%d " + "(tag=%d) DMA NOT started\n", __func__, + hsdevp->cmd_issued[tag], tag); + start_dma = 0; + } + + dev_dbg(ap->dev, "%s qc=%p tag: %x cmd: 0x%02x dma_dir: %s " + "start_dma? %x\n", __func__, qc, tag, qc->tf.command, + ata_get_cmd_descript(qc->dma_dir), start_dma); + sata_dwc_tf_dump(&(qc->tf)); + + if (start_dma) { + reg = core_scr_read(SCR_ERROR); + if (reg & SATA_DWC_SERROR_ERR_BITS) { + dev_err(ap->dev, "%s: ****** SError=0x%08x ******\n", + __func__, reg); + } + + if (dir == DMA_TO_DEVICE) + out_le32(&hsdev->sata_dwc_regs->dmacr, + SATA_DWC_DMACR_TXCHEN); + else + out_le32(&hsdev->sata_dwc_regs->dmacr, + SATA_DWC_DMACR_RXCHEN); + + /* Enable AHB DMA transfer on the specified channel */ + dma_dwc_xfer_start(dma_chan); + } +} + +static void sata_dwc_bmdma_start(struct ata_queued_cmd *qc) +{ + u8 tag = qc->tag; + + if (ata_is_ncq(qc->tf.protocol)) { + dev_dbg(qc->ap->dev, "%s: ap->link.sactive=0x%08x tag=%d\n", + __func__, qc->ap->link.sactive, tag); + } else { + tag = 0; + } + dev_dbg(qc->ap->dev, "%s\n", __func__); + sata_dwc_bmdma_start_by_tag(qc, tag); +} + +/* + * Function : sata_dwc_qc_prep_by_tag + * arguments : ata_queued_cmd *qc, u8 tag + * Return value : None + * qc_prep for a particular queued command based on tag + */ +static void sata_dwc_qc_prep_by_tag(struct ata_queued_cmd *qc, u8 tag) +{ + struct scatterlist *sg = qc->sg; + struct ata_port *ap = qc->ap; + u32 dma_chan; + struct sata_dwc_device *hsdev = HSDEV_FROM_AP(ap); + struct sata_dwc_device_port *hsdevp = HSDEVP_FROM_AP(ap); + int err; + + dev_dbg(ap->dev, "%s: port=%d dma dir=%s n_elem=%d\n", + __func__, ap->port_no, ata_get_cmd_descript(qc->dma_dir), + qc->n_elem); + + dma_chan = dma_dwc_xfer_setup(sg, qc->n_elem, hsdevp->llit[tag], + hsdevp->llit_dma[tag], + (void *__iomem)(&hsdev->sata_dwc_regs->\ + dmadr), qc->dma_dir); + if (dma_chan < 0) { + dev_err(ap->dev, "%s: dma_dwc_xfer_setup returns err %d\n", + __func__, err); + return; + } + hsdevp->dma_chan[tag] = dma_chan; +} + +static unsigned int sata_dwc_qc_issue(struct ata_queued_cmd *qc) +{ + u32 sactive; + u8 tag = qc->tag; + struct ata_port *ap = qc->ap; + +#ifdef DEBUG_NCQ + if (qc->tag > 0 || ap->link.sactive > 1) + dev_info(ap->dev, "%s ap id=%d cmd(0x%02x)=%s qc tag=%d " + "prot=%s ap active_tag=0x%08x ap sactive=0x%08x\n", + __func__, ap->print_id, qc->tf.command, + ata_get_cmd_descript(&qc->tf), + qc->tag, ata_get_cmd_descript(qc->tf.protocol), + ap->link.active_tag, ap->link.sactive); +#endif + + if (!ata_is_ncq(qc->tf.protocol)) + tag = 0; + sata_dwc_qc_prep_by_tag(qc, tag); + + if (ata_is_ncq(qc->tf.protocol)) { + sactive = core_scr_read(SCR_ACTIVE); + sactive |= (0x00000001 << tag); + core_scr_write(SCR_ACTIVE, sactive); + + dev_dbg(qc->ap->dev, "%s: tag=%d ap->link.sactive = 0x%08x " + "sactive=0x%08x\n", __func__, tag, qc->ap->link.sactive, + sactive); + + ap->ops->sff_tf_load(ap, &qc->tf); + sata_dwc_exec_command_by_tag(ap, &qc->tf, qc->tag, + SATA_DWC_CMD_ISSUED_PEND); + } else { + ata_sff_qc_issue(qc); + } + return 0; +} + +/* + * Function : sata_dwc_qc_prep + * arguments : ata_queued_cmd *qc + * Return value : None + * qc_prep for a particular queued command + */ + +static void sata_dwc_qc_prep(struct ata_queued_cmd *qc) +{ + if ((qc->dma_dir == DMA_NONE) || (qc->tf.protocol == ATA_PROT_PIO)) + return; + +#ifdef DEBUG_NCQ + if (qc->tag > 0) + dev_info(qc->ap->dev, "%s: qc->tag=%d ap->active_tag=0x%08x\n", + __func__, tag, qc->ap->link.active_tag); + + return ; +#endif +} + +static void sata_dwc_error_handler(struct ata_port *ap) +{ + ap->link.flags |= ATA_LFLAG_NO_HRST; + ata_sff_error_handler(ap); +} + +/* + * scsi mid-layer and libata interface structures + */ +static struct scsi_host_template sata_dwc_sht = { + ATA_NCQ_SHT(DRV_NAME), + /* + * test-only: Currently this driver doesn't handle NCQ + * correctly. We enable NCQ but set the queue depth to a + * max of 1. This will get fixed in in a future release. + */ + .sg_tablesize = LIBATA_MAX_PRD, + .can_queue = ATA_DEF_QUEUE, /* ATA_MAX_QUEUE */ + .dma_boundary = ATA_DMA_BOUNDARY, +}; + +static struct ata_port_operations sata_dwc_ops = { + .inherits = &ata_sff_port_ops, + + .error_handler = sata_dwc_error_handler, + + .qc_prep = sata_dwc_qc_prep, + .qc_issue = sata_dwc_qc_issue, + + .scr_read = sata_dwc_scr_read, + .scr_write = sata_dwc_scr_write, + + .port_start = sata_dwc_port_start, + .port_stop = sata_dwc_port_stop, + + .bmdma_setup = sata_dwc_bmdma_setup, + .bmdma_start = sata_dwc_bmdma_start, +}; + +static const struct ata_port_info sata_dwc_port_info[] = { + { + .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | + ATA_FLAG_MMIO | ATA_FLAG_NCQ, + .pio_mask = 0x1f, /* pio 0-4 */ + .udma_mask = ATA_UDMA6, + .port_ops = &sata_dwc_ops, + }, +}; + +static int sata_dwc_probe(struct of_device *ofdev, + const struct of_device_id *match) +{ + struct sata_dwc_device *hsdev; + u32 idr, versionr; + char *ver = (char *)&versionr; + u8 *base = NULL; + int err = 0; + int irq, rc; + struct ata_host *host; + struct ata_port_info pi = sata_dwc_port_info[0]; + const struct ata_port_info *ppi[] = { &pi, NULL }; + + /* Allocate DWC SATA device */ + hsdev = kmalloc(sizeof(*hsdev), GFP_KERNEL); + if (hsdev == NULL) { + dev_err(&ofdev->dev, "kmalloc failed for hsdev\n"); + err = -ENOMEM; + goto error_out; + } + memset(hsdev, 0, sizeof(*hsdev)); + + /* Ioremap SATA registers */ + base = of_iomap(ofdev->dev.of_node, 0); + if (!base) { + dev_err(&ofdev->dev, "ioremap failed for SATA register" + " address\n"); + err = -ENODEV; + goto error_out; + } + hsdev->reg_base = base; + dev_dbg(&ofdev->dev, "ioremap done for SATA register address\n"); + + /* Synopsys DWC SATA specific Registers */ + hsdev->sata_dwc_regs = (void *__iomem)(base + SATA_DWC_REG_OFFSET); + + /* Allocate and fill host */ + host = ata_host_alloc_pinfo(&ofdev->dev, ppi, SATA_DWC_MAX_PORTS); + if (!host) { + dev_err(&ofdev->dev, "ata_host_alloc_pinfo failed\n"); + err = -ENOMEM; + goto error_out; + } + + host->private_data = hsdev; + + /* Setup port */ + host->ports[0]->ioaddr.cmd_addr = base; + host->ports[0]->ioaddr.scr_addr = base + SATA_DWC_SCR_OFFSET; + host_pvt.scr_addr_sstatus = base + SATA_DWC_SCR_OFFSET; + sata_dwc_setup_port(&host->ports[0]->ioaddr, (unsigned long)base); + + /* Read the ID and Version Registers */ + idr = in_le32(&hsdev->sata_dwc_regs->idr); + versionr = in_le32(&hsdev->sata_dwc_regs->versionr); + dev_notice(&ofdev->dev, "id %d, controller version %c.%c%c\n", + idr, ver[0], ver[1], ver[2]); + + /* Get SATA DMA interrupt number */ + irq = irq_of_parse_and_map(ofdev->dev.of_node, 1); + if (irq == NO_IRQ) { + dev_err(&ofdev->dev, "no SATA DMA irq\n"); + err = -ENODEV; + goto error_out; + } + + /* Get physical SATA DMA register base address */ + host_pvt.sata_dma_regs = of_iomap(ofdev->dev.of_node, 1); + if (!(host_pvt.sata_dma_regs)) { + dev_err(&ofdev->dev, "ioremap failed for AHBDMA register" + " address\n"); + err = -ENODEV; + goto error_out; + } + + /* Save dev for later use in dev_xxx() routines */ + host_pvt.dwc_dev = &ofdev->dev; + + /* Initialize AHB DMAC */ + dma_dwc_init(hsdev, irq); + + /* Enable SATA Interrupts */ + sata_dwc_enable_interrupts(hsdev); + + /* Get SATA interrupt number */ + irq = irq_of_parse_and_map(ofdev->dev.of_node, 0); + if (irq == NO_IRQ) { + dev_err(&ofdev->dev, "no SATA DMA irq\n"); + err = -ENODEV; + goto error_out; + } + + /* + * Now, register with libATA core, this will also initiate the + * device discovery process, invoking our port_start() handler & + * error_handler() to execute a dummy Softreset EH session + */ + rc = ata_host_activate(host, irq, sata_dwc_isr, 0, &sata_dwc_sht); + + if (rc != 0) + dev_err(&ofdev->dev, "failed to activate host"); + + dev_set_drvdata(&ofdev->dev, host); + return 0; + +error_out: + /* Free SATA DMA resources */ + dma_dwc_exit(hsdev); + + if (base) + iounmap(base); + return err; +} + +static int sata_dwc_remove(struct of_device *ofdev) +{ + struct device *dev = &ofdev->dev; + struct ata_host *host = dev_get_drvdata(dev); + struct sata_dwc_device *hsdev = host->private_data; + + ata_host_detach(host); + dev_set_drvdata(dev, NULL); + + /* Free SATA DMA resources */ + dma_dwc_exit(hsdev); + + iounmap(hsdev->reg_base); + kfree(hsdev); + kfree(host); + dev_dbg(&ofdev->dev, "done\n"); + return 0; +} + +static const struct of_device_id sata_dwc_match[] = { + { .compatible = "amcc,sata-460ex", }, + {} +}; +MODULE_DEVICE_TABLE(of, sata_dwc_match); + +static struct of_platform_driver sata_dwc_driver = { + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + .of_match_table = sata_dwc_match, + }, + .probe = sata_dwc_probe, + .remove = sata_dwc_remove, +}; + +static int __init sata_dwc_init(void) +{ + return of_register_platform_driver(&sata_dwc_driver); +} + +static void __exit sata_dwc_exit(void) +{ + of_unregister_platform_driver(&sata_dwc_driver); +} + +module_init(sata_dwc_init); +module_exit(sata_dwc_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Mark Miesfeld <mmiesfeld@amcc.com>"); +MODULE_DESCRIPTION("DesignWare Cores SATA controller low lever driver"); +MODULE_VERSION(DRV_VERSION); diff --git a/drivers/ata/sata_fsl.c b/drivers/ata/sata_fsl.c index 61c89b5..18c986d 100644 --- a/drivers/ata/sata_fsl.c +++ b/drivers/ata/sata_fsl.c @@ -1096,7 +1096,7 @@ static void sata_fsl_host_intr(struct ata_port *ap) { struct sata_fsl_host_priv *host_priv = ap->host->private_data; void __iomem *hcr_base = host_priv->hcr_base; - u32 hstatus, qc_active = 0; + u32 hstatus, done_mask = 0; struct ata_queued_cmd *qc; u32 SError; @@ -1116,28 +1116,28 @@ static void sata_fsl_host_intr(struct ata_port *ap) } /* Read command completed register */ - qc_active = ioread32(hcr_base + CC); + done_mask = ioread32(hcr_base + CC); VPRINTK("Status of all queues :\n"); - VPRINTK("qc_active/CC = 0x%x, CA = 0x%x, CE=0x%x,CQ=0x%x,apqa=0x%x\n", - qc_active, + VPRINTK("done_mask/CC = 0x%x, CA = 0x%x, CE=0x%x,CQ=0x%x,apqa=0x%x\n", + done_mask, ioread32(hcr_base + CA), ioread32(hcr_base + CE), ioread32(hcr_base + CQ), ap->qc_active); - if (qc_active & ap->qc_active) { + if (done_mask & ap->qc_active) { int i; /* clear CC bit, this will also complete the interrupt */ - iowrite32(qc_active, hcr_base + CC); + iowrite32(done_mask, hcr_base + CC); DPRINTK("Status of all queues :\n"); - DPRINTK("qc_active/CC = 0x%x, CA = 0x%x, CE=0x%x\n", - qc_active, ioread32(hcr_base + CA), + DPRINTK("done_mask/CC = 0x%x, CA = 0x%x, CE=0x%x\n", + done_mask, ioread32(hcr_base + CA), ioread32(hcr_base + CE)); for (i = 0; i < SATA_FSL_QUEUE_DEPTH; i++) { - if (qc_active & (1 << i)) { + if (done_mask & (1 << i)) { qc = ata_qc_from_tag(ap, i); if (qc) { ata_qc_complete(qc); @@ -1164,7 +1164,7 @@ static void sata_fsl_host_intr(struct ata_port *ap) /* Spurious Interrupt!! */ DPRINTK("spurious interrupt!!, CC = 0x%x\n", ioread32(hcr_base + CC)); - iowrite32(qc_active, hcr_base + CC); + iowrite32(done_mask, hcr_base + CC); return; } } diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index a476cd9..9463c71 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c @@ -2716,34 +2716,35 @@ static void mv_err_intr(struct ata_port *ap) static void mv_process_crpb_response(struct ata_port *ap, struct mv_crpb *response, unsigned int tag, int ncq_enabled) { + u8 ata_status; + u16 edma_status = le16_to_cpu(response->flags); struct ata_queued_cmd *qc = ata_qc_from_tag(ap, tag); - if (qc) { - u8 ata_status; - u16 edma_status = le16_to_cpu(response->flags); - /* - * edma_status from a response queue entry: - * LSB is from EDMA_ERR_IRQ_CAUSE (non-NCQ only). - * MSB is saved ATA status from command completion. - */ - if (!ncq_enabled) { - u8 err_cause = edma_status & 0xff & ~EDMA_ERR_DEV; - if (err_cause) { - /* - * Error will be seen/handled by mv_err_intr(). - * So do nothing at all here. - */ - return; - } - } - ata_status = edma_status >> CRPB_FLAG_STATUS_SHIFT; - if (!ac_err_mask(ata_status)) - ata_qc_complete(qc); - /* else: leave it for mv_err_intr() */ - } else { + if (unlikely(!qc)) { ata_port_printk(ap, KERN_ERR, "%s: no qc for tag=%d\n", __func__, tag); + return; + } + + /* + * edma_status from a response queue entry: + * LSB is from EDMA_ERR_IRQ_CAUSE (non-NCQ only). + * MSB is saved ATA status from command completion. + */ + if (!ncq_enabled) { + u8 err_cause = edma_status & 0xff & ~EDMA_ERR_DEV; + if (err_cause) { + /* + * Error will be seen/handled by + * mv_err_intr(). So do nothing at all here. + */ + return; + } } + ata_status = edma_status >> CRPB_FLAG_STATUS_SHIFT; + if (!ac_err_mask(ata_status)) + ata_qc_complete(qc); + /* else: leave it for mv_err_intr() */ } static void mv_process_crpb_entries(struct ata_port *ap, struct mv_port_priv *pp) diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c index 2116113..cb89ef8 100644 --- a/drivers/ata/sata_nv.c +++ b/drivers/ata/sata_nv.c @@ -1018,7 +1018,7 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance) NV_ADMA_STAT_CPBERR | NV_ADMA_STAT_CMD_COMPLETE)) { u32 check_commands = notifier_clears[i]; - int pos, error = 0; + int pos, rc; if (status & NV_ADMA_STAT_CPBERR) { /* check all active commands */ @@ -1030,10 +1030,12 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance) } /* check CPBs for completed commands */ - while ((pos = ffs(check_commands)) && !error) { + while ((pos = ffs(check_commands))) { pos--; - error = nv_adma_check_cpb(ap, pos, + rc = nv_adma_check_cpb(ap, pos, notifier_error & (1 << pos)); + if (unlikely(rc)) + check_commands = 0; check_commands &= ~(1 << pos); } } @@ -2129,7 +2131,6 @@ static int nv_swncq_sdbfis(struct ata_port *ap) struct nv_swncq_port_priv *pp = ap->private_data; struct ata_eh_info *ehi = &ap->link.eh_info; u32 sactive; - int nr_done = 0; u32 done_mask; int i; u8 host_stat; @@ -2170,22 +2171,21 @@ static int nv_swncq_sdbfis(struct ata_port *ap) pp->dhfis_bits &= ~(1 << i); pp->dmafis_bits &= ~(1 << i); pp->sdbfis_bits |= (1 << i); - nr_done++; } } if (!ap->qc_active) { DPRINTK("over\n"); nv_swncq_pp_reinit(ap); - return nr_done; + return 0; } if (pp->qc_active & pp->dhfis_bits) - return nr_done; + return 0; if ((pp->ncq_flags & ncq_saw_backout) || (pp->qc_active ^ pp->dhfis_bits)) - /* if the controller cann't get a device to host register FIS, + /* if the controller can't get a device to host register FIS, * The driver needs to reissue the new command. */ lack_dhfis = 1; @@ -2202,7 +2202,7 @@ static int nv_swncq_sdbfis(struct ata_port *ap) if (lack_dhfis) { qc = ata_qc_from_tag(ap, pp->last_issue_tag); nv_swncq_issue_atacmd(ap, qc); - return nr_done; + return 0; } if (pp->defer_queue.defer_bits) { @@ -2212,7 +2212,7 @@ static int nv_swncq_sdbfis(struct ata_port *ap) nv_swncq_issue_atacmd(ap, qc); } - return nr_done; + return 0; } static inline u32 nv_swncq_tag(struct ata_port *ap) @@ -2224,7 +2224,7 @@ static inline u32 nv_swncq_tag(struct ata_port *ap) return (tag & 0x1f); } -static int nv_swncq_dmafis(struct ata_port *ap) +static void nv_swncq_dmafis(struct ata_port *ap) { struct ata_queued_cmd *qc; unsigned int rw; @@ -2239,7 +2239,7 @@ static int nv_swncq_dmafis(struct ata_port *ap) qc = ata_qc_from_tag(ap, tag); if (unlikely(!qc)) - return 0; + return; rw = qc->tf.flags & ATA_TFLAG_WRITE; @@ -2254,8 +2254,6 @@ static int nv_swncq_dmafis(struct ata_port *ap) dmactl |= ATA_DMA_WR; iowrite8(dmactl | ATA_DMA_START, ap->ioaddr.bmdma_addr + ATA_DMA_CMD); - - return 1; } static void nv_swncq_host_interrupt(struct ata_port *ap, u16 fis) @@ -2265,7 +2263,6 @@ static void nv_swncq_host_interrupt(struct ata_port *ap, u16 fis) struct ata_eh_info *ehi = &ap->link.eh_info; u32 serror; u8 ata_stat; - int rc = 0; ata_stat = ap->ops->sff_check_status(ap); nv_swncq_irq_clear(ap, fis); @@ -2310,8 +2307,7 @@ static void nv_swncq_host_interrupt(struct ata_port *ap, u16 fis) "dhfis 0x%X dmafis 0x%X sactive 0x%X\n", ap->print_id, pp->qc_active, pp->dhfis_bits, pp->dmafis_bits, readl(pp->sactive_block)); - rc = nv_swncq_sdbfis(ap); - if (rc < 0) + if (nv_swncq_sdbfis(ap) < 0) goto irq_error; } @@ -2348,7 +2344,7 @@ static void nv_swncq_host_interrupt(struct ata_port *ap, u16 fis) */ pp->dmafis_bits |= (0x1 << nv_swncq_tag(ap)); pp->ncq_flags |= ncq_saw_dmas; - rc = nv_swncq_dmafis(ap); + nv_swncq_dmafis(ap); } irq_exit: diff --git a/drivers/atm/fore200e.c b/drivers/atm/fore200e.c index da8f176..b7385e0 100644 --- a/drivers/atm/fore200e.c +++ b/drivers/atm/fore200e.c @@ -2657,7 +2657,7 @@ static int __devinit fore200e_sba_probe(struct of_device *op, fore200e->bus = bus; fore200e->bus_dev = op; - fore200e->irq = op->irqs[0]; + fore200e->irq = op->archdata.irqs[0]; fore200e->phys_base = op->resource[0].start; sprintf(fore200e->name, "%s-%d", bus->model_name, index); @@ -2795,7 +2795,7 @@ static int __init fore200e_module_init(void) printk(FORE200E "FORE Systems 200E-series ATM driver - version " FORE200E_VERSION "\n"); #ifdef CONFIG_SBUS - err = of_register_driver(&fore200e_sba_driver, &of_bus_type); + err = of_register_platform_driver(&fore200e_sba_driver); if (err) return err; #endif @@ -2806,7 +2806,7 @@ static int __init fore200e_module_init(void) #ifdef CONFIG_SBUS if (err) - of_unregister_driver(&fore200e_sba_driver); + of_unregister_platform_driver(&fore200e_sba_driver); #endif return err; @@ -2818,7 +2818,7 @@ static void __exit fore200e_module_cleanup(void) pci_unregister_driver(&fore200e_pca_driver); #endif #ifdef CONFIG_SBUS - of_unregister_driver(&fore200e_sba_driver); + of_unregister_platform_driver(&fore200e_sba_driver); #endif } diff --git a/drivers/base/platform.c b/drivers/base/platform.c index 1bb8faa..c6c933f 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -12,6 +12,7 @@ #include <linux/string.h> #include <linux/platform_device.h> +#include <linux/of_device.h> #include <linux/module.h> #include <linux/init.h> #include <linux/dma-mapping.h> @@ -583,6 +584,12 @@ static struct device_attribute platform_dev_attrs[] = { static int platform_uevent(struct device *dev, struct kobj_uevent_env *env) { struct platform_device *pdev = to_platform_device(dev); + int rc; + + /* Some devices have extra OF data and an OF-style MODALIAS */ + rc = of_device_uevent(dev,env); + if (rc != -ENODEV) + return rc; add_uevent_var(env, "MODALIAS=%s%s", PLATFORM_MODULE_PREFIX, (pdev->id_entry) ? pdev->id_entry->name : pdev->name); @@ -621,7 +628,11 @@ static int platform_match(struct device *dev, struct device_driver *drv) struct platform_device *pdev = to_platform_device(dev); struct platform_driver *pdrv = to_platform_driver(drv); - /* match against the id table first */ + /* Attempt an OF style match first */ + if (of_driver_match_device(dev, drv)) + return 1; + + /* Then try to match against the id table */ if (pdrv->id_table) return platform_match_id(pdrv->id_table, pdev) != NULL; diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c index 258bc2a..23b7c48 100644 --- a/drivers/block/virtio_blk.c +++ b/drivers/block/virtio_blk.c @@ -225,16 +225,6 @@ static int virtblk_ioctl(struct block_device *bdev, fmode_t mode, struct gendisk *disk = bdev->bd_disk; struct virtio_blk *vblk = disk->private_data; - if (cmd == 0x56424944) { /* 'VBID' */ - void __user *usr_data = (void __user *)data; - char id_str[VIRTIO_BLK_ID_BYTES]; - int err; - - err = virtblk_get_id(disk, id_str); - if (!err && copy_to_user(usr_data, id_str, VIRTIO_BLK_ID_BYTES)) - err = -EFAULT; - return err; - } /* * Only allow the generic SCSI ioctls if the host can support it. */ @@ -281,6 +271,27 @@ static int index_to_minor(int index) return index << PART_BITS; } +static ssize_t virtblk_serial_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct gendisk *disk = dev_to_disk(dev); + int err; + + /* sysfs gives us a PAGE_SIZE buffer */ + BUILD_BUG_ON(PAGE_SIZE < VIRTIO_BLK_ID_BYTES); + + buf[VIRTIO_BLK_ID_BYTES] = '\0'; + err = virtblk_get_id(disk, buf); + if (!err) + return strlen(buf); + + if (err == -EIO) /* Unsupported? Make it empty. */ + return 0; + + return err; +} +DEVICE_ATTR(serial, S_IRUGO, virtblk_serial_show, NULL); + static int __devinit virtblk_probe(struct virtio_device *vdev) { struct virtio_blk *vblk; @@ -366,12 +377,32 @@ static int __devinit virtblk_probe(struct virtio_device *vdev) vblk->disk->driverfs_dev = &vdev->dev; index++; - /* If barriers are supported, tell block layer that queue is ordered */ - if (virtio_has_feature(vdev, VIRTIO_BLK_F_FLUSH)) + if (virtio_has_feature(vdev, VIRTIO_BLK_F_FLUSH)) { + /* + * If the FLUSH feature is supported we do have support for + * flushing a volatile write cache on the host. Use that + * to implement write barrier support. + */ blk_queue_ordered(q, QUEUE_ORDERED_DRAIN_FLUSH, virtblk_prepare_flush); - else if (virtio_has_feature(vdev, VIRTIO_BLK_F_BARRIER)) + } else if (virtio_has_feature(vdev, VIRTIO_BLK_F_BARRIER)) { + /* + * If the BARRIER feature is supported the host expects us + * to order request by tags. This implies there is not + * volatile write cache on the host, and that the host + * never re-orders outstanding I/O. This feature is not + * useful for real life scenarious and deprecated. + */ blk_queue_ordered(q, QUEUE_ORDERED_TAG, NULL); + } else { + /* + * If the FLUSH feature is not supported we must assume that + * the host does not perform any kind of volatile write + * caching. We still need to drain the queue to provider + * proper barrier semantics. + */ + blk_queue_ordered(q, QUEUE_ORDERED_DRAIN, NULL); + } /* If disk is read-only in the host, the guest should obey */ if (virtio_has_feature(vdev, VIRTIO_BLK_F_RO)) @@ -445,8 +476,15 @@ static int __devinit virtblk_probe(struct virtio_device *vdev) add_disk(vblk->disk); + err = device_create_file(disk_to_dev(vblk->disk), &dev_attr_serial); + if (err) + goto out_del_disk; + return 0; +out_del_disk: + del_gendisk(vblk->disk); + blk_cleanup_queue(vblk->disk->queue); out_put_disk: put_disk(vblk->disk); out_mempool: diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index 82ed403..f63ac3d 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c @@ -48,6 +48,7 @@ #include <xen/grant_table.h> #include <xen/events.h> #include <xen/page.h> +#include <xen/platform_pci.h> #include <xen/interface/grant_table.h> #include <xen/interface/io/blkif.h> @@ -737,6 +738,35 @@ static int blkfront_probe(struct xenbus_device *dev, } } + if (xen_hvm_domain()) { + char *type; + int len; + /* no unplug has been done: do not hook devices != xen vbds */ + if (xen_platform_pci_unplug & XEN_UNPLUG_IGNORE) { + int major; + + if (!VDEV_IS_EXTENDED(vdevice)) + major = BLKIF_MAJOR(vdevice); + else + major = XENVBD_MAJOR; + + if (major != XENVBD_MAJOR) { + printk(KERN_INFO + "%s: HVM does not support vbd %d as xen block device\n", + __FUNCTION__, vdevice); + return -ENODEV; + } + } + /* do not create a PV cdrom device if we are an HVM guest */ + type = xenbus_read(XBT_NIL, dev->nodename, "device-type", &len); + if (IS_ERR(type)) + return -ENODEV; + if (strncmp(type, "cdrom", 5) == 0) { + kfree(type); + return -ENODEV; + } + kfree(type); + } info = kzalloc(sizeof(*info), GFP_KERNEL); if (!info) { xenbus_dev_fatal(dev, -ENOMEM, "allocating info structure"); diff --git a/drivers/char/agp/efficeon-agp.c b/drivers/char/agp/efficeon-agp.c index aa109cb..d607f53 100644 --- a/drivers/char/agp/efficeon-agp.c +++ b/drivers/char/agp/efficeon-agp.c @@ -372,6 +372,17 @@ static int __devinit agp_efficeon_probe(struct pci_dev *pdev, bridge->capndx = cap_ptr; /* + * If the device has not been properly setup, the following will catch + * the problem and should stop the system from crashing. + * 20030610 - hamish@zot.org + */ + if (pci_enable_device(pdev)) { + printk(KERN_ERR PFX "Unable to Enable PCI device\n"); + agp_put_bridge(bridge); + return -ENODEV; + } + + /* * The following fixes the case where the BIOS has "forgotten" to * provide an address range for the GART. * 20030610 - hamish@zot.org @@ -385,17 +396,6 @@ static int __devinit agp_efficeon_probe(struct pci_dev *pdev, } } - /* - * If the device has not been properly setup, the following will catch - * the problem and should stop the system from crashing. - * 20030610 - hamish@zot.org - */ - if (pci_enable_device(pdev)) { - printk(KERN_ERR PFX "Unable to Enable PCI device\n"); - agp_put_bridge(bridge); - return -ENODEV; - } - /* Fill in the mode register */ if (cap_ptr) { pci_read_config_dword(pdev, diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c index d836a71..ddf5def 100644 --- a/drivers/char/agp/intel-agp.c +++ b/drivers/char/agp/intel-agp.c @@ -816,9 +816,9 @@ static const struct intel_driver_description { { PCI_DEVICE_ID_INTEL_IRONLAKE_MC2_HB, PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG, "HD Graphics", NULL, &intel_i965_driver }, { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_IG, - "Sandybridge", NULL, &intel_i965_driver }, + "Sandybridge", NULL, &intel_gen6_driver }, { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_IG, - "Sandybridge", NULL, &intel_i965_driver }, + "Sandybridge", NULL, &intel_gen6_driver }, { 0, 0, NULL, NULL, NULL } }; @@ -908,6 +908,17 @@ static int __devinit agp_intel_probe(struct pci_dev *pdev, dev_info(&pdev->dev, "Intel %s Chipset\n", intel_agp_chipsets[i].name); /* + * If the device has not been properly setup, the following will catch + * the problem and should stop the system from crashing. + * 20030610 - hamish@zot.org + */ + if (pci_enable_device(pdev)) { + dev_err(&pdev->dev, "can't enable PCI device\n"); + agp_put_bridge(bridge); + return -ENODEV; + } + + /* * The following fixes the case where the BIOS has "forgotten" to * provide an address range for the GART. * 20030610 - hamish@zot.org @@ -921,17 +932,6 @@ static int __devinit agp_intel_probe(struct pci_dev *pdev, } } - /* - * If the device has not been properly setup, the following will catch - * the problem and should stop the system from crashing. - * 20030610 - hamish@zot.org - */ - if (pci_enable_device(pdev)) { - dev_err(&pdev->dev, "can't enable PCI device\n"); - agp_put_bridge(bridge); - return -ENODEV; - } - /* Fill in the mode register */ if (cap_ptr) { pci_read_config_dword(pdev, diff --git a/drivers/char/agp/intel-agp.h b/drivers/char/agp/intel-agp.h index 2547465..c05e3e5 100644 --- a/drivers/char/agp/intel-agp.h +++ b/drivers/char/agp/intel-agp.h @@ -60,6 +60,12 @@ #define I810_PTE_LOCAL 0x00000002 #define I810_PTE_VALID 0x00000001 #define I830_PTE_SYSTEM_CACHED 0x00000006 +/* GT PTE cache control fields */ +#define GEN6_PTE_UNCACHED 0x00000002 +#define GEN6_PTE_LLC 0x00000004 +#define GEN6_PTE_LLC_MLC 0x00000006 +#define GEN6_PTE_GFDT 0x00000008 + #define I810_SMRAM_MISCC 0x70 #define I810_GFX_MEM_WIN_SIZE 0x00010000 #define I810_GFX_MEM_WIN_32M 0x00010000 diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index a754715..d22ffb8 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -25,6 +25,10 @@ #define USE_PCI_DMA_API 1 #endif +/* Max amount of stolen space, anything above will be returned to Linux */ +int intel_max_stolen = 32 * 1024 * 1024; +EXPORT_SYMBOL(intel_max_stolen); + static const struct aper_size_info_fixed intel_i810_sizes[] = { {64, 16384, 4}, @@ -104,7 +108,7 @@ static int intel_agp_map_memory(struct agp_memory *mem) DBG("try mapping %lu pages\n", (unsigned long)mem->page_count); if (sg_alloc_table(&st, mem->page_count, GFP_KERNEL)) - return -ENOMEM; + goto err; mem->sg_list = sg = st.sgl; @@ -113,11 +117,14 @@ static int intel_agp_map_memory(struct agp_memory *mem) mem->num_sg = pci_map_sg(intel_private.pcidev, mem->sg_list, mem->page_count, PCI_DMA_BIDIRECTIONAL); - if (unlikely(!mem->num_sg)) { - intel_agp_free_sglist(mem); - return -ENOMEM; - } + if (unlikely(!mem->num_sg)) + goto err; + return 0; + +err: + sg_free_table(&st); + return -ENOMEM; } static void intel_agp_unmap_memory(struct agp_memory *mem) @@ -176,7 +183,7 @@ static void intel_agp_insert_sg_entries(struct agp_memory *mem, if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB || agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB) { - cache_bits = I830_PTE_SYSTEM_CACHED; + cache_bits = GEN6_PTE_LLC_MLC; } for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { @@ -710,7 +717,12 @@ static void intel_i830_init_gtt_entries(void) break; } } - if (gtt_entries > 0) { + if (!local && gtt_entries > intel_max_stolen) { + dev_info(&agp_bridge->dev->dev, + "detected %dK stolen memory, trimming to %dK\n", + gtt_entries / KB(1), intel_max_stolen / KB(1)); + gtt_entries = intel_max_stolen / KB(4); + } else if (gtt_entries > 0) { dev_info(&agp_bridge->dev->dev, "detected %dK %s memory\n", gtt_entries / KB(1), local ? "local" : "stolen"); gtt_entries /= KB(4); @@ -797,6 +809,10 @@ static int intel_i830_create_gatt_table(struct agp_bridge_data *bridge) /* we have to call this as early as possible after the MMIO base address is known */ intel_i830_init_gtt_entries(); + if (intel_private.gtt_entries == 0) { + iounmap(intel_private.registers); + return -ENOMEM; + } agp_bridge->gatt_table = NULL; @@ -1282,6 +1298,11 @@ static int intel_i915_create_gatt_table(struct agp_bridge_data *bridge) /* we have to call this as early as possible after the MMIO base address is known */ intel_i830_init_gtt_entries(); + if (intel_private.gtt_entries == 0) { + iounmap(intel_private.gtt); + iounmap(intel_private.registers); + return -ENOMEM; + } agp_bridge->gatt_table = NULL; @@ -1309,6 +1330,16 @@ static unsigned long intel_i965_mask_memory(struct agp_bridge_data *bridge, return addr | bridge->driver->masks[type].mask; } +static unsigned long intel_gen6_mask_memory(struct agp_bridge_data *bridge, + dma_addr_t addr, int type) +{ + /* Shift high bits down */ + addr |= (addr >> 28) & 0xff; + + /* Type checking must be done elsewhere */ + return addr | bridge->driver->masks[type].mask; +} + static void intel_i965_get_gtt_range(int *gtt_offset, int *gtt_size) { u16 snb_gmch_ctl; @@ -1390,6 +1421,11 @@ static int intel_i965_create_gatt_table(struct agp_bridge_data *bridge) /* we have to call this as early as possible after the MMIO base address is known */ intel_i830_init_gtt_entries(); + if (intel_private.gtt_entries == 0) { + iounmap(intel_private.gtt); + iounmap(intel_private.registers); + return -ENOMEM; + } agp_bridge->gatt_table = NULL; @@ -1517,6 +1553,39 @@ static const struct agp_bridge_driver intel_i965_driver = { #endif }; +static const struct agp_bridge_driver intel_gen6_driver = { + .owner = THIS_MODULE, + .aperture_sizes = intel_i830_sizes, + .size_type = FIXED_APER_SIZE, + .num_aperture_sizes = 4, + .needs_scratch_page = true, + .configure = intel_i9xx_configure, + .fetch_size = intel_i9xx_fetch_size, + .cleanup = intel_i915_cleanup, + .mask_memory = intel_gen6_mask_memory, + .masks = intel_i810_masks, + .agp_enable = intel_i810_agp_enable, + .cache_flush = global_cache_flush, + .create_gatt_table = intel_i965_create_gatt_table, + .free_gatt_table = intel_i830_free_gatt_table, + .insert_memory = intel_i915_insert_entries, + .remove_memory = intel_i915_remove_entries, + .alloc_by_type = intel_i830_alloc_by_type, + .free_by_type = intel_i810_free_by_type, + .agp_alloc_page = agp_generic_alloc_page, + .agp_alloc_pages = agp_generic_alloc_pages, + .agp_destroy_page = agp_generic_destroy_page, + .agp_destroy_pages = agp_generic_destroy_pages, + .agp_type_to_mask_type = intel_i830_type_to_mask_type, + .chipset_flush = intel_i915_chipset_flush, +#ifdef USE_PCI_DMA_API + .agp_map_page = intel_agp_map_page, + .agp_unmap_page = intel_agp_unmap_page, + .agp_map_memory = intel_agp_map_memory, + .agp_unmap_memory = intel_agp_unmap_memory, +#endif +}; + static const struct agp_bridge_driver intel_g33_driver = { .owner = THIS_MODULE, .aperture_sizes = intel_i830_sizes, diff --git a/drivers/char/bsr.c b/drivers/char/bsr.c index 89d871e..9191713 100644 --- a/drivers/char/bsr.c +++ b/drivers/char/bsr.c @@ -23,6 +23,7 @@ #include <linux/of.h> #include <linux/of_device.h> #include <linux/of_platform.h> +#include <linux/fs.h> #include <linux/module.h> #include <linux/cdev.h> #include <linux/list.h> diff --git a/drivers/char/hw_random/n2-drv.c b/drivers/char/hw_random/n2-drv.c index 101d5f2..7a4f080 100644 --- a/drivers/char/hw_random/n2-drv.c +++ b/drivers/char/hw_random/n2-drv.c @@ -762,12 +762,12 @@ static struct of_platform_driver n2rng_driver = { static int __init n2rng_init(void) { - return of_register_driver(&n2rng_driver, &of_bus_type); + return of_register_platform_driver(&n2rng_driver); } static void __exit n2rng_exit(void) { - of_unregister_driver(&n2rng_driver); + of_unregister_platform_driver(&n2rng_driver); } module_init(n2rng_init); diff --git a/drivers/char/mem.c b/drivers/char/mem.c index f54dab8..a398ecd 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -916,7 +916,7 @@ static int __init chr_dev_init(void) NULL, devlist[minor].name); } - return 0; + return tty_init(); } fs_initcall(chr_dev_init); diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index d71f0fc..507441a 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -3128,7 +3128,7 @@ static struct cdev tty_cdev, console_cdev; * Ok, now we can initialize the rest of the tty devices and can count * on memory allocations, interrupts etc.. */ -static int __init tty_init(void) +int __init tty_init(void) { cdev_init(&tty_cdev, &tty_fops); if (cdev_add(&tty_cdev, MKDEV(TTYAUX_MAJOR, 0), 1) || @@ -3149,4 +3149,4 @@ static int __init tty_init(void) #endif return 0; } -module_init(tty_init); + diff --git a/drivers/char/vt.c b/drivers/char/vt.c index 7cdb6ee..4a9eb30 100644 --- a/drivers/char/vt.c +++ b/drivers/char/vt.c @@ -104,6 +104,7 @@ #include <linux/io.h> #include <asm/system.h> #include <linux/uaccess.h> +#include <linux/kdb.h> #define MAX_NR_CON_DRIVER 16 @@ -187,10 +188,15 @@ static DECLARE_WORK(console_work, console_callback); * fg_console is the current virtual console, * last_console is the last used one, * want_console is the console we want to switch to, + * saved_* variants are for save/restore around kernel debugger enter/leave */ int fg_console; int last_console; int want_console = -1; +int saved_fg_console; +int saved_last_console; +int saved_want_console; +int saved_vc_mode; /* * For each existing display, we have a pointer to console currently visible @@ -3414,6 +3420,78 @@ int con_is_bound(const struct consw *csw) EXPORT_SYMBOL(con_is_bound); /** + * con_debug_enter - prepare the console for the kernel debugger + * @sw: console driver + * + * Called when the console is taken over by the kernel debugger, this + * function needs to save the current console state, then put the console + * into a state suitable for the kernel debugger. + * + * RETURNS: + * Zero on success, nonzero if a failure occurred when trying to prepare + * the console for the debugger. + */ +int con_debug_enter(struct vc_data *vc) +{ + int ret = 0; + + saved_fg_console = fg_console; + saved_last_console = last_console; + saved_want_console = want_console; + saved_vc_mode = vc->vc_mode; + vc->vc_mode = KD_TEXT; + console_blanked = 0; + if (vc->vc_sw->con_debug_enter) + ret = vc->vc_sw->con_debug_enter(vc); +#ifdef CONFIG_KGDB_KDB + /* Set the initial LINES variable if it is not already set */ + if (vc->vc_rows < 999) { + int linecount; + char lns[4]; + const char *setargs[3] = { + "set", + "LINES", + lns, + }; + if (kdbgetintenv(setargs[0], &linecount)) { + snprintf(lns, 4, "%i", vc->vc_rows); + kdb_set(2, setargs); + } + } +#endif /* CONFIG_KGDB_KDB */ + return ret; +} +EXPORT_SYMBOL_GPL(con_debug_enter); + +/** + * con_debug_leave - restore console state + * @sw: console driver + * + * Restore the console state to what it was before the kernel debugger + * was invoked. + * + * RETURNS: + * Zero on success, nonzero if a failure occurred when trying to restore + * the console. + */ +int con_debug_leave(void) +{ + struct vc_data *vc; + int ret = 0; + + fg_console = saved_fg_console; + last_console = saved_last_console; + want_console = saved_want_console; + vc_cons[fg_console].d->vc_mode = saved_vc_mode; + + vc = vc_cons[fg_console].d; + if (vc->vc_sw->con_debug_leave) + ret = vc->vc_sw->con_debug_leave(vc); + return ret; +} +EXPORT_SYMBOL_GPL(con_debug_leave); + +/** * register_con_driver - register console driver to console layer * @csw: console driver * @first: the first console to take over, minimum value is 0 diff --git a/drivers/crypto/n2_core.c b/drivers/crypto/n2_core.c index b99c38f..26af2dd 100644 --- a/drivers/crypto/n2_core.c +++ b/drivers/crypto/n2_core.c @@ -2247,20 +2247,20 @@ static struct of_platform_driver n2_mau_driver = { static int __init n2_init(void) { - int err = of_register_driver(&n2_crypto_driver, &of_bus_type); + int err = of_register_platform_driver(&n2_crypto_driver); if (!err) { - err = of_register_driver(&n2_mau_driver, &of_bus_type); + err = of_register_platform_driver(&n2_mau_driver); if (err) - of_unregister_driver(&n2_crypto_driver); + of_unregister_platform_driver(&n2_crypto_driver); } return err; } static void __exit n2_exit(void) { - of_unregister_driver(&n2_mau_driver); - of_unregister_driver(&n2_crypto_driver); + of_unregister_platform_driver(&n2_mau_driver); + of_unregister_platform_driver(&n2_crypto_driver); } module_init(n2_init); diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 4e51fe3..6a6bd56 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -8,6 +8,7 @@ #include <linux/debugfs.h> #include <linux/seq_file.h> #include <linux/gpio.h> +#include <linux/of_gpio.h> #include <linux/idr.h> #include <linux/slab.h> @@ -1100,16 +1101,24 @@ int gpiochip_add(struct gpio_chip *chip) } } + of_gpiochip_add(chip); + unlock: spin_unlock_irqrestore(&gpio_lock, flags); - if (status == 0) - status = gpiochip_export(chip); + + if (status) + goto fail; + + status = gpiochip_export(chip); + if (status) + goto fail; + + return 0; fail: /* failures here can mean systems won't boot... */ - if (status) - pr_err("gpiochip_add: gpios %d..%d (%s) failed to register\n", - chip->base, chip->base + chip->ngpio - 1, - chip->label ? : "generic"); + pr_err("gpiochip_add: gpios %d..%d (%s) failed to register\n", + chip->base, chip->base + chip->ngpio - 1, + chip->label ? : "generic"); return status; } EXPORT_SYMBOL_GPL(gpiochip_add); @@ -1128,6 +1137,8 @@ int gpiochip_remove(struct gpio_chip *chip) spin_lock_irqsave(&gpio_lock, flags); + of_gpiochip_remove(chip); + for (id = chip->base; id < chip->base + chip->ngpio; id++) { if (test_bit(FLAG_REQUESTED, &gpio_desc[id].flags)) { status = -EBUSY; @@ -1148,6 +1159,38 @@ int gpiochip_remove(struct gpio_chip *chip) } EXPORT_SYMBOL_GPL(gpiochip_remove); +/** + * gpiochip_find() - iterator for locating a specific gpio_chip + * @data: data to pass to match function + * @callback: Callback function to check gpio_chip + * + * Similar to bus_find_device. It returns a reference to a gpio_chip as + * determined by a user supplied @match callback. The callback should return + * 0 if the device doesn't match and non-zero if it does. If the callback is + * non-zero, this function will return to the caller and not iterate over any + * more gpio_chips. + */ +struct gpio_chip *gpiochip_find(void *data, + int (*match)(struct gpio_chip *chip, void *data)) +{ + struct gpio_chip *chip = NULL; + unsigned long flags; + int i; + + spin_lock_irqsave(&gpio_lock, flags); + for (i = 0; i < ARCH_NR_GPIOS; i++) { + if (!gpio_desc[i].chip) + continue; + + if (match(gpio_desc[i].chip, data)) { + chip = gpio_desc[i].chip; + break; + } + } + spin_unlock_irqrestore(&gpio_lock, flags); + + return chip; +} /* These "optional" allocation calls help prevent drivers from stomping * on each other, and help provide better diagnostics in debugfs. diff --git a/drivers/gpio/xilinx_gpio.c b/drivers/gpio/xilinx_gpio.c index b8fa65b..7096909 100644 --- a/drivers/gpio/xilinx_gpio.c +++ b/drivers/gpio/xilinx_gpio.c @@ -161,14 +161,12 @@ static void xgpio_save_regs(struct of_mm_gpio_chip *mm_gc) static int __devinit xgpio_of_probe(struct device_node *np) { struct xgpio_instance *chip; - struct of_gpio_chip *ofchip; int status = 0; const u32 *tree_info; chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (!chip) return -ENOMEM; - ofchip = &chip->mmchip.of_gc; /* Update GPIO state shadow register with default value */ tree_info = of_get_property(np, "xlnx,dout-default", NULL); @@ -182,21 +180,20 @@ static int __devinit xgpio_of_probe(struct device_node *np) chip->gpio_dir = *tree_info; /* Check device node and parent device node for device width */ - ofchip->gc.ngpio = 32; /* By default assume full GPIO controller */ + chip->mmchip.gc.ngpio = 32; /* By default assume full GPIO controller */ tree_info = of_get_property(np, "xlnx,gpio-width", NULL); if (!tree_info) tree_info = of_get_property(np->parent, "xlnx,gpio-width", NULL); if (tree_info) - ofchip->gc.ngpio = *tree_info; + chip->mmchip.gc.ngpio = *tree_info; spin_lock_init(&chip->gpio_lock); - ofchip->gpio_cells = 2; - ofchip->gc.direction_input = xgpio_dir_in; - ofchip->gc.direction_output = xgpio_dir_out; - ofchip->gc.get = xgpio_get; - ofchip->gc.set = xgpio_set; + chip->mmchip.gc.direction_input = xgpio_dir_in; + chip->mmchip.gc.direction_output = xgpio_dir_out; + chip->mmchip.gc.get = xgpio_get; + chip->mmchip.gc.set = xgpio_set; chip->mmchip.save_regs = xgpio_save_regs; diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index 88910e5..4cab0c6 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -6,7 +6,7 @@ # menuconfig DRM tristate "Direct Rendering Manager (XFree86 4.1.0 and higher DRI support)" - depends on (AGP || AGP=n) && PCI && !EMULATED_CMPXCHG && MMU + depends on (AGP || AGP=n) && !EMULATED_CMPXCHG && MMU select I2C select I2C_ALGOBIT select SLOW_WORK @@ -17,7 +17,7 @@ menuconfig DRM These modules provide support for synchronization, security, and DMA transfers. Please see <http://dri.sourceforge.net/> for more details. You should also select and configure AGP - (/dev/agpgart) support. + (/dev/agpgart) support if it is available for your platform. config DRM_KMS_HELPER tristate @@ -61,6 +61,7 @@ config DRM_RADEON select DRM_KMS_HELPER select DRM_TTM select POWER_SUPPLY + select HWMON help Choose this option if you have an ATI Radeon graphics card. There are both PCI and AGP versions. You don't need to choose this to @@ -130,7 +131,7 @@ endchoice config DRM_MGA tristate "Matrox g200/g400" - depends on DRM + depends on DRM && PCI select FW_LOADER help Choose this option if you have a Matrox G200, G400 or G450 graphics @@ -148,14 +149,14 @@ config DRM_SIS config DRM_VIA tristate "Via unichrome video cards" - depends on DRM + depends on DRM && PCI help Choose this option if you have a Via unichrome or compatible video chipset. If M is selected the module will be called via. config DRM_SAVAGE tristate "Savage video cards" - depends on DRM + depends on DRM && PCI help Choose this option if you have a Savage3D/4/SuperSavage/Pro/Twister chipset. If M is selected the module will be called savage. diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index abe3f44..f3a23a3 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -9,9 +9,10 @@ drm-y := drm_auth.o drm_buffer.o drm_bufs.o drm_cache.o \ drm_drv.o drm_fops.o drm_gem.o drm_ioctl.o drm_irq.o \ drm_lock.o drm_memory.o drm_proc.o drm_stub.o drm_vm.o \ drm_agpsupport.o drm_scatter.o ati_pcigart.o drm_pci.o \ - drm_sysfs.o drm_hashtab.o drm_sman.o drm_mm.o \ + drm_platform.o drm_sysfs.o drm_hashtab.o drm_sman.o drm_mm.o \ drm_crtc.o drm_modes.o drm_edid.o \ - drm_info.o drm_debugfs.o drm_encoder_slave.o + drm_info.o drm_debugfs.o drm_encoder_slave.o \ + drm_trace_points.o drm_global.o drm-$(CONFIG_COMPAT) += drm_ioc32.o @@ -19,6 +20,8 @@ drm_kms_helper-y := drm_fb_helper.o drm_crtc_helper.o drm_dp_i2c_helper.o obj-$(CONFIG_DRM_KMS_HELPER) += drm_kms_helper.o +CFLAGS_drm_trace_points.o := -I$(src) + obj-$(CONFIG_DRM) += drm.o obj-$(CONFIG_DRM_TTM) += ttm/ obj-$(CONFIG_DRM_TDFX) += tdfx/ diff --git a/drivers/gpu/drm/drm_bufs.c b/drivers/gpu/drm/drm_bufs.c index 2092e7b..a5c9ce9 100644 --- a/drivers/gpu/drm/drm_bufs.c +++ b/drivers/gpu/drm/drm_bufs.c @@ -39,19 +39,6 @@ #include <asm/shmparam.h> #include "drmP.h" -resource_size_t drm_get_resource_start(struct drm_device *dev, unsigned int resource) -{ - return pci_resource_start(dev->pdev, resource); -} -EXPORT_SYMBOL(drm_get_resource_start); - -resource_size_t drm_get_resource_len(struct drm_device *dev, unsigned int resource) -{ - return pci_resource_len(dev->pdev, resource); -} - -EXPORT_SYMBOL(drm_get_resource_len); - static struct drm_map_list *drm_find_matching_map(struct drm_device *dev, struct drm_local_map *map) { @@ -189,7 +176,7 @@ static int drm_addmap_core(struct drm_device * dev, resource_size_t offset, switch (map->type) { case _DRM_REGISTERS: case _DRM_FRAME_BUFFER: -#if !defined(__sparc__) && !defined(__alpha__) && !defined(__ia64__) && !defined(__powerpc64__) && !defined(__x86_64__) +#if !defined(__sparc__) && !defined(__alpha__) && !defined(__ia64__) && !defined(__powerpc64__) && !defined(__x86_64__) && !defined(__arm__) if (map->offset + (map->size-1) < map->offset || map->offset < virt_to_phys(high_memory)) { kfree(map); diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 57cea01..4c68f76 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -80,6 +80,7 @@ static struct drm_prop_enum_list drm_dithering_mode_enum_list[] = { { DRM_MODE_DITHERING_OFF, "Off" }, { DRM_MODE_DITHERING_ON, "On" }, + { DRM_MODE_DITHERING_AUTO, "Automatic" }, }; /* @@ -1126,7 +1127,7 @@ int drm_mode_getresources(struct drm_device *dev, void *data, if (file_priv->master->minor->type == DRM_MINOR_CONTROL) { list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - DRM_DEBUG_KMS("CRTC ID is %d\n", crtc->base.id); + DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id); if (put_user(crtc->base.id, crtc_id + copied)) { ret = -EFAULT; goto out; @@ -1154,8 +1155,8 @@ int drm_mode_getresources(struct drm_device *dev, void *data, list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { - DRM_DEBUG_KMS("ENCODER ID is %d\n", - encoder->base.id); + DRM_DEBUG_KMS("[ENCODER:%d:%s]\n", encoder->base.id, + drm_get_encoder_name(encoder)); if (put_user(encoder->base.id, encoder_id + copied)) { ret = -EFAULT; @@ -1185,8 +1186,9 @@ int drm_mode_getresources(struct drm_device *dev, void *data, list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - DRM_DEBUG_KMS("CONNECTOR ID is %d\n", - connector->base.id); + DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", + connector->base.id, + drm_get_connector_name(connector)); if (put_user(connector->base.id, connector_id + copied)) { ret = -EFAULT; @@ -1209,7 +1211,7 @@ int drm_mode_getresources(struct drm_device *dev, void *data, } card_res->count_connectors = connector_count; - DRM_DEBUG_KMS("Counted %d %d %d\n", card_res->count_crtcs, + DRM_DEBUG_KMS("CRTC[%d] CONNECTORS[%d] ENCODERS[%d]\n", card_res->count_crtcs, card_res->count_connectors, card_res->count_encoders); out: @@ -1312,7 +1314,7 @@ int drm_mode_getconnector(struct drm_device *dev, void *data, memset(&u_mode, 0, sizeof(struct drm_mode_modeinfo)); - DRM_DEBUG_KMS("connector id %d:\n", out_resp->connector_id); + DRM_DEBUG_KMS("[CONNECTOR:%d:?]\n", out_resp->connector_id); mutex_lock(&dev->mode_config.mutex); @@ -1493,6 +1495,7 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data, goto out; } crtc = obj_to_crtc(obj); + DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id); if (crtc_req->mode_valid) { /* If we have a mode we need a framebuffer. */ @@ -1569,6 +1572,9 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data, goto out; } connector = obj_to_connector(obj); + DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", + connector->base.id, + drm_get_connector_name(connector)); connector_set[i] = connector; } @@ -1684,6 +1690,7 @@ int drm_mode_addfb(struct drm_device *dev, r->fb_id = fb->base.id; list_add(&fb->filp_head, &file_priv->fbs); + DRM_DEBUG_KMS("[FB:%d]\n", fb->base.id); out: mutex_unlock(&dev->mode_config.mutex); @@ -2610,6 +2617,15 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, goto out; crtc = obj_to_crtc(obj); + if (crtc->fb == NULL) { + /* The framebuffer is currently unbound, presumably + * due to a hotplug event, that userspace has not + * yet discovered. + */ + ret = -EBUSY; + goto out; + } + if (crtc->funcs->page_flip == NULL) goto out; diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index 9b2a541..11fe9c8 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -86,7 +86,8 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector, int count = 0; int mode_flags = 0; - DRM_DEBUG_KMS("%s\n", drm_get_connector_name(connector)); + DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", connector->base.id, + drm_get_connector_name(connector)); /* set all modes to the unverified state */ list_for_each_entry_safe(mode, t, &connector->modes, head) mode->status = MODE_UNVERIFIED; @@ -102,8 +103,8 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector, connector->status = connector->funcs->detect(connector); if (connector->status == connector_status_disconnected) { - DRM_DEBUG_KMS("%s is disconnected\n", - drm_get_connector_name(connector)); + DRM_DEBUG_KMS("[CONNECTOR:%d:%s] disconnected\n", + connector->base.id, drm_get_connector_name(connector)); drm_mode_connector_update_edid_property(connector, NULL); goto prune; } @@ -141,8 +142,8 @@ prune: drm_mode_sort(&connector->modes); - DRM_DEBUG_KMS("Probed modes for %s\n", - drm_get_connector_name(connector)); + DRM_DEBUG_KMS("[CONNECTOR:%d:%s] probed modes :\n", connector->base.id, + drm_get_connector_name(connector)); list_for_each_entry_safe(mode, t, &connector->modes, head) { mode->vrefresh = drm_mode_vrefresh(mode); @@ -201,6 +202,17 @@ bool drm_helper_crtc_in_use(struct drm_crtc *crtc) } EXPORT_SYMBOL(drm_helper_crtc_in_use); +static void +drm_encoder_disable(struct drm_encoder *encoder) +{ + struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private; + + if (encoder_funcs->disable) + (*encoder_funcs->disable)(encoder); + else + (*encoder_funcs->dpms)(encoder, DRM_MODE_DPMS_OFF); +} + /** * drm_helper_disable_unused_functions - disable unused objects * @dev: DRM device @@ -215,7 +227,6 @@ void drm_helper_disable_unused_functions(struct drm_device *dev) { struct drm_encoder *encoder; struct drm_connector *connector; - struct drm_encoder_helper_funcs *encoder_funcs; struct drm_crtc *crtc; list_for_each_entry(connector, &dev->mode_config.connector_list, head) { @@ -226,12 +237,8 @@ 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 (!drm_helper_encoder_in_use(encoder)) { - if (encoder_funcs->disable) - (*encoder_funcs->disable)(encoder); - else - (*encoder_funcs->dpms)(encoder, DRM_MODE_DPMS_OFF); + drm_encoder_disable(encoder); /* disconnector encoder from any connector */ encoder->crtc = NULL; } @@ -241,7 +248,10 @@ void drm_helper_disable_unused_functions(struct drm_device *dev) 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, DRM_MODE_DPMS_OFF); + if (crtc_funcs->disable) + (*crtc_funcs->disable)(crtc); + else + (*crtc_funcs->dpms)(crtc, DRM_MODE_DPMS_OFF); crtc->fb = NULL; } } @@ -292,11 +302,11 @@ drm_crtc_prepare_encoders(struct drm_device *dev) encoder_funcs = encoder->helper_private; /* Disable unused encoders */ if (encoder->crtc == NULL) - (*encoder_funcs->dpms)(encoder, DRM_MODE_DPMS_OFF); + drm_encoder_disable(encoder); /* Disable encoders whose CRTC is about to change */ if (encoder_funcs->get_crtc && encoder->crtc != (*encoder_funcs->get_crtc)(encoder)) - (*encoder_funcs->dpms)(encoder, DRM_MODE_DPMS_OFF); + drm_encoder_disable(encoder); } } @@ -365,6 +375,7 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, if (!(ret = crtc_funcs->mode_fixup(crtc, mode, adjusted_mode))) { goto done; } + DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id); /* Prepare the encoders and CRTCs before setting the mode. */ list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { @@ -392,8 +403,9 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, if (encoder->crtc != crtc) continue; - DRM_DEBUG("%s: set mode %s %x\n", drm_get_encoder_name(encoder), - mode->name, mode->base.id); + DRM_DEBUG_KMS("[ENCODER:%d:%s] set [MODE:%d:%s]\n", + encoder->base.id, drm_get_encoder_name(encoder), + mode->base.id, mode->name); encoder_funcs = encoder->helper_private; encoder_funcs->mode_set(encoder, mode, adjusted_mode); } @@ -469,10 +481,15 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) crtc_funcs = set->crtc->helper_private; - DRM_DEBUG_KMS("crtc: %p %d fb: %p connectors: %p num_connectors:" - " %d (x, y) (%i, %i)\n", - set->crtc, set->crtc->base.id, set->fb, set->connectors, - (int)set->num_connectors, set->x, set->y); + if (set->fb) { + DRM_DEBUG_KMS("[CRTC:%d] [FB:%d] #connectors=%d (x y) (%i %i)\n", + set->crtc->base.id, set->fb->base.id, + (int)set->num_connectors, set->x, set->y); + } else { + DRM_DEBUG_KMS("[CRTC:%d] [NOFB] #connectors=%d (x y) (%i %i)\n", + set->crtc->base.id, (int)set->num_connectors, + set->x, set->y); + } dev = set->crtc->dev; @@ -601,8 +618,14 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) mode_changed = true; connector->encoder->crtc = new_crtc; } - DRM_DEBUG_KMS("setting connector %d crtc to %p\n", - connector->base.id, new_crtc); + if (new_crtc) { + DRM_DEBUG_KMS("[CONNECTOR:%d:%s] to [CRTC:%d]\n", + connector->base.id, drm_get_connector_name(connector), + new_crtc->base.id); + } else { + DRM_DEBUG_KMS("[CONNECTOR:%d:%s] to [NOCRTC]\n", + connector->base.id, drm_get_connector_name(connector)); + } } /* mode_set_base is not a required function */ @@ -620,8 +643,8 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) if (!drm_crtc_helper_set_mode(set->crtc, set->mode, set->x, set->y, old_fb)) { - DRM_ERROR("failed to set mode on crtc %p\n", - set->crtc); + DRM_ERROR("failed to set mode on [CRTC:%d]\n", + set->crtc->base.id); ret = -EINVAL; goto fail; } diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index 4a66201..90288ec 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -243,47 +243,20 @@ int drm_lastclose(struct drm_device * dev) * * Initializes an array of drm_device structures, and attempts to * initialize all available devices, using consecutive minors, registering the - * stubs and initializing the AGP device. + * stubs and initializing the device. * * Expands the \c DRIVER_PREINIT and \c DRIVER_POST_INIT macros before and * after the initialization for driver customization. */ int drm_init(struct drm_driver *driver) { - struct pci_dev *pdev = NULL; - const struct pci_device_id *pid; - int i; - DRM_DEBUG("\n"); - INIT_LIST_HEAD(&driver->device_list); - if (driver->driver_features & DRIVER_MODESET) - return pci_register_driver(&driver->pci_driver); - - /* If not using KMS, fall back to stealth mode manual scanning. */ - for (i = 0; driver->pci_driver.id_table[i].vendor != 0; i++) { - pid = &driver->pci_driver.id_table[i]; - - /* Loop around setting up a DRM device for each PCI device - * matching our ID and device class. If we had the internal - * function that pci_get_subsys and pci_get_class used, we'd - * be able to just pass pid in instead of doing a two-stage - * thing. - */ - pdev = NULL; - while ((pdev = - pci_get_subsys(pid->vendor, pid->device, pid->subvendor, - pid->subdevice, pdev)) != NULL) { - if ((pdev->class & pid->class_mask) != pid->class) - continue; - - /* stealth mode requires a manual probe */ - pci_dev_get(pdev); - drm_get_dev(pdev, pid, driver); - } - } - return 0; + if (driver->driver_features & DRIVER_USE_PLATFORM_DEVICE) + return drm_platform_init(driver); + else + return drm_pci_init(driver); } EXPORT_SYMBOL(drm_init); @@ -315,6 +288,7 @@ static int __init drm_core_init(void) { int ret = -ENOMEM; + drm_global_init(); idr_init(&drm_minors_idr); if (register_chrdev(DRM_MAJOR, "drm", &drm_stub_fops)) @@ -362,6 +336,7 @@ static void __exit drm_core_exit(void) unregister_chrdev(DRM_MAJOR, "drm"); + idr_remove_all(&drm_minors_idr); idr_destroy(&drm_minors_idr); } @@ -506,9 +481,9 @@ long drm_ioctl(struct file *filp, if (ioctl->flags & DRM_UNLOCKED) retcode = func(dev, kdata, file_priv); else { - lock_kernel(); + mutex_lock(&drm_global_mutex); retcode = func(dev, kdata, file_priv); - unlock_kernel(); + mutex_unlock(&drm_global_mutex); } if (cmd & IOC_OUT) { diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 9585e53..dce5c4a 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -282,7 +282,7 @@ drm_do_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter) return block; carp: - dev_warn(&connector->dev->pdev->dev, "%s: EDID block %d invalid.\n", + dev_warn(connector->dev->dev, "%s: EDID block %d invalid.\n", drm_get_connector_name(connector), j); out: @@ -1623,7 +1623,7 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid) return 0; } if (!drm_edid_is_valid(edid)) { - dev_warn(&connector->dev->pdev->dev, "%s: EDID invalid.\n", + dev_warn(connector->dev->dev, "%s: EDID invalid.\n", drm_get_connector_name(connector)); return 0; } diff --git a/drivers/gpu/drm/drm_encoder_slave.c b/drivers/gpu/drm/drm_encoder_slave.c index f018469..d62c064 100644 --- a/drivers/gpu/drm/drm_encoder_slave.c +++ b/drivers/gpu/drm/drm_encoder_slave.c @@ -41,6 +41,9 @@ * &drm_encoder_slave. The @slave_funcs field will be initialized with * the hooks provided by the slave driver. * + * If @info->platform_data is non-NULL it will be used as the initial + * slave config. + * * Returns 0 on success or a negative errno on failure, in particular, * -ENODEV is returned when no matching driver is found. */ @@ -85,6 +88,10 @@ int drm_i2c_encoder_init(struct drm_device *dev, if (err) goto fail_unregister; + if (info->platform_data) + encoder->slave_funcs->set_config(&encoder->base, + info->platform_data); + return 0; fail_unregister: diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 7196620..de82e20 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -241,6 +241,80 @@ static int drm_fb_helper_parse_command_line(struct drm_fb_helper *fb_helper) return 0; } +int drm_fb_helper_debug_enter(struct fb_info *info) +{ + struct drm_fb_helper *helper = info->par; + struct drm_crtc_helper_funcs *funcs; + int i; + + if (list_empty(&kernel_fb_helper_list)) + return false; + + list_for_each_entry(helper, &kernel_fb_helper_list, kernel_fb_list) { + for (i = 0; i < helper->crtc_count; i++) { + struct drm_mode_set *mode_set = + &helper->crtc_info[i].mode_set; + + if (!mode_set->crtc->enabled) + continue; + + funcs = mode_set->crtc->helper_private; + funcs->mode_set_base_atomic(mode_set->crtc, + mode_set->fb, + mode_set->x, + mode_set->y); + + } + } + + return 0; +} +EXPORT_SYMBOL(drm_fb_helper_debug_enter); + +/* Find the real fb for a given fb helper CRTC */ +static struct drm_framebuffer *drm_mode_config_fb(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct drm_crtc *c; + + list_for_each_entry(c, &dev->mode_config.crtc_list, head) { + if (crtc->base.id == c->base.id) + return c->fb; + } + + return NULL; +} + +int drm_fb_helper_debug_leave(struct fb_info *info) +{ + struct drm_fb_helper *helper = info->par; + struct drm_crtc *crtc; + struct drm_crtc_helper_funcs *funcs; + struct drm_framebuffer *fb; + int i; + + for (i = 0; i < helper->crtc_count; i++) { + struct drm_mode_set *mode_set = &helper->crtc_info[i].mode_set; + crtc = mode_set->crtc; + funcs = crtc->helper_private; + fb = drm_mode_config_fb(crtc); + + if (!crtc->enabled) + continue; + + if (!fb) { + DRM_ERROR("no fb to restore??\n"); + continue; + } + + funcs->mode_set_base_atomic(mode_set->crtc, fb, crtc->x, + crtc->y); + } + + return 0; +} +EXPORT_SYMBOL(drm_fb_helper_debug_leave); + bool drm_fb_helper_force_kernel_mode(void) { int i = 0; @@ -611,7 +685,7 @@ int drm_fb_helper_check_var(struct fb_var_screeninfo *var, struct drm_framebuffer *fb = fb_helper->fb; int depth; - if (var->pixclock != 0) + if (var->pixclock != 0 || in_dbg_master()) return -EINVAL; /* Need to resize the fb object !!! */ diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c index e7aace2..2ca8df8 100644 --- a/drivers/gpu/drm/drm_fops.c +++ b/drivers/gpu/drm/drm_fops.c @@ -39,6 +39,9 @@ #include <linux/slab.h> #include <linux/smp_lock.h> +/* from BKL pushdown: note that nothing else serializes idr_find() */ +DEFINE_MUTEX(drm_global_mutex); + static int drm_open_helper(struct inode *inode, struct file *filp, struct drm_device * dev); @@ -175,8 +178,7 @@ int drm_stub_open(struct inode *inode, struct file *filp) DRM_DEBUG("\n"); - /* BKL pushdown: note that nothing else serializes idr_find() */ - lock_kernel(); + mutex_lock(&drm_global_mutex); minor = idr_find(&drm_minors_idr, minor_id); if (!minor) goto out; @@ -197,7 +199,7 @@ int drm_stub_open(struct inode *inode, struct file *filp) fops_put(old_fops); out: - unlock_kernel(); + mutex_unlock(&drm_global_mutex); return err; } @@ -472,7 +474,7 @@ int drm_release(struct inode *inode, struct file *filp) struct drm_device *dev = file_priv->minor->dev; int retcode = 0; - lock_kernel(); + mutex_lock(&drm_global_mutex); DRM_DEBUG("open_count = %d\n", dev->open_count); @@ -573,17 +575,14 @@ int drm_release(struct inode *inode, struct file *filp) if (atomic_read(&dev->ioctl_count)) { DRM_ERROR("Device busy: %d\n", atomic_read(&dev->ioctl_count)); - spin_unlock(&dev->count_lock); - unlock_kernel(); - return -EBUSY; + retcode = -EBUSY; + goto out; } - spin_unlock(&dev->count_lock); - unlock_kernel(); - return drm_lastclose(dev); + retcode = drm_lastclose(dev); } +out: spin_unlock(&dev->count_lock); - - unlock_kernel(); + mutex_unlock(&drm_global_mutex); return retcode; } diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c index 33dad3f..4f1b867 100644 --- a/drivers/gpu/drm/drm_gem.c +++ b/drivers/gpu/drm/drm_gem.c @@ -68,8 +68,18 @@ * We make up offsets for buffer objects so we can recognize them at * mmap time. */ + +/* pgoff in mmap is an unsigned long, so we need to make sure that + * the faked up offset will fit + */ + +#if BITS_PER_LONG == 64 #define DRM_FILE_PAGE_OFFSET_START ((0xFFFFFFFFUL >> PAGE_SHIFT) + 1) #define DRM_FILE_PAGE_OFFSET_SIZE ((0xFFFFFFFFUL >> PAGE_SHIFT) * 16) +#else +#define DRM_FILE_PAGE_OFFSET_START ((0xFFFFFFFUL >> PAGE_SHIFT) + 1) +#define DRM_FILE_PAGE_OFFSET_SIZE ((0xFFFFFFFUL >> PAGE_SHIFT) * 16) +#endif /** * Initialize the GEM device fields @@ -419,6 +429,7 @@ drm_gem_release(struct drm_device *dev, struct drm_file *file_private) idr_for_each(&file_private->object_idr, &drm_gem_object_release_handle, NULL); + idr_remove_all(&file_private->object_idr); idr_destroy(&file_private->object_idr); } diff --git a/drivers/gpu/drm/ttm/ttm_global.c b/drivers/gpu/drm/drm_global.c index b170071..c87dc96 100644 --- a/drivers/gpu/drm/ttm/ttm_global.c +++ b/drivers/gpu/drm/drm_global.c @@ -28,45 +28,45 @@ * Authors: Thomas Hellstrom <thellstrom-at-vmware-dot-com> */ -#include "ttm/ttm_module.h" #include <linux/mutex.h> #include <linux/slab.h> #include <linux/module.h> +#include "drm_global.h" -struct ttm_global_item { +struct drm_global_item { struct mutex mutex; void *object; int refcount; }; -static struct ttm_global_item glob[TTM_GLOBAL_NUM]; +static struct drm_global_item glob[DRM_GLOBAL_NUM]; -void ttm_global_init(void) +void drm_global_init(void) { int i; - for (i = 0; i < TTM_GLOBAL_NUM; ++i) { - struct ttm_global_item *item = &glob[i]; + for (i = 0; i < DRM_GLOBAL_NUM; ++i) { + struct drm_global_item *item = &glob[i]; mutex_init(&item->mutex); item->object = NULL; item->refcount = 0; } } -void ttm_global_release(void) +void drm_global_release(void) { int i; - for (i = 0; i < TTM_GLOBAL_NUM; ++i) { - struct ttm_global_item *item = &glob[i]; + for (i = 0; i < DRM_GLOBAL_NUM; ++i) { + struct drm_global_item *item = &glob[i]; BUG_ON(item->object != NULL); BUG_ON(item->refcount != 0); } } -int ttm_global_item_ref(struct ttm_global_reference *ref) +int drm_global_item_ref(struct drm_global_reference *ref) { int ret; - struct ttm_global_item *item = &glob[ref->global_type]; + struct drm_global_item *item = &glob[ref->global_type]; void *object; mutex_lock(&item->mutex); @@ -93,11 +93,11 @@ out_err: item->object = NULL; return ret; } -EXPORT_SYMBOL(ttm_global_item_ref); +EXPORT_SYMBOL(drm_global_item_ref); -void ttm_global_item_unref(struct ttm_global_reference *ref) +void drm_global_item_unref(struct drm_global_reference *ref) { - struct ttm_global_item *item = &glob[ref->global_type]; + struct drm_global_item *item = &glob[ref->global_type]; mutex_lock(&item->mutex); BUG_ON(item->refcount == 0); @@ -108,5 +108,5 @@ void ttm_global_item_unref(struct ttm_global_reference *ref) } mutex_unlock(&item->mutex); } -EXPORT_SYMBOL(ttm_global_item_unref); +EXPORT_SYMBOL(drm_global_item_unref); diff --git a/drivers/gpu/drm/drm_info.c b/drivers/gpu/drm/drm_info.c index f0f6c6b..2ef2c78 100644 --- a/drivers/gpu/drm/drm_info.c +++ b/drivers/gpu/drm/drm_info.c @@ -51,13 +51,24 @@ int drm_name_info(struct seq_file *m, void *data) if (!master) return 0; - if (master->unique) { - seq_printf(m, "%s %s %s\n", - dev->driver->pci_driver.name, - pci_name(dev->pdev), master->unique); + if (drm_core_check_feature(dev, DRIVER_USE_PLATFORM_DEVICE)) { + if (master->unique) { + seq_printf(m, "%s %s %s\n", + dev->driver->platform_device->name, + dev_name(dev->dev), master->unique); + } else { + seq_printf(m, "%s\n", + dev->driver->platform_device->name); + } } else { - seq_printf(m, "%s %s\n", dev->driver->pci_driver.name, - pci_name(dev->pdev)); + if (master->unique) { + seq_printf(m, "%s %s %s\n", + dev->driver->pci_driver.name, + dev_name(dev->dev), master->unique); + } else { + seq_printf(m, "%s %s\n", dev->driver->pci_driver.name, + dev_name(dev->dev)); + } } return 0; diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c index 9b9ff46..7b03b19 100644 --- a/drivers/gpu/drm/drm_ioctl.c +++ b/drivers/gpu/drm/drm_ioctl.c @@ -64,6 +64,19 @@ int drm_getunique(struct drm_device *dev, void *data, return 0; } +static void +drm_unset_busid(struct drm_device *dev, + struct drm_master *master) +{ + kfree(dev->devname); + dev->devname = NULL; + + kfree(master->unique); + master->unique = NULL; + master->unique_len = 0; + master->unique_size = 0; +} + /** * Set the bus id. * @@ -94,17 +107,24 @@ int drm_setunique(struct drm_device *dev, void *data, master->unique_len = u->unique_len; master->unique_size = u->unique_len + 1; master->unique = kmalloc(master->unique_size, GFP_KERNEL); - if (!master->unique) - return -ENOMEM; - if (copy_from_user(master->unique, u->unique, master->unique_len)) - return -EFAULT; + if (!master->unique) { + ret = -ENOMEM; + goto err; + } + + if (copy_from_user(master->unique, u->unique, master->unique_len)) { + ret = -EFAULT; + goto err; + } master->unique[master->unique_len] = '\0'; dev->devname = kmalloc(strlen(dev->driver->pci_driver.name) + strlen(master->unique) + 2, GFP_KERNEL); - if (!dev->devname) - return -ENOMEM; + if (!dev->devname) { + ret = -ENOMEM; + goto err; + } sprintf(dev->devname, "%s@%s", dev->driver->pci_driver.name, master->unique); @@ -113,53 +133,103 @@ int drm_setunique(struct drm_device *dev, void *data, * busid. */ ret = sscanf(master->unique, "PCI:%d:%d:%d", &bus, &slot, &func); - if (ret != 3) - return -EINVAL; + if (ret != 3) { + ret = -EINVAL; + goto err; + } + domain = bus >> 8; bus &= 0xff; if ((domain != drm_get_pci_domain(dev)) || (bus != dev->pdev->bus->number) || (slot != PCI_SLOT(dev->pdev->devfn)) || - (func != PCI_FUNC(dev->pdev->devfn))) - return -EINVAL; + (func != PCI_FUNC(dev->pdev->devfn))) { + ret = -EINVAL; + goto err; + } return 0; + +err: + drm_unset_busid(dev, master); + return ret; } static int drm_set_busid(struct drm_device *dev, struct drm_file *file_priv) { struct drm_master *master = file_priv->master; - int len; + int len, ret; if (master->unique != NULL) - return -EBUSY; + drm_unset_busid(dev, master); - master->unique_len = 40; - master->unique_size = master->unique_len; - master->unique = kmalloc(master->unique_size, GFP_KERNEL); - if (master->unique == NULL) - return -ENOMEM; - - len = snprintf(master->unique, master->unique_len, "pci:%04x:%02x:%02x.%d", - drm_get_pci_domain(dev), - dev->pdev->bus->number, - PCI_SLOT(dev->pdev->devfn), - PCI_FUNC(dev->pdev->devfn)); - if (len >= master->unique_len) - DRM_ERROR("buffer overflow"); - else - master->unique_len = len; + if (drm_core_check_feature(dev, DRIVER_USE_PLATFORM_DEVICE)) { + master->unique_len = 10 + strlen(dev->platformdev->name); + master->unique = kmalloc(master->unique_len + 1, GFP_KERNEL); - dev->devname = kmalloc(strlen(dev->driver->pci_driver.name) + - master->unique_len + 2, GFP_KERNEL); - if (dev->devname == NULL) - return -ENOMEM; + if (master->unique == NULL) + return -ENOMEM; - sprintf(dev->devname, "%s@%s", dev->driver->pci_driver.name, - master->unique); + len = snprintf(master->unique, master->unique_len, + "platform:%s", dev->platformdev->name); + + if (len > master->unique_len) { + DRM_ERROR("Unique buffer overflowed\n"); + ret = -EINVAL; + goto err; + } + + dev->devname = + kmalloc(strlen(dev->platformdev->name) + + master->unique_len + 2, GFP_KERNEL); + + if (dev->devname == NULL) { + ret = -ENOMEM; + goto err; + } + + sprintf(dev->devname, "%s@%s", dev->platformdev->name, + master->unique); + + } else { + master->unique_len = 40; + master->unique_size = master->unique_len; + master->unique = kmalloc(master->unique_size, GFP_KERNEL); + if (master->unique == NULL) + return -ENOMEM; + + len = snprintf(master->unique, master->unique_len, + "pci:%04x:%02x:%02x.%d", + drm_get_pci_domain(dev), + dev->pdev->bus->number, + PCI_SLOT(dev->pdev->devfn), + PCI_FUNC(dev->pdev->devfn)); + if (len >= master->unique_len) { + DRM_ERROR("buffer overflow"); + ret = -EINVAL; + goto err; + } else + master->unique_len = len; + + dev->devname = + kmalloc(strlen(dev->driver->pci_driver.name) + + master->unique_len + 2, GFP_KERNEL); + + if (dev->devname == NULL) { + ret = -ENOMEM; + goto err; + } + + sprintf(dev->devname, "%s@%s", dev->driver->pci_driver.name, + master->unique); + } return 0; + +err: + drm_unset_busid(dev, master); + return ret; } /** @@ -323,7 +393,9 @@ int drm_setversion(struct drm_device *dev, void *data, struct drm_file *file_pri /* * Version 1.1 includes tying of DRM to specific device */ - drm_set_busid(dev, file_priv); + retcode = drm_set_busid(dev, file_priv); + if (retcode) + goto done; } } diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index a263b70..9d3a503 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -34,6 +34,7 @@ */ #include "drmP.h" +#include "drm_trace.h" #include <linux/interrupt.h> /* For task queue support */ #include <linux/slab.h> @@ -57,6 +58,9 @@ int drm_irq_by_busid(struct drm_device *dev, void *data, { struct drm_irq_busid *p = data; + if (drm_core_check_feature(dev, DRIVER_USE_PLATFORM_DEVICE)) + return -EINVAL; + if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ)) return -EINVAL; @@ -211,7 +215,7 @@ int drm_irq_install(struct drm_device *dev) if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ)) return -EINVAL; - if (dev->pdev->irq == 0) + if (drm_dev_to_irq(dev) == 0) return -EINVAL; mutex_lock(&dev->struct_mutex); @@ -229,7 +233,7 @@ int drm_irq_install(struct drm_device *dev) dev->irq_enabled = 1; mutex_unlock(&dev->struct_mutex); - DRM_DEBUG("irq=%d\n", dev->pdev->irq); + DRM_DEBUG("irq=%d\n", drm_dev_to_irq(dev)); /* Before installing handler */ dev->driver->irq_preinstall(dev); @@ -302,14 +306,14 @@ int drm_irq_uninstall(struct drm_device * dev) if (!irq_enabled) return -EINVAL; - DRM_DEBUG("irq=%d\n", dev->pdev->irq); + DRM_DEBUG("irq=%d\n", drm_dev_to_irq(dev)); if (!drm_core_check_feature(dev, DRIVER_MODESET)) vga_client_register(dev->pdev, NULL, NULL, NULL); dev->driver->irq_uninstall(dev); - free_irq(dev->pdev->irq, dev); + free_irq(drm_dev_to_irq(dev), dev); return 0; } @@ -341,7 +345,7 @@ int drm_control(struct drm_device *dev, void *data, if (drm_core_check_feature(dev, DRIVER_MODESET)) return 0; if (dev->if_version < DRM_IF_VERSION(1, 2) && - ctl->irq != dev->pdev->irq) + ctl->irq != drm_dev_to_irq(dev)) return -EINVAL; return drm_irq_install(dev); case DRM_UNINST_HANDLER: @@ -587,6 +591,7 @@ static int drm_queue_vblank_event(struct drm_device *dev, int pipe, return -ENOMEM; e->pipe = pipe; + e->base.pid = current->pid; e->event.base.type = DRM_EVENT_VBLANK; e->event.base.length = sizeof e->event; e->event.user_data = vblwait->request.signal; @@ -614,6 +619,9 @@ static int drm_queue_vblank_event(struct drm_device *dev, int pipe, DRM_DEBUG("event on vblank count %d, current %d, crtc %d\n", vblwait->request.sequence, seq, pipe); + trace_drm_vblank_event_queued(current->pid, pipe, + vblwait->request.sequence); + e->event.sequence = vblwait->request.sequence; if ((seq - vblwait->request.sequence) <= (1 << 23)) { e->event.tv_sec = now.tv_sec; @@ -621,6 +629,8 @@ static int drm_queue_vblank_event(struct drm_device *dev, int pipe, drm_vblank_put(dev, e->pipe); list_add_tail(&e->base.link, &e->base.file_priv->event_list); wake_up_interruptible(&e->base.file_priv->event_wait); + trace_drm_vblank_event_delivered(current->pid, pipe, + vblwait->request.sequence); } else { list_add_tail(&e->base.link, &dev->vblank_event_list); } @@ -651,7 +661,7 @@ int drm_wait_vblank(struct drm_device *dev, void *data, int ret = 0; unsigned int flags, seq, crtc; - if ((!dev->pdev->irq) || (!dev->irq_enabled)) + if ((!drm_dev_to_irq(dev)) || (!dev->irq_enabled)) return -EINVAL; if (vblwait->request.type & _DRM_VBLANK_SIGNAL) @@ -751,9 +761,13 @@ void drm_handle_vblank_events(struct drm_device *dev, int crtc) drm_vblank_put(dev, e->pipe); list_move_tail(&e->base.link, &e->base.file_priv->event_list); wake_up_interruptible(&e->base.file_priv->event_wait); + trace_drm_vblank_event_delivered(e->base.pid, e->pipe, + e->event.sequence); } spin_unlock_irqrestore(&dev->event_lock, flags); + + trace_drm_vblank_event(crtc, seq); } /** diff --git a/drivers/gpu/drm/drm_mm.c b/drivers/gpu/drm/drm_mm.c index 2ac074c8..da99edc 100644 --- a/drivers/gpu/drm/drm_mm.c +++ b/drivers/gpu/drm/drm_mm.c @@ -48,44 +48,14 @@ #define MM_UNUSED_TARGET 4 -unsigned long drm_mm_tail_space(struct drm_mm *mm) -{ - struct list_head *tail_node; - struct drm_mm_node *entry; - - tail_node = mm->ml_entry.prev; - entry = list_entry(tail_node, struct drm_mm_node, ml_entry); - if (!entry->free) - return 0; - - return entry->size; -} - -int drm_mm_remove_space_from_tail(struct drm_mm *mm, unsigned long size) -{ - struct list_head *tail_node; - struct drm_mm_node *entry; - - tail_node = mm->ml_entry.prev; - entry = list_entry(tail_node, struct drm_mm_node, ml_entry); - if (!entry->free) - return -ENOMEM; - - if (entry->size <= size) - return -ENOMEM; - - entry->size -= size; - return 0; -} - static struct drm_mm_node *drm_mm_kmalloc(struct drm_mm *mm, int atomic) { struct drm_mm_node *child; if (atomic) - child = kmalloc(sizeof(*child), GFP_ATOMIC); + child = kzalloc(sizeof(*child), GFP_ATOMIC); else - child = kmalloc(sizeof(*child), GFP_KERNEL); + child = kzalloc(sizeof(*child), GFP_KERNEL); if (unlikely(child == NULL)) { spin_lock(&mm->unused_lock); @@ -94,8 +64,8 @@ static struct drm_mm_node *drm_mm_kmalloc(struct drm_mm *mm, int atomic) else { child = list_entry(mm->unused_nodes.next, - struct drm_mm_node, fl_entry); - list_del(&child->fl_entry); + struct drm_mm_node, free_stack); + list_del(&child->free_stack); --mm->num_unused; } spin_unlock(&mm->unused_lock); @@ -115,7 +85,7 @@ int drm_mm_pre_get(struct drm_mm *mm) spin_lock(&mm->unused_lock); while (mm->num_unused < MM_UNUSED_TARGET) { spin_unlock(&mm->unused_lock); - node = kmalloc(sizeof(*node), GFP_KERNEL); + node = kzalloc(sizeof(*node), GFP_KERNEL); spin_lock(&mm->unused_lock); if (unlikely(node == NULL)) { @@ -124,7 +94,7 @@ int drm_mm_pre_get(struct drm_mm *mm) return ret; } ++mm->num_unused; - list_add_tail(&node->fl_entry, &mm->unused_nodes); + list_add_tail(&node->free_stack, &mm->unused_nodes); } spin_unlock(&mm->unused_lock); return 0; @@ -146,27 +116,12 @@ static int drm_mm_create_tail_node(struct drm_mm *mm, child->start = start; child->mm = mm; - list_add_tail(&child->ml_entry, &mm->ml_entry); - list_add_tail(&child->fl_entry, &mm->fl_entry); + list_add_tail(&child->node_list, &mm->node_list); + list_add_tail(&child->free_stack, &mm->free_stack); return 0; } -int drm_mm_add_space_to_tail(struct drm_mm *mm, unsigned long size, int atomic) -{ - struct list_head *tail_node; - struct drm_mm_node *entry; - - tail_node = mm->ml_entry.prev; - entry = list_entry(tail_node, struct drm_mm_node, ml_entry); - if (!entry->free) { - return drm_mm_create_tail_node(mm, entry->start + entry->size, - size, atomic); - } - entry->size += size; - return 0; -} - static struct drm_mm_node *drm_mm_split_at_start(struct drm_mm_node *parent, unsigned long size, int atomic) @@ -177,15 +132,14 @@ static struct drm_mm_node *drm_mm_split_at_start(struct drm_mm_node *parent, if (unlikely(child == NULL)) return NULL; - INIT_LIST_HEAD(&child->fl_entry); + INIT_LIST_HEAD(&child->free_stack); - child->free = 0; child->size = size; child->start = parent->start; child->mm = parent->mm; - list_add_tail(&child->ml_entry, &parent->ml_entry); - INIT_LIST_HEAD(&child->fl_entry); + list_add_tail(&child->node_list, &parent->node_list); + INIT_LIST_HEAD(&child->free_stack); parent->size -= size; parent->start += size; @@ -213,7 +167,7 @@ struct drm_mm_node *drm_mm_get_block_generic(struct drm_mm_node *node, } if (node->size == size) { - list_del_init(&node->fl_entry); + list_del_init(&node->free_stack); node->free = 0; } else { node = drm_mm_split_at_start(node, size, atomic); @@ -251,7 +205,7 @@ struct drm_mm_node *drm_mm_get_block_range_generic(struct drm_mm_node *node, } if (node->size == size) { - list_del_init(&node->fl_entry); + list_del_init(&node->free_stack); node->free = 0; } else { node = drm_mm_split_at_start(node, size, atomic); @@ -273,16 +227,19 @@ void drm_mm_put_block(struct drm_mm_node *cur) { struct drm_mm *mm = cur->mm; - struct list_head *cur_head = &cur->ml_entry; - struct list_head *root_head = &mm->ml_entry; + struct list_head *cur_head = &cur->node_list; + struct list_head *root_head = &mm->node_list; struct drm_mm_node *prev_node = NULL; struct drm_mm_node *next_node; int merged = 0; + BUG_ON(cur->scanned_block || cur->scanned_prev_free + || cur->scanned_next_free); + if (cur_head->prev != root_head) { prev_node = - list_entry(cur_head->prev, struct drm_mm_node, ml_entry); + list_entry(cur_head->prev, struct drm_mm_node, node_list); if (prev_node->free) { prev_node->size += cur->size; merged = 1; @@ -290,15 +247,15 @@ void drm_mm_put_block(struct drm_mm_node *cur) } if (cur_head->next != root_head) { next_node = - list_entry(cur_head->next, struct drm_mm_node, ml_entry); + list_entry(cur_head->next, struct drm_mm_node, node_list); if (next_node->free) { if (merged) { prev_node->size += next_node->size; - list_del(&next_node->ml_entry); - list_del(&next_node->fl_entry); + list_del(&next_node->node_list); + list_del(&next_node->free_stack); spin_lock(&mm->unused_lock); if (mm->num_unused < MM_UNUSED_TARGET) { - list_add(&next_node->fl_entry, + list_add(&next_node->free_stack, &mm->unused_nodes); ++mm->num_unused; } else @@ -313,12 +270,12 @@ void drm_mm_put_block(struct drm_mm_node *cur) } if (!merged) { cur->free = 1; - list_add(&cur->fl_entry, &mm->fl_entry); + list_add(&cur->free_stack, &mm->free_stack); } else { - list_del(&cur->ml_entry); + list_del(&cur->node_list); spin_lock(&mm->unused_lock); if (mm->num_unused < MM_UNUSED_TARGET) { - list_add(&cur->fl_entry, &mm->unused_nodes); + list_add(&cur->free_stack, &mm->unused_nodes); ++mm->num_unused; } else kfree(cur); @@ -328,40 +285,50 @@ void drm_mm_put_block(struct drm_mm_node *cur) EXPORT_SYMBOL(drm_mm_put_block); +static int check_free_mm_node(struct drm_mm_node *entry, unsigned long size, + unsigned alignment) +{ + unsigned wasted = 0; + + if (entry->size < size) + return 0; + + if (alignment) { + register unsigned tmp = entry->start % alignment; + if (tmp) + wasted = alignment - tmp; + } + + if (entry->size >= size + wasted) { + return 1; + } + + return 0; +} + struct drm_mm_node *drm_mm_search_free(const struct drm_mm *mm, unsigned long size, unsigned alignment, int best_match) { - struct list_head *list; - const struct list_head *free_stack = &mm->fl_entry; struct drm_mm_node *entry; struct drm_mm_node *best; unsigned long best_size; - unsigned wasted; + + BUG_ON(mm->scanned_blocks); best = NULL; best_size = ~0UL; - list_for_each(list, free_stack) { - entry = list_entry(list, struct drm_mm_node, fl_entry); - wasted = 0; - - if (entry->size < size) + list_for_each_entry(entry, &mm->free_stack, free_stack) { + if (!check_free_mm_node(entry, size, alignment)) continue; - if (alignment) { - register unsigned tmp = entry->start % alignment; - if (tmp) - wasted += alignment - tmp; - } + if (!best_match) + return entry; - if (entry->size >= size + wasted) { - if (!best_match) - return entry; - if (entry->size < best_size) { - best = entry; - best_size = entry->size; - } + if (entry->size < best_size) { + best = entry; + best_size = entry->size; } } @@ -376,43 +343,28 @@ struct drm_mm_node *drm_mm_search_free_in_range(const struct drm_mm *mm, unsigned long end, int best_match) { - struct list_head *list; - const struct list_head *free_stack = &mm->fl_entry; struct drm_mm_node *entry; struct drm_mm_node *best; unsigned long best_size; - unsigned wasted; + + BUG_ON(mm->scanned_blocks); best = NULL; best_size = ~0UL; - list_for_each(list, free_stack) { - entry = list_entry(list, struct drm_mm_node, fl_entry); - wasted = 0; - - if (entry->size < size) - continue; - + list_for_each_entry(entry, &mm->free_stack, free_stack) { if (entry->start > end || (entry->start+entry->size) < start) continue; - if (entry->start < start) - wasted += start - entry->start; + if (!check_free_mm_node(entry, size, alignment)) + continue; - if (alignment) { - register unsigned tmp = (entry->start + wasted) % alignment; - if (tmp) - wasted += alignment - tmp; - } + if (!best_match) + return entry; - if (entry->size >= size + wasted && - (entry->start + wasted + size) <= end) { - if (!best_match) - return entry; - if (entry->size < best_size) { - best = entry; - best_size = entry->size; - } + if (entry->size < best_size) { + best = entry; + best_size = entry->size; } } @@ -420,9 +372,161 @@ struct drm_mm_node *drm_mm_search_free_in_range(const struct drm_mm *mm, } EXPORT_SYMBOL(drm_mm_search_free_in_range); +/** + * Initializa lru scanning. + * + * This simply sets up the scanning routines with the parameters for the desired + * hole. + * + * Warning: As long as the scan list is non-empty, no other operations than + * adding/removing nodes to/from the scan list are allowed. + */ +void drm_mm_init_scan(struct drm_mm *mm, unsigned long size, + unsigned alignment) +{ + mm->scan_alignment = alignment; + mm->scan_size = size; + mm->scanned_blocks = 0; + mm->scan_hit_start = 0; + mm->scan_hit_size = 0; +} +EXPORT_SYMBOL(drm_mm_init_scan); + +/** + * Add a node to the scan list that might be freed to make space for the desired + * hole. + * + * Returns non-zero, if a hole has been found, zero otherwise. + */ +int drm_mm_scan_add_block(struct drm_mm_node *node) +{ + struct drm_mm *mm = node->mm; + struct list_head *prev_free, *next_free; + struct drm_mm_node *prev_node, *next_node; + + mm->scanned_blocks++; + + prev_free = next_free = NULL; + + BUG_ON(node->free); + node->scanned_block = 1; + node->free = 1; + + if (node->node_list.prev != &mm->node_list) { + prev_node = list_entry(node->node_list.prev, struct drm_mm_node, + node_list); + + if (prev_node->free) { + list_del(&prev_node->node_list); + + node->start = prev_node->start; + node->size += prev_node->size; + + prev_node->scanned_prev_free = 1; + + prev_free = &prev_node->free_stack; + } + } + + if (node->node_list.next != &mm->node_list) { + next_node = list_entry(node->node_list.next, struct drm_mm_node, + node_list); + + if (next_node->free) { + list_del(&next_node->node_list); + + node->size += next_node->size; + + next_node->scanned_next_free = 1; + + next_free = &next_node->free_stack; + } + } + + /* The free_stack list is not used for allocated objects, so these two + * pointers can be abused (as long as no allocations in this memory + * manager happens). */ + node->free_stack.prev = prev_free; + node->free_stack.next = next_free; + + if (check_free_mm_node(node, mm->scan_size, mm->scan_alignment)) { + mm->scan_hit_start = node->start; + mm->scan_hit_size = node->size; + + return 1; + } + + return 0; +} +EXPORT_SYMBOL(drm_mm_scan_add_block); + +/** + * Remove a node from the scan list. + * + * Nodes _must_ be removed in the exact same order from the scan list as they + * have been added, otherwise the internal state of the memory manager will be + * corrupted. + * + * When the scan list is empty, the selected memory nodes can be freed. An + * immediatly following drm_mm_search_free with best_match = 0 will then return + * the just freed block (because its at the top of the free_stack list). + * + * Returns one if this block should be evicted, zero otherwise. Will always + * return zero when no hole has been found. + */ +int drm_mm_scan_remove_block(struct drm_mm_node *node) +{ + struct drm_mm *mm = node->mm; + struct drm_mm_node *prev_node, *next_node; + + mm->scanned_blocks--; + + BUG_ON(!node->scanned_block); + node->scanned_block = 0; + node->free = 0; + + prev_node = list_entry(node->free_stack.prev, struct drm_mm_node, + free_stack); + next_node = list_entry(node->free_stack.next, struct drm_mm_node, + free_stack); + + if (prev_node) { + BUG_ON(!prev_node->scanned_prev_free); + prev_node->scanned_prev_free = 0; + + list_add_tail(&prev_node->node_list, &node->node_list); + + node->start = prev_node->start + prev_node->size; + node->size -= prev_node->size; + } + + if (next_node) { + BUG_ON(!next_node->scanned_next_free); + next_node->scanned_next_free = 0; + + list_add(&next_node->node_list, &node->node_list); + + node->size -= next_node->size; + } + + INIT_LIST_HEAD(&node->free_stack); + + /* Only need to check for containement because start&size for the + * complete resulting free block (not just the desired part) is + * stored. */ + if (node->start >= mm->scan_hit_start && + node->start + node->size + <= mm->scan_hit_start + mm->scan_hit_size) { + return 1; + } + + return 0; +} +EXPORT_SYMBOL(drm_mm_scan_remove_block); + int drm_mm_clean(struct drm_mm * mm) { - struct list_head *head = &mm->ml_entry; + struct list_head *head = &mm->node_list; return (head->next->next == head); } @@ -430,10 +534,11 @@ EXPORT_SYMBOL(drm_mm_clean); int drm_mm_init(struct drm_mm * mm, unsigned long start, unsigned long size) { - INIT_LIST_HEAD(&mm->ml_entry); - INIT_LIST_HEAD(&mm->fl_entry); + INIT_LIST_HEAD(&mm->node_list); + INIT_LIST_HEAD(&mm->free_stack); INIT_LIST_HEAD(&mm->unused_nodes); mm->num_unused = 0; + mm->scanned_blocks = 0; spin_lock_init(&mm->unused_lock); return drm_mm_create_tail_node(mm, start, size, 0); @@ -442,25 +547,25 @@ EXPORT_SYMBOL(drm_mm_init); void drm_mm_takedown(struct drm_mm * mm) { - struct list_head *bnode = mm->fl_entry.next; + struct list_head *bnode = mm->free_stack.next; struct drm_mm_node *entry; struct drm_mm_node *next; - entry = list_entry(bnode, struct drm_mm_node, fl_entry); + entry = list_entry(bnode, struct drm_mm_node, free_stack); - if (entry->ml_entry.next != &mm->ml_entry || - entry->fl_entry.next != &mm->fl_entry) { + if (entry->node_list.next != &mm->node_list || + entry->free_stack.next != &mm->free_stack) { DRM_ERROR("Memory manager not clean. Delaying takedown\n"); return; } - list_del(&entry->fl_entry); - list_del(&entry->ml_entry); + list_del(&entry->free_stack); + list_del(&entry->node_list); kfree(entry); spin_lock(&mm->unused_lock); - list_for_each_entry_safe(entry, next, &mm->unused_nodes, fl_entry) { - list_del(&entry->fl_entry); + list_for_each_entry_safe(entry, next, &mm->unused_nodes, free_stack) { + list_del(&entry->free_stack); kfree(entry); --mm->num_unused; } @@ -475,7 +580,7 @@ void drm_mm_debug_table(struct drm_mm *mm, const char *prefix) struct drm_mm_node *entry; int total_used = 0, total_free = 0, total = 0; - list_for_each_entry(entry, &mm->ml_entry, ml_entry) { + list_for_each_entry(entry, &mm->node_list, node_list) { printk(KERN_DEBUG "%s 0x%08lx-0x%08lx: %8ld: %s\n", prefix, entry->start, entry->start + entry->size, entry->size, entry->free ? "free" : "used"); @@ -496,7 +601,7 @@ int drm_mm_dump_table(struct seq_file *m, struct drm_mm *mm) struct drm_mm_node *entry; int total_used = 0, total_free = 0, total = 0; - list_for_each_entry(entry, &mm->ml_entry, ml_entry) { + list_for_each_entry(entry, &mm->node_list, node_list) { seq_printf(m, "0x%08lx-0x%08lx: 0x%08lx: %s\n", entry->start, entry->start + entry->size, entry->size, entry->free ? "free" : "used"); total += entry->size; if (entry->free) diff --git a/drivers/gpu/drm/drm_pci.c b/drivers/gpu/drm/drm_pci.c index 2ea9ad4..e20f78b 100644 --- a/drivers/gpu/drm/drm_pci.c +++ b/drivers/gpu/drm/drm_pci.c @@ -124,4 +124,147 @@ void drm_pci_free(struct drm_device * dev, drm_dma_handle_t * dmah) EXPORT_SYMBOL(drm_pci_free); +#ifdef CONFIG_PCI +/** + * Register. + * + * \param pdev - PCI device structure + * \param ent entry from the PCI ID table with device type flags + * \return zero on success or a negative number on failure. + * + * Attempt to gets inter module "drm" information. If we are first + * then register the character device and inter module information. + * Try and register, if we fail to register, backout previous work. + */ +int drm_get_pci_dev(struct pci_dev *pdev, const struct pci_device_id *ent, + struct drm_driver *driver) +{ + struct drm_device *dev; + int ret; + + DRM_DEBUG("\n"); + + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) + return -ENOMEM; + + ret = pci_enable_device(pdev); + if (ret) + goto err_g1; + + pci_set_master(pdev); + + dev->pdev = pdev; + dev->dev = &pdev->dev; + + dev->pci_device = pdev->device; + dev->pci_vendor = pdev->vendor; + +#ifdef __alpha__ + dev->hose = pdev->sysdata; +#endif + + if ((ret = drm_fill_in_dev(dev, ent, driver))) { + printk(KERN_ERR "DRM: Fill_in_dev failed.\n"); + goto err_g2; + } + + if (drm_core_check_feature(dev, DRIVER_MODESET)) { + pci_set_drvdata(pdev, dev); + ret = drm_get_minor(dev, &dev->control, DRM_MINOR_CONTROL); + if (ret) + goto err_g2; + } + + if ((ret = drm_get_minor(dev, &dev->primary, DRM_MINOR_LEGACY))) + goto err_g3; + + if (dev->driver->load) { + ret = dev->driver->load(dev, ent->driver_data); + if (ret) + goto err_g4; + } + + /* setup the grouping for the legacy output */ + if (drm_core_check_feature(dev, DRIVER_MODESET)) { + ret = drm_mode_group_init_legacy_group(dev, + &dev->primary->mode_group); + if (ret) + goto err_g4; + } + + list_add_tail(&dev->driver_item, &driver->device_list); + + DRM_INFO("Initialized %s %d.%d.%d %s for %s on minor %d\n", + driver->name, driver->major, driver->minor, driver->patchlevel, + driver->date, pci_name(pdev), dev->primary->index); + + return 0; + +err_g4: + drm_put_minor(&dev->primary); +err_g3: + if (drm_core_check_feature(dev, DRIVER_MODESET)) + drm_put_minor(&dev->control); +err_g2: + pci_disable_device(pdev); +err_g1: + kfree(dev); + return ret; +} +EXPORT_SYMBOL(drm_get_pci_dev); + +/** + * PCI device initialization. Called via drm_init at module load time, + * + * \return zero on success or a negative number on failure. + * + * Initializes a drm_device structures,registering the + * stubs and initializing the AGP device. + * + * Expands the \c DRIVER_PREINIT and \c DRIVER_POST_INIT macros before and + * after the initialization for driver customization. + */ +int drm_pci_init(struct drm_driver *driver) +{ + struct pci_dev *pdev = NULL; + const struct pci_device_id *pid; + int i; + + if (driver->driver_features & DRIVER_MODESET) + return pci_register_driver(&driver->pci_driver); + + /* If not using KMS, fall back to stealth mode manual scanning. */ + for (i = 0; driver->pci_driver.id_table[i].vendor != 0; i++) { + pid = &driver->pci_driver.id_table[i]; + + /* Loop around setting up a DRM device for each PCI device + * matching our ID and device class. If we had the internal + * function that pci_get_subsys and pci_get_class used, we'd + * be able to just pass pid in instead of doing a two-stage + * thing. + */ + pdev = NULL; + while ((pdev = + pci_get_subsys(pid->vendor, pid->device, pid->subvendor, + pid->subdevice, pdev)) != NULL) { + if ((pdev->class & pid->class_mask) != pid->class) + continue; + + /* stealth mode requires a manual probe */ + pci_dev_get(pdev); + drm_get_pci_dev(pdev, pid, driver); + } + } + return 0; +} + +#else + +int drm_pci_init(struct drm_driver *driver) +{ + return -1; +} + +#endif /*@}*/ diff --git a/drivers/gpu/drm/drm_platform.c b/drivers/gpu/drm/drm_platform.c new file mode 100644 index 0000000..460e9a3 --- /dev/null +++ b/drivers/gpu/drm/drm_platform.c @@ -0,0 +1,122 @@ +/* + * Derived from drm_pci.c + * + * Copyright 2003 José Fonseca. + * Copyright 2003 Leif Delgass. + * Copyright (c) 2009, Code Aurora Forum. + * 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 + * AUTHORS 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 "drmP.h" + +/** + * Register. + * + * \param platdev - Platform device struture + * \return zero on success or a negative number on failure. + * + * Attempt to gets inter module "drm" information. If we are first + * then register the character device and inter module information. + * Try and register, if we fail to register, backout previous work. + */ + +int drm_get_platform_dev(struct platform_device *platdev, + struct drm_driver *driver) +{ + struct drm_device *dev; + int ret; + + DRM_DEBUG("\n"); + + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) + return -ENOMEM; + + dev->platformdev = platdev; + dev->dev = &platdev->dev; + + ret = drm_fill_in_dev(dev, NULL, driver); + + if (ret) { + printk(KERN_ERR "DRM: Fill_in_dev failed.\n"); + goto err_g1; + } + + if (drm_core_check_feature(dev, DRIVER_MODESET)) { + dev_set_drvdata(&platdev->dev, dev); + ret = drm_get_minor(dev, &dev->control, DRM_MINOR_CONTROL); + if (ret) + goto err_g1; + } + + ret = drm_get_minor(dev, &dev->primary, DRM_MINOR_LEGACY); + if (ret) + goto err_g2; + + if (dev->driver->load) { + ret = dev->driver->load(dev, 0); + if (ret) + goto err_g3; + } + + /* setup the grouping for the legacy output */ + if (drm_core_check_feature(dev, DRIVER_MODESET)) { + ret = drm_mode_group_init_legacy_group(dev, + &dev->primary->mode_group); + if (ret) + goto err_g3; + } + + list_add_tail(&dev->driver_item, &driver->device_list); + + DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n", + driver->name, driver->major, driver->minor, driver->patchlevel, + driver->date, dev->primary->index); + + return 0; + +err_g3: + drm_put_minor(&dev->primary); +err_g2: + if (drm_core_check_feature(dev, DRIVER_MODESET)) + drm_put_minor(&dev->control); +err_g1: + kfree(dev); + return ret; +} +EXPORT_SYMBOL(drm_get_platform_dev); + +/** + * Platform device initialization. Called via drm_init at module load time, + * + * \return zero on success or a negative number on failure. + * + * Initializes a drm_device structures,registering the + * stubs + * + * Expands the \c DRIVER_PREINIT and \c DRIVER_POST_INIT macros before and + * after the initialization for driver customization. + */ + +int drm_platform_init(struct drm_driver *driver) +{ + return drm_get_platform_dev(driver->platform_device, driver); +} diff --git a/drivers/gpu/drm/drm_stub.c b/drivers/gpu/drm/drm_stub.c index a0c365f..d1ad574 100644 --- a/drivers/gpu/drm/drm_stub.c +++ b/drivers/gpu/drm/drm_stub.c @@ -156,6 +156,9 @@ static void drm_master_destroy(struct kref *kref) master->unique_len = 0; } + kfree(dev->devname); + dev->devname = NULL; + list_for_each_entry_safe(pt, next, &master->magicfree, head) { list_del(&pt->head); drm_ht_remove_item(&master->magiclist, &pt->hash_item); @@ -224,7 +227,7 @@ int drm_dropmaster_ioctl(struct drm_device *dev, void *data, return 0; } -static int drm_fill_in_dev(struct drm_device * dev, struct pci_dev *pdev, +int drm_fill_in_dev(struct drm_device *dev, const struct pci_device_id *ent, struct drm_driver *driver) { @@ -245,14 +248,6 @@ static int drm_fill_in_dev(struct drm_device * dev, struct pci_dev *pdev, idr_init(&dev->drw_idr); - dev->pdev = pdev; - dev->pci_device = pdev->device; - dev->pci_vendor = pdev->vendor; - -#ifdef __alpha__ - dev->hose = pdev->sysdata; -#endif - if (drm_ht_create(&dev->map_hash, 12)) { return -ENOMEM; } @@ -321,7 +316,7 @@ static int drm_fill_in_dev(struct drm_device * dev, struct pci_dev *pdev, * create the proc init entry via proc_init(). This routines assigns * minor numbers to secondary heads of multi-headed cards */ -static int drm_get_minor(struct drm_device *dev, struct drm_minor **minor, int type) +int drm_get_minor(struct drm_device *dev, struct drm_minor **minor, int type) { struct drm_minor *new_minor; int ret; @@ -388,83 +383,6 @@ err_idr: } /** - * Register. - * - * \param pdev - PCI device structure - * \param ent entry from the PCI ID table with device type flags - * \return zero on success or a negative number on failure. - * - * Attempt to gets inter module "drm" information. If we are first - * then register the character device and inter module information. - * Try and register, if we fail to register, backout previous work. - */ -int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent, - struct drm_driver *driver) -{ - struct drm_device *dev; - int ret; - - DRM_DEBUG("\n"); - - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) - return -ENOMEM; - - ret = pci_enable_device(pdev); - if (ret) - goto err_g1; - - pci_set_master(pdev); - if ((ret = drm_fill_in_dev(dev, pdev, ent, driver))) { - printk(KERN_ERR "DRM: Fill_in_dev failed.\n"); - goto err_g2; - } - - if (drm_core_check_feature(dev, DRIVER_MODESET)) { - pci_set_drvdata(pdev, dev); - ret = drm_get_minor(dev, &dev->control, DRM_MINOR_CONTROL); - if (ret) - goto err_g2; - } - - if ((ret = drm_get_minor(dev, &dev->primary, DRM_MINOR_LEGACY))) - goto err_g3; - - if (dev->driver->load) { - ret = dev->driver->load(dev, ent->driver_data); - if (ret) - goto err_g4; - } - - /* setup the grouping for the legacy output */ - if (drm_core_check_feature(dev, DRIVER_MODESET)) { - ret = drm_mode_group_init_legacy_group(dev, &dev->primary->mode_group); - if (ret) - goto err_g4; - } - - list_add_tail(&dev->driver_item, &driver->device_list); - - DRM_INFO("Initialized %s %d.%d.%d %s for %s on minor %d\n", - driver->name, driver->major, driver->minor, driver->patchlevel, - driver->date, pci_name(pdev), dev->primary->index); - - return 0; - -err_g4: - drm_put_minor(&dev->primary); -err_g3: - if (drm_core_check_feature(dev, DRIVER_MODESET)) - drm_put_minor(&dev->control); -err_g2: - pci_disable_device(pdev); -err_g1: - kfree(dev); - return ret; -} -EXPORT_SYMBOL(drm_get_dev); - -/** * Put a secondary minor number. * * \param sec_minor - structure to be released diff --git a/drivers/gpu/drm/drm_sysfs.c b/drivers/gpu/drm/drm_sysfs.c index 101d381..86118a7 100644 --- a/drivers/gpu/drm/drm_sysfs.c +++ b/drivers/gpu/drm/drm_sysfs.c @@ -489,7 +489,8 @@ int drm_sysfs_device_add(struct drm_minor *minor) int err; char *minor_str; - minor->kdev.parent = &minor->dev->pdev->dev; + minor->kdev.parent = minor->dev->dev; + minor->kdev.class = drm_class; minor->kdev.release = drm_sysfs_device_release; minor->kdev.devt = minor->device; diff --git a/drivers/gpu/drm/drm_trace.h b/drivers/gpu/drm/drm_trace.h new file mode 100644 index 0000000..03ea964 --- /dev/null +++ b/drivers/gpu/drm/drm_trace.h @@ -0,0 +1,66 @@ +#if !defined(_DRM_TRACE_H_) || defined(TRACE_HEADER_MULTI_READ) +#define _DRM_TRACE_H_ + +#include <linux/stringify.h> +#include <linux/types.h> +#include <linux/tracepoint.h> + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM drm +#define TRACE_SYSTEM_STRING __stringify(TRACE_SYSTEM) +#define TRACE_INCLUDE_FILE drm_trace + +TRACE_EVENT(drm_vblank_event, + TP_PROTO(int crtc, unsigned int seq), + TP_ARGS(crtc, seq), + TP_STRUCT__entry( + __field(int, crtc) + __field(unsigned int, seq) + ), + TP_fast_assign( + __entry->crtc = crtc; + __entry->seq = seq; + ), + TP_printk("crtc=%d, seq=%d", __entry->crtc, __entry->seq) +); + +TRACE_EVENT(drm_vblank_event_queued, + TP_PROTO(pid_t pid, int crtc, unsigned int seq), + TP_ARGS(pid, crtc, seq), + TP_STRUCT__entry( + __field(pid_t, pid) + __field(int, crtc) + __field(unsigned int, seq) + ), + TP_fast_assign( + __entry->pid = pid; + __entry->crtc = crtc; + __entry->seq = seq; + ), + TP_printk("pid=%d, crtc=%d, seq=%d", __entry->pid, __entry->crtc, \ + __entry->seq) +); + +TRACE_EVENT(drm_vblank_event_delivered, + TP_PROTO(pid_t pid, int crtc, unsigned int seq), + TP_ARGS(pid, crtc, seq), + TP_STRUCT__entry( + __field(pid_t, pid) + __field(int, crtc) + __field(unsigned int, seq) + ), + TP_fast_assign( + __entry->pid = pid; + __entry->crtc = crtc; + __entry->seq = seq; + ), + TP_printk("pid=%d, crtc=%d, seq=%d", __entry->pid, __entry->crtc, \ + __entry->seq) +); + +#endif /* _DRM_TRACE_H_ */ + +/* This part must be outside protection */ +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH . +#include <trace/define_trace.h> diff --git a/drivers/gpu/drm/drm_trace_points.c b/drivers/gpu/drm/drm_trace_points.c new file mode 100644 index 0000000..0d0eb90 --- /dev/null +++ b/drivers/gpu/drm/drm_trace_points.c @@ -0,0 +1,4 @@ +#include "drmP.h" + +#define CREATE_TRACE_POINTS +#include "drm_trace.h" diff --git a/drivers/gpu/drm/drm_vm.c b/drivers/gpu/drm/drm_vm.c index c3b13fb..3778360 100644 --- a/drivers/gpu/drm/drm_vm.c +++ b/drivers/gpu/drm/drm_vm.c @@ -61,7 +61,7 @@ static pgprot_t drm_io_prot(uint32_t map_type, struct vm_area_struct *vma) tmp = pgprot_writecombine(tmp); else tmp = pgprot_noncached(tmp); -#elif defined(__sparc__) +#elif defined(__sparc__) || defined(__arm__) tmp = pgprot_noncached(tmp); #endif return tmp; @@ -601,6 +601,7 @@ int drm_mmap_locked(struct file *filp, struct vm_area_struct *vma) } switch (map->type) { +#if !defined(__arm__) case _DRM_AGP: if (drm_core_has_AGP(dev) && dev->agp->cant_use_aperture) { /* @@ -615,20 +616,31 @@ int drm_mmap_locked(struct file *filp, struct vm_area_struct *vma) break; } /* fall through to _DRM_FRAME_BUFFER... */ +#endif case _DRM_FRAME_BUFFER: case _DRM_REGISTERS: offset = dev->driver->get_reg_ofs(dev); vma->vm_flags |= VM_IO; /* not in core dump */ vma->vm_page_prot = drm_io_prot(map->type, vma); +#if !defined(__arm__) if (io_remap_pfn_range(vma, vma->vm_start, (map->offset + offset) >> PAGE_SHIFT, vma->vm_end - vma->vm_start, vma->vm_page_prot)) return -EAGAIN; +#else + if (remap_pfn_range(vma, vma->vm_start, + (map->offset + offset) >> PAGE_SHIFT, + vma->vm_end - vma->vm_start, + vma->vm_page_prot)) + return -EAGAIN; +#endif + DRM_DEBUG(" Type = %d; start = 0x%lx, end = 0x%lx," " offset = 0x%llx\n", map->type, vma->vm_start, vma->vm_end, (unsigned long long)(map->offset + offset)); + vma->vm_ops = &drm_vm_ops; break; case _DRM_CONSISTENT: diff --git a/drivers/gpu/drm/i2c/Makefile b/drivers/gpu/drm/i2c/Makefile index 6d2abaf..9286256 100644 --- a/drivers/gpu/drm/i2c/Makefile +++ b/drivers/gpu/drm/i2c/Makefile @@ -2,3 +2,6 @@ ccflags-y := -Iinclude/drm ch7006-y := ch7006_drv.o ch7006_mode.o obj-$(CONFIG_DRM_I2C_CH7006) += ch7006.o + +sil164-y := sil164_drv.o +obj-$(CONFIG_DRM_I2C_SIL164) += sil164.o diff --git a/drivers/gpu/drm/i2c/ch7006_drv.c b/drivers/gpu/drm/i2c/ch7006_drv.c index 81681a0..833b35f 100644 --- a/drivers/gpu/drm/i2c/ch7006_drv.c +++ b/drivers/gpu/drm/i2c/ch7006_drv.c @@ -33,7 +33,7 @@ static void ch7006_encoder_set_config(struct drm_encoder *encoder, { struct ch7006_priv *priv = to_ch7006_priv(encoder); - priv->params = params; + priv->params = *(struct ch7006_encoder_params *)params; } static void ch7006_encoder_destroy(struct drm_encoder *encoder) @@ -114,7 +114,7 @@ static void ch7006_encoder_mode_set(struct drm_encoder *encoder, { struct i2c_client *client = drm_i2c_encoder_get_client(encoder); struct ch7006_priv *priv = to_ch7006_priv(encoder); - struct ch7006_encoder_params *params = priv->params; + struct ch7006_encoder_params *params = &priv->params; struct ch7006_state *state = &priv->state; uint8_t *regs = state->regs; struct ch7006_mode *mode = priv->mode; @@ -428,6 +428,22 @@ static int ch7006_remove(struct i2c_client *client) return 0; } +static int ch7006_suspend(struct i2c_client *client, pm_message_t mesg) +{ + ch7006_dbg(client, "\n"); + + return 0; +} + +static int ch7006_resume(struct i2c_client *client) +{ + ch7006_dbg(client, "\n"); + + ch7006_write(client, 0x3d, 0x0); + + return 0; +} + static int ch7006_encoder_init(struct i2c_client *client, struct drm_device *dev, struct drm_encoder_slave *encoder) @@ -487,6 +503,8 @@ static struct drm_i2c_encoder_driver ch7006_driver = { .i2c_driver = { .probe = ch7006_probe, .remove = ch7006_remove, + .suspend = ch7006_suspend, + .resume = ch7006_resume, .driver = { .name = "ch7006", diff --git a/drivers/gpu/drm/i2c/ch7006_priv.h b/drivers/gpu/drm/i2c/ch7006_priv.h index b06d3d9..1c6d2e3 100644 --- a/drivers/gpu/drm/i2c/ch7006_priv.h +++ b/drivers/gpu/drm/i2c/ch7006_priv.h @@ -77,7 +77,7 @@ struct ch7006_state { }; struct ch7006_priv { - struct ch7006_encoder_params *params; + struct ch7006_encoder_params params; struct ch7006_mode *mode; struct ch7006_state state; diff --git a/drivers/gpu/drm/i2c/sil164_drv.c b/drivers/gpu/drm/i2c/sil164_drv.c new file mode 100644 index 0000000..0b67732 --- /dev/null +++ b/drivers/gpu/drm/i2c/sil164_drv.c @@ -0,0 +1,462 @@ +/* + * Copyright (C) 2010 Francisco Jerez. + * 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 "drmP.h" +#include "drm_crtc_helper.h" +#include "drm_encoder_slave.h" +#include "i2c/sil164.h" + +struct sil164_priv { + struct sil164_encoder_params config; + struct i2c_client *duallink_slave; + + uint8_t saved_state[0x10]; + uint8_t saved_slave_state[0x10]; +}; + +#define to_sil164_priv(x) \ + ((struct sil164_priv *)to_encoder_slave(x)->slave_priv) + +#define sil164_dbg(client, format, ...) do { \ + if (drm_debug & DRM_UT_KMS) \ + dev_printk(KERN_DEBUG, &client->dev, \ + "%s: " format, __func__, ## __VA_ARGS__); \ + } while (0) +#define sil164_info(client, format, ...) \ + dev_info(&client->dev, format, __VA_ARGS__) +#define sil164_err(client, format, ...) \ + dev_err(&client->dev, format, __VA_ARGS__) + +#define SIL164_I2C_ADDR_MASTER 0x38 +#define SIL164_I2C_ADDR_SLAVE 0x39 + +/* HW register definitions */ + +#define SIL164_VENDOR_LO 0x0 +#define SIL164_VENDOR_HI 0x1 +#define SIL164_DEVICE_LO 0x2 +#define SIL164_DEVICE_HI 0x3 +#define SIL164_REVISION 0x4 +#define SIL164_FREQ_MIN 0x6 +#define SIL164_FREQ_MAX 0x7 +#define SIL164_CONTROL0 0x8 +# define SIL164_CONTROL0_POWER_ON 0x01 +# define SIL164_CONTROL0_EDGE_RISING 0x02 +# define SIL164_CONTROL0_INPUT_24BIT 0x04 +# define SIL164_CONTROL0_DUAL_EDGE 0x08 +# define SIL164_CONTROL0_HSYNC_ON 0x10 +# define SIL164_CONTROL0_VSYNC_ON 0x20 +#define SIL164_DETECT 0x9 +# define SIL164_DETECT_INTR_STAT 0x01 +# define SIL164_DETECT_HOTPLUG_STAT 0x02 +# define SIL164_DETECT_RECEIVER_STAT 0x04 +# define SIL164_DETECT_INTR_MODE_RECEIVER 0x00 +# define SIL164_DETECT_INTR_MODE_HOTPLUG 0x08 +# define SIL164_DETECT_OUT_MODE_HIGH 0x00 +# define SIL164_DETECT_OUT_MODE_INTR 0x10 +# define SIL164_DETECT_OUT_MODE_RECEIVER 0x20 +# define SIL164_DETECT_OUT_MODE_HOTPLUG 0x30 +# define SIL164_DETECT_VSWING_STAT 0x80 +#define SIL164_CONTROL1 0xa +# define SIL164_CONTROL1_DESKEW_ENABLE 0x10 +# define SIL164_CONTROL1_DESKEW_INCR_SHIFT 5 +#define SIL164_GPIO 0xb +#define SIL164_CONTROL2 0xc +# define SIL164_CONTROL2_FILTER_ENABLE 0x01 +# define SIL164_CONTROL2_FILTER_SETTING_SHIFT 1 +# define SIL164_CONTROL2_DUALLINK_MASTER 0x40 +# define SIL164_CONTROL2_SYNC_CONT 0x80 +#define SIL164_DUALLINK 0xd +# define SIL164_DUALLINK_ENABLE 0x10 +# define SIL164_DUALLINK_SKEW_SHIFT 5 +#define SIL164_PLLZONE 0xe +# define SIL164_PLLZONE_STAT 0x08 +# define SIL164_PLLZONE_FORCE_ON 0x10 +# define SIL164_PLLZONE_FORCE_HIGH 0x20 + +/* HW access functions */ + +static void +sil164_write(struct i2c_client *client, uint8_t addr, uint8_t val) +{ + uint8_t buf[] = {addr, val}; + int ret; + + ret = i2c_master_send(client, buf, ARRAY_SIZE(buf)); + if (ret < 0) + sil164_err(client, "Error %d writing to subaddress 0x%x\n", + ret, addr); +} + +static uint8_t +sil164_read(struct i2c_client *client, uint8_t addr) +{ + uint8_t val; + int ret; + + ret = i2c_master_send(client, &addr, sizeof(addr)); + if (ret < 0) + goto fail; + + ret = i2c_master_recv(client, &val, sizeof(val)); + if (ret < 0) + goto fail; + + return val; + +fail: + sil164_err(client, "Error %d reading from subaddress 0x%x\n", + ret, addr); + return 0; +} + +static void +sil164_save_state(struct i2c_client *client, uint8_t *state) +{ + int i; + + for (i = 0x8; i <= 0xe; i++) + state[i] = sil164_read(client, i); +} + +static void +sil164_restore_state(struct i2c_client *client, uint8_t *state) +{ + int i; + + for (i = 0x8; i <= 0xe; i++) + sil164_write(client, i, state[i]); +} + +static void +sil164_set_power_state(struct i2c_client *client, bool on) +{ + uint8_t control0 = sil164_read(client, SIL164_CONTROL0); + + if (on) + control0 |= SIL164_CONTROL0_POWER_ON; + else + control0 &= ~SIL164_CONTROL0_POWER_ON; + + sil164_write(client, SIL164_CONTROL0, control0); +} + +static void +sil164_init_state(struct i2c_client *client, + struct sil164_encoder_params *config, + bool duallink) +{ + sil164_write(client, SIL164_CONTROL0, + SIL164_CONTROL0_HSYNC_ON | + SIL164_CONTROL0_VSYNC_ON | + (config->input_edge ? SIL164_CONTROL0_EDGE_RISING : 0) | + (config->input_width ? SIL164_CONTROL0_INPUT_24BIT : 0) | + (config->input_dual ? SIL164_CONTROL0_DUAL_EDGE : 0)); + + sil164_write(client, SIL164_DETECT, + SIL164_DETECT_INTR_STAT | + SIL164_DETECT_OUT_MODE_RECEIVER); + + sil164_write(client, SIL164_CONTROL1, + (config->input_skew ? SIL164_CONTROL1_DESKEW_ENABLE : 0) | + (((config->input_skew + 4) & 0x7) + << SIL164_CONTROL1_DESKEW_INCR_SHIFT)); + + sil164_write(client, SIL164_CONTROL2, + SIL164_CONTROL2_SYNC_CONT | + (config->pll_filter ? 0 : SIL164_CONTROL2_FILTER_ENABLE) | + (4 << SIL164_CONTROL2_FILTER_SETTING_SHIFT)); + + sil164_write(client, SIL164_PLLZONE, 0); + + if (duallink) + sil164_write(client, SIL164_DUALLINK, + SIL164_DUALLINK_ENABLE | + (((config->duallink_skew + 4) & 0x7) + << SIL164_DUALLINK_SKEW_SHIFT)); + else + sil164_write(client, SIL164_DUALLINK, 0); +} + +/* DRM encoder functions */ + +static void +sil164_encoder_set_config(struct drm_encoder *encoder, void *params) +{ + struct sil164_priv *priv = to_sil164_priv(encoder); + + priv->config = *(struct sil164_encoder_params *)params; +} + +static void +sil164_encoder_dpms(struct drm_encoder *encoder, int mode) +{ + struct sil164_priv *priv = to_sil164_priv(encoder); + bool on = (mode == DRM_MODE_DPMS_ON); + bool duallink = (on && encoder->crtc->mode.clock > 165000); + + sil164_set_power_state(drm_i2c_encoder_get_client(encoder), on); + + if (priv->duallink_slave) + sil164_set_power_state(priv->duallink_slave, duallink); +} + +static void +sil164_encoder_save(struct drm_encoder *encoder) +{ + struct sil164_priv *priv = to_sil164_priv(encoder); + + sil164_save_state(drm_i2c_encoder_get_client(encoder), + priv->saved_state); + + if (priv->duallink_slave) + sil164_save_state(priv->duallink_slave, + priv->saved_slave_state); +} + +static void +sil164_encoder_restore(struct drm_encoder *encoder) +{ + struct sil164_priv *priv = to_sil164_priv(encoder); + + sil164_restore_state(drm_i2c_encoder_get_client(encoder), + priv->saved_state); + + if (priv->duallink_slave) + sil164_restore_state(priv->duallink_slave, + priv->saved_slave_state); +} + +static bool +sil164_encoder_mode_fixup(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + return true; +} + +static int +sil164_encoder_mode_valid(struct drm_encoder *encoder, + struct drm_display_mode *mode) +{ + struct sil164_priv *priv = to_sil164_priv(encoder); + + if (mode->clock < 32000) + return MODE_CLOCK_LOW; + + if (mode->clock > 330000 || + (mode->clock > 165000 && !priv->duallink_slave)) + return MODE_CLOCK_HIGH; + + return MODE_OK; +} + +static void +sil164_encoder_mode_set(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct sil164_priv *priv = to_sil164_priv(encoder); + bool duallink = adjusted_mode->clock > 165000; + + sil164_init_state(drm_i2c_encoder_get_client(encoder), + &priv->config, duallink); + + if (priv->duallink_slave) + sil164_init_state(priv->duallink_slave, + &priv->config, duallink); + + sil164_encoder_dpms(encoder, DRM_MODE_DPMS_ON); +} + +static enum drm_connector_status +sil164_encoder_detect(struct drm_encoder *encoder, + struct drm_connector *connector) +{ + struct i2c_client *client = drm_i2c_encoder_get_client(encoder); + + if (sil164_read(client, SIL164_DETECT) & SIL164_DETECT_HOTPLUG_STAT) + return connector_status_connected; + else + return connector_status_disconnected; +} + +static int +sil164_encoder_get_modes(struct drm_encoder *encoder, + struct drm_connector *connector) +{ + return 0; +} + +static int +sil164_encoder_create_resources(struct drm_encoder *encoder, + struct drm_connector *connector) +{ + return 0; +} + +static int +sil164_encoder_set_property(struct drm_encoder *encoder, + struct drm_connector *connector, + struct drm_property *property, + uint64_t val) +{ + return 0; +} + +static void +sil164_encoder_destroy(struct drm_encoder *encoder) +{ + struct sil164_priv *priv = to_sil164_priv(encoder); + + if (priv->duallink_slave) + i2c_unregister_device(priv->duallink_slave); + + kfree(priv); + drm_i2c_encoder_destroy(encoder); +} + +static struct drm_encoder_slave_funcs sil164_encoder_funcs = { + .set_config = sil164_encoder_set_config, + .destroy = sil164_encoder_destroy, + .dpms = sil164_encoder_dpms, + .save = sil164_encoder_save, + .restore = sil164_encoder_restore, + .mode_fixup = sil164_encoder_mode_fixup, + .mode_valid = sil164_encoder_mode_valid, + .mode_set = sil164_encoder_mode_set, + .detect = sil164_encoder_detect, + .get_modes = sil164_encoder_get_modes, + .create_resources = sil164_encoder_create_resources, + .set_property = sil164_encoder_set_property, +}; + +/* I2C driver functions */ + +static int +sil164_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + int vendor = sil164_read(client, SIL164_VENDOR_HI) << 8 | + sil164_read(client, SIL164_VENDOR_LO); + int device = sil164_read(client, SIL164_DEVICE_HI) << 8 | + sil164_read(client, SIL164_DEVICE_LO); + int rev = sil164_read(client, SIL164_REVISION); + + if (vendor != 0x1 || device != 0x6) { + sil164_dbg(client, "Unknown device %x:%x.%x\n", + vendor, device, rev); + return -ENODEV; + } + + sil164_info(client, "Detected device %x:%x.%x\n", + vendor, device, rev); + + return 0; +} + +static int +sil164_remove(struct i2c_client *client) +{ + return 0; +} + +static struct i2c_client * +sil164_detect_slave(struct i2c_client *client) +{ + struct i2c_adapter *adap = client->adapter; + struct i2c_msg msg = { + .addr = SIL164_I2C_ADDR_SLAVE, + .len = 0, + }; + const struct i2c_board_info info = { + I2C_BOARD_INFO("sil164", SIL164_I2C_ADDR_SLAVE) + }; + + if (i2c_transfer(adap, &msg, 1) != 1) { + sil164_dbg(adap, "No dual-link slave found."); + return NULL; + } + + return i2c_new_device(adap, &info); +} + +static int +sil164_encoder_init(struct i2c_client *client, + struct drm_device *dev, + struct drm_encoder_slave *encoder) +{ + struct sil164_priv *priv; + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + encoder->slave_priv = priv; + encoder->slave_funcs = &sil164_encoder_funcs; + + priv->duallink_slave = sil164_detect_slave(client); + + return 0; +} + +static struct i2c_device_id sil164_ids[] = { + { "sil164", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, sil164_ids); + +static struct drm_i2c_encoder_driver sil164_driver = { + .i2c_driver = { + .probe = sil164_probe, + .remove = sil164_remove, + .driver = { + .name = "sil164", + }, + .id_table = sil164_ids, + }, + .encoder_init = sil164_encoder_init, +}; + +/* Module initialization */ + +static int __init +sil164_init(void) +{ + return drm_i2c_encoder_register(THIS_MODULE, &sil164_driver); +} + +static void __exit +sil164_exit(void) +{ + drm_i2c_encoder_unregister(&sil164_driver); +} + +MODULE_AUTHOR("Francisco Jerez <currojerez@riseup.net>"); +MODULE_DESCRIPTION("Silicon Image sil164 TMDS transmitter driver"); +MODULE_LICENSE("GPL and additional rights"); + +module_init(sil164_init); +module_exit(sil164_exit); diff --git a/drivers/gpu/drm/i810/i810_dma.c b/drivers/gpu/drm/i810/i810_dma.c index 997d917..0e6c131 100644 --- a/drivers/gpu/drm/i810/i810_dma.c +++ b/drivers/gpu/drm/i810/i810_dma.c @@ -37,6 +37,7 @@ #include <linux/interrupt.h> /* For task queue support */ #include <linux/delay.h> #include <linux/slab.h> +#include <linux/smp_lock.h> #include <linux/pagemap.h> #define I810_BUF_FREE 2 @@ -60,9 +61,8 @@ static struct drm_buf *i810_freelist_get(struct drm_device * dev) /* In use is already a pointer */ used = cmpxchg(buf_priv->in_use, I810_BUF_FREE, I810_BUF_CLIENT); - if (used == I810_BUF_FREE) { + if (used == I810_BUF_FREE) return buf; - } } return NULL; } @@ -71,7 +71,7 @@ static struct drm_buf *i810_freelist_get(struct drm_device * dev) * yet, the hardware updates in use for us once its on the ring buffer. */ -static int i810_freelist_put(struct drm_device * dev, struct drm_buf * buf) +static int i810_freelist_put(struct drm_device *dev, struct drm_buf *buf) { drm_i810_buf_priv_t *buf_priv = buf->dev_private; int used; @@ -121,7 +121,7 @@ static const struct file_operations i810_buffer_fops = { .fasync = drm_fasync, }; -static int i810_map_buffer(struct drm_buf * buf, struct drm_file *file_priv) +static int i810_map_buffer(struct drm_buf *buf, struct drm_file *file_priv) { struct drm_device *dev = file_priv->minor->dev; drm_i810_buf_priv_t *buf_priv = buf->dev_private; @@ -152,7 +152,7 @@ static int i810_map_buffer(struct drm_buf * buf, struct drm_file *file_priv) return retcode; } -static int i810_unmap_buffer(struct drm_buf * buf) +static int i810_unmap_buffer(struct drm_buf *buf) { drm_i810_buf_priv_t *buf_priv = buf->dev_private; int retcode = 0; @@ -172,7 +172,7 @@ static int i810_unmap_buffer(struct drm_buf * buf) return retcode; } -static int i810_dma_get_buffer(struct drm_device * dev, drm_i810_dma_t * d, +static int i810_dma_get_buffer(struct drm_device *dev, drm_i810_dma_t *d, struct drm_file *file_priv) { struct drm_buf *buf; @@ -202,7 +202,7 @@ static int i810_dma_get_buffer(struct drm_device * dev, drm_i810_dma_t * d, return retcode; } -static int i810_dma_cleanup(struct drm_device * dev) +static int i810_dma_cleanup(struct drm_device *dev) { struct drm_device_dma *dma = dev->dma; @@ -218,9 +218,8 @@ static int i810_dma_cleanup(struct drm_device * dev) drm_i810_private_t *dev_priv = (drm_i810_private_t *) dev->dev_private; - if (dev_priv->ring.virtual_start) { + if (dev_priv->ring.virtual_start) drm_core_ioremapfree(&dev_priv->ring.map, dev); - } if (dev_priv->hw_status_page) { pci_free_consistent(dev->pdev, PAGE_SIZE, dev_priv->hw_status_page, @@ -242,7 +241,7 @@ static int i810_dma_cleanup(struct drm_device * dev) return 0; } -static int i810_wait_ring(struct drm_device * dev, int n) +static int i810_wait_ring(struct drm_device *dev, int n) { drm_i810_private_t *dev_priv = dev->dev_private; drm_i810_ring_buffer_t *ring = &(dev_priv->ring); @@ -271,11 +270,11 @@ static int i810_wait_ring(struct drm_device * dev, int n) udelay(1); } - out_wait_ring: +out_wait_ring: return iters; } -static void i810_kernel_lost_context(struct drm_device * dev) +static void i810_kernel_lost_context(struct drm_device *dev) { drm_i810_private_t *dev_priv = dev->dev_private; drm_i810_ring_buffer_t *ring = &(dev_priv->ring); @@ -287,7 +286,7 @@ static void i810_kernel_lost_context(struct drm_device * dev) ring->space += ring->Size; } -static int i810_freelist_init(struct drm_device * dev, drm_i810_private_t * dev_priv) +static int i810_freelist_init(struct drm_device *dev, drm_i810_private_t *dev_priv) { struct drm_device_dma *dma = dev->dma; int my_idx = 24; @@ -322,9 +321,9 @@ static int i810_freelist_init(struct drm_device * dev, drm_i810_private_t * dev_ return 0; } -static int i810_dma_initialize(struct drm_device * dev, - drm_i810_private_t * dev_priv, - drm_i810_init_t * init) +static int i810_dma_initialize(struct drm_device *dev, + drm_i810_private_t *dev_priv, + drm_i810_init_t *init) { struct drm_map_list *r_list; memset(dev_priv, 0, sizeof(drm_i810_private_t)); @@ -462,7 +461,7 @@ static int i810_dma_init(struct drm_device *dev, void *data, * Use 'volatile' & local var tmp to force the emitted values to be * identical to the verified ones. */ -static void i810EmitContextVerified(struct drm_device * dev, +static void i810EmitContextVerified(struct drm_device *dev, volatile unsigned int *code) { drm_i810_private_t *dev_priv = dev->dev_private; @@ -495,7 +494,7 @@ static void i810EmitContextVerified(struct drm_device * dev, ADVANCE_LP_RING(); } -static void i810EmitTexVerified(struct drm_device * dev, volatile unsigned int *code) +static void i810EmitTexVerified(struct drm_device *dev, volatile unsigned int *code) { drm_i810_private_t *dev_priv = dev->dev_private; int i, j = 0; @@ -528,7 +527,7 @@ static void i810EmitTexVerified(struct drm_device * dev, volatile unsigned int * /* Need to do some additional checking when setting the dest buffer. */ -static void i810EmitDestVerified(struct drm_device * dev, +static void i810EmitDestVerified(struct drm_device *dev, volatile unsigned int *code) { drm_i810_private_t *dev_priv = dev->dev_private; @@ -563,7 +562,7 @@ static void i810EmitDestVerified(struct drm_device * dev, ADVANCE_LP_RING(); } -static void i810EmitState(struct drm_device * dev) +static void i810EmitState(struct drm_device *dev) { drm_i810_private_t *dev_priv = dev->dev_private; drm_i810_sarea_t *sarea_priv = dev_priv->sarea_priv; @@ -594,7 +593,7 @@ static void i810EmitState(struct drm_device * dev) /* need to verify */ -static void i810_dma_dispatch_clear(struct drm_device * dev, int flags, +static void i810_dma_dispatch_clear(struct drm_device *dev, int flags, unsigned int clear_color, unsigned int clear_zval) { @@ -669,7 +668,7 @@ static void i810_dma_dispatch_clear(struct drm_device * dev, int flags, } } -static void i810_dma_dispatch_swap(struct drm_device * dev) +static void i810_dma_dispatch_swap(struct drm_device *dev) { drm_i810_private_t *dev_priv = dev->dev_private; drm_i810_sarea_t *sarea_priv = dev_priv->sarea_priv; @@ -715,8 +714,8 @@ static void i810_dma_dispatch_swap(struct drm_device * dev) } } -static void i810_dma_dispatch_vertex(struct drm_device * dev, - struct drm_buf * buf, int discard, int used) +static void i810_dma_dispatch_vertex(struct drm_device *dev, + struct drm_buf *buf, int discard, int used) { drm_i810_private_t *dev_priv = dev->dev_private; drm_i810_buf_priv_t *buf_priv = buf->dev_private; @@ -795,7 +794,7 @@ static void i810_dma_dispatch_vertex(struct drm_device * dev, } } -static void i810_dma_dispatch_flip(struct drm_device * dev) +static void i810_dma_dispatch_flip(struct drm_device *dev) { drm_i810_private_t *dev_priv = dev->dev_private; int pitch = dev_priv->pitch; @@ -841,7 +840,7 @@ static void i810_dma_dispatch_flip(struct drm_device * dev) } -static void i810_dma_quiescent(struct drm_device * dev) +static void i810_dma_quiescent(struct drm_device *dev) { drm_i810_private_t *dev_priv = dev->dev_private; RING_LOCALS; @@ -858,7 +857,7 @@ static void i810_dma_quiescent(struct drm_device * dev) i810_wait_ring(dev, dev_priv->ring.Size - 8); } -static int i810_flush_queue(struct drm_device * dev) +static int i810_flush_queue(struct drm_device *dev) { drm_i810_private_t *dev_priv = dev->dev_private; struct drm_device_dma *dma = dev->dma; @@ -891,7 +890,7 @@ static int i810_flush_queue(struct drm_device * dev) } /* Must be called with the lock held */ -static void i810_reclaim_buffers(struct drm_device * dev, +static void i810_reclaim_buffers(struct drm_device *dev, struct drm_file *file_priv) { struct drm_device_dma *dma = dev->dma; @@ -969,9 +968,8 @@ static int i810_clear_bufs(struct drm_device *dev, void *data, LOCK_TEST_WITH_RETURN(dev, file_priv); /* GH: Someone's doing nasty things... */ - if (!dev->dev_private) { + if (!dev->dev_private) return -EINVAL; - } i810_dma_dispatch_clear(dev, clear->flags, clear->clear_color, clear->clear_depth); @@ -1039,7 +1037,7 @@ static int i810_docopy(struct drm_device *dev, void *data, return 0; } -static void i810_dma_dispatch_mc(struct drm_device * dev, struct drm_buf * buf, int used, +static void i810_dma_dispatch_mc(struct drm_device *dev, struct drm_buf *buf, int used, unsigned int last_render) { drm_i810_private_t *dev_priv = dev->dev_private; @@ -1053,9 +1051,8 @@ static void i810_dma_dispatch_mc(struct drm_device * dev, struct drm_buf * buf, i810_kernel_lost_context(dev); u = cmpxchg(buf_priv->in_use, I810_BUF_CLIENT, I810_BUF_HARDWARE); - if (u != I810_BUF_CLIENT) { + if (u != I810_BUF_CLIENT) DRM_DEBUG("MC found buffer that isn't mine!\n"); - } if (used > 4 * 1024) used = 0; @@ -1160,7 +1157,7 @@ static int i810_ov0_flip(struct drm_device *dev, void *data, LOCK_TEST_WITH_RETURN(dev, file_priv); - //Tell the overlay to update + /* Tell the overlay to update */ I810_WRITE(0x30000, dev_priv->overlay_physical | 0x80000000); return 0; @@ -1168,7 +1165,7 @@ static int i810_ov0_flip(struct drm_device *dev, void *data, /* Not sure why this isn't set all the time: */ -static void i810_do_init_pageflip(struct drm_device * dev) +static void i810_do_init_pageflip(struct drm_device *dev) { drm_i810_private_t *dev_priv = dev->dev_private; @@ -1178,7 +1175,7 @@ static void i810_do_init_pageflip(struct drm_device * dev) dev_priv->sarea_priv->pf_current_page = dev_priv->current_page; } -static int i810_do_cleanup_pageflip(struct drm_device * dev) +static int i810_do_cleanup_pageflip(struct drm_device *dev) { drm_i810_private_t *dev_priv = dev->dev_private; @@ -1218,49 +1215,61 @@ int i810_driver_load(struct drm_device *dev, unsigned long flags) return 0; } -void i810_driver_lastclose(struct drm_device * dev) +void i810_driver_lastclose(struct drm_device *dev) { i810_dma_cleanup(dev); } -void i810_driver_preclose(struct drm_device * dev, struct drm_file *file_priv) +void i810_driver_preclose(struct drm_device *dev, struct drm_file *file_priv) { if (dev->dev_private) { drm_i810_private_t *dev_priv = dev->dev_private; - if (dev_priv->page_flipping) { + if (dev_priv->page_flipping) i810_do_cleanup_pageflip(dev); - } } } -void i810_driver_reclaim_buffers_locked(struct drm_device * dev, +void i810_driver_reclaim_buffers_locked(struct drm_device *dev, struct drm_file *file_priv) { i810_reclaim_buffers(dev, file_priv); } -int i810_driver_dma_quiescent(struct drm_device * dev) +int i810_driver_dma_quiescent(struct drm_device *dev) { i810_dma_quiescent(dev); return 0; } +/* + * call the drm_ioctl under the big kernel lock because + * to lock against the i810_mmap_buffers function. + */ +long i810_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + int ret; + lock_kernel(); + ret = drm_ioctl(file, cmd, arg); + unlock_kernel(); + return ret; +} + struct drm_ioctl_desc i810_ioctls[] = { - DRM_IOCTL_DEF(DRM_I810_INIT, i810_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_I810_VERTEX, i810_dma_vertex, DRM_AUTH), - DRM_IOCTL_DEF(DRM_I810_CLEAR, i810_clear_bufs, DRM_AUTH), - DRM_IOCTL_DEF(DRM_I810_FLUSH, i810_flush_ioctl, DRM_AUTH), - DRM_IOCTL_DEF(DRM_I810_GETAGE, i810_getage, DRM_AUTH), - DRM_IOCTL_DEF(DRM_I810_GETBUF, i810_getbuf, DRM_AUTH), - DRM_IOCTL_DEF(DRM_I810_SWAP, i810_swap_bufs, DRM_AUTH), - DRM_IOCTL_DEF(DRM_I810_COPY, i810_copybuf, DRM_AUTH), - DRM_IOCTL_DEF(DRM_I810_DOCOPY, i810_docopy, DRM_AUTH), - DRM_IOCTL_DEF(DRM_I810_OV0INFO, i810_ov0_info, DRM_AUTH), - DRM_IOCTL_DEF(DRM_I810_FSTATUS, i810_fstatus, DRM_AUTH), - DRM_IOCTL_DEF(DRM_I810_OV0FLIP, i810_ov0_flip, DRM_AUTH), - DRM_IOCTL_DEF(DRM_I810_MC, i810_dma_mc, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_I810_RSTATUS, i810_rstatus, DRM_AUTH), - DRM_IOCTL_DEF(DRM_I810_FLIP, i810_flip_bufs, DRM_AUTH) + DRM_IOCTL_DEF(DRM_I810_INIT, i810_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY|DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_I810_VERTEX, i810_dma_vertex, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_I810_CLEAR, i810_clear_bufs, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_I810_FLUSH, i810_flush_ioctl, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_I810_GETAGE, i810_getage, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_I810_GETBUF, i810_getbuf, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_I810_SWAP, i810_swap_bufs, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_I810_COPY, i810_copybuf, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_I810_DOCOPY, i810_docopy, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_I810_OV0INFO, i810_ov0_info, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_I810_FSTATUS, i810_fstatus, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_I810_OV0FLIP, i810_ov0_flip, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_I810_MC, i810_dma_mc, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY|DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_I810_RSTATUS, i810_rstatus, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_I810_FLIP, i810_flip_bufs, DRM_AUTH|DRM_UNLOCKED), }; int i810_max_ioctl = DRM_ARRAY_SIZE(i810_ioctls); @@ -1276,7 +1285,7 @@ int i810_max_ioctl = DRM_ARRAY_SIZE(i810_ioctls); * \returns * A value of 1 is always retured to indictate every i810 is AGP. */ -int i810_driver_device_is_agp(struct drm_device * dev) +int i810_driver_device_is_agp(struct drm_device *dev) { return 1; } diff --git a/drivers/gpu/drm/i810/i810_drv.c b/drivers/gpu/drm/i810/i810_drv.c index c1e0275..b4250b2 100644 --- a/drivers/gpu/drm/i810/i810_drv.c +++ b/drivers/gpu/drm/i810/i810_drv.c @@ -59,7 +59,7 @@ static struct drm_driver driver = { .owner = THIS_MODULE, .open = drm_open, .release = drm_release, - .unlocked_ioctl = drm_ioctl, + .unlocked_ioctl = i810_ioctl, .mmap = drm_mmap, .poll = drm_poll, .fasync = drm_fasync, diff --git a/drivers/gpu/drm/i810/i810_drv.h b/drivers/gpu/drm/i810/i810_drv.h index 21e2691..c9339f4 100644 --- a/drivers/gpu/drm/i810/i810_drv.h +++ b/drivers/gpu/drm/i810/i810_drv.h @@ -115,56 +115,59 @@ typedef struct drm_i810_private { } drm_i810_private_t; /* i810_dma.c */ -extern int i810_driver_dma_quiescent(struct drm_device * dev); -extern void i810_driver_reclaim_buffers_locked(struct drm_device * dev, +extern int i810_driver_dma_quiescent(struct drm_device *dev); +extern void i810_driver_reclaim_buffers_locked(struct drm_device *dev, struct drm_file *file_priv); extern int i810_driver_load(struct drm_device *, unsigned long flags); -extern void i810_driver_lastclose(struct drm_device * dev); -extern void i810_driver_preclose(struct drm_device * dev, +extern void i810_driver_lastclose(struct drm_device *dev); +extern void i810_driver_preclose(struct drm_device *dev, struct drm_file *file_priv); -extern void i810_driver_reclaim_buffers_locked(struct drm_device * dev, +extern void i810_driver_reclaim_buffers_locked(struct drm_device *dev, struct drm_file *file_priv); -extern int i810_driver_device_is_agp(struct drm_device * dev); +extern int i810_driver_device_is_agp(struct drm_device *dev); +extern long i810_ioctl(struct file *file, unsigned int cmd, unsigned long arg); extern struct drm_ioctl_desc i810_ioctls[]; extern int i810_max_ioctl; #define I810_BASE(reg) ((unsigned long) \ dev_priv->mmio_map->handle) #define I810_ADDR(reg) (I810_BASE(reg) + reg) -#define I810_DEREF(reg) *(__volatile__ int *)I810_ADDR(reg) +#define I810_DEREF(reg) (*(__volatile__ int *)I810_ADDR(reg)) #define I810_READ(reg) I810_DEREF(reg) -#define I810_WRITE(reg,val) do { I810_DEREF(reg) = val; } while (0) -#define I810_DEREF16(reg) *(__volatile__ u16 *)I810_ADDR(reg) +#define I810_WRITE(reg, val) do { I810_DEREF(reg) = val; } while (0) +#define I810_DEREF16(reg) (*(__volatile__ u16 *)I810_ADDR(reg)) #define I810_READ16(reg) I810_DEREF16(reg) -#define I810_WRITE16(reg,val) do { I810_DEREF16(reg) = val; } while (0) +#define I810_WRITE16(reg, val) do { I810_DEREF16(reg) = val; } while (0) #define I810_VERBOSE 0 #define RING_LOCALS unsigned int outring, ringmask; \ - volatile char *virt; - -#define BEGIN_LP_RING(n) do { \ - if (I810_VERBOSE) \ - DRM_DEBUG("BEGIN_LP_RING(%d)\n", n); \ - if (dev_priv->ring.space < n*4) \ - i810_wait_ring(dev, n*4); \ - dev_priv->ring.space -= n*4; \ - outring = dev_priv->ring.tail; \ - ringmask = dev_priv->ring.tail_mask; \ - virt = dev_priv->ring.virtual_start; \ + volatile char *virt; + +#define BEGIN_LP_RING(n) do { \ + if (I810_VERBOSE) \ + DRM_DEBUG("BEGIN_LP_RING(%d)\n", n); \ + if (dev_priv->ring.space < n*4) \ + i810_wait_ring(dev, n*4); \ + dev_priv->ring.space -= n*4; \ + outring = dev_priv->ring.tail; \ + ringmask = dev_priv->ring.tail_mask; \ + virt = dev_priv->ring.virtual_start; \ } while (0) -#define ADVANCE_LP_RING() do { \ - if (I810_VERBOSE) DRM_DEBUG("ADVANCE_LP_RING\n"); \ +#define ADVANCE_LP_RING() do { \ + if (I810_VERBOSE) \ + DRM_DEBUG("ADVANCE_LP_RING\n"); \ dev_priv->ring.tail = outring; \ - I810_WRITE(LP_RING + RING_TAIL, outring); \ -} while(0) - -#define OUT_RING(n) do { \ - if (I810_VERBOSE) DRM_DEBUG(" OUT_RING %x\n", (int)(n)); \ - *(volatile unsigned int *)(virt + outring) = n; \ - outring += 4; \ - outring &= ringmask; \ + I810_WRITE(LP_RING + RING_TAIL, outring); \ +} while (0) + +#define OUT_RING(n) do { \ + if (I810_VERBOSE) \ + DRM_DEBUG(" OUT_RING %x\n", (int)(n)); \ + *(volatile unsigned int *)(virt + outring) = n; \ + outring += 4; \ + outring &= ringmask; \ } while (0) #define GFX_OP_USER_INTERRUPT ((0<<29)|(2<<23)) diff --git a/drivers/gpu/drm/i830/i830_dma.c b/drivers/gpu/drm/i830/i830_dma.c index 65759a9..5168862 100644 --- a/drivers/gpu/drm/i830/i830_dma.c +++ b/drivers/gpu/drm/i830/i830_dma.c @@ -36,6 +36,7 @@ #include "i830_drm.h" #include "i830_drv.h" #include <linux/interrupt.h> /* For task queue support */ +#include <linux/smp_lock.h> #include <linux/pagemap.h> #include <linux/delay.h> #include <linux/slab.h> @@ -62,9 +63,8 @@ static struct drm_buf *i830_freelist_get(struct drm_device * dev) /* In use is already a pointer */ used = cmpxchg(buf_priv->in_use, I830_BUF_FREE, I830_BUF_CLIENT); - if (used == I830_BUF_FREE) { + if (used == I830_BUF_FREE) return buf; - } } return NULL; } @@ -73,7 +73,7 @@ static struct drm_buf *i830_freelist_get(struct drm_device * dev) * yet, the hardware updates in use for us once its on the ring buffer. */ -static int i830_freelist_put(struct drm_device * dev, struct drm_buf * buf) +static int i830_freelist_put(struct drm_device *dev, struct drm_buf *buf) { drm_i830_buf_priv_t *buf_priv = buf->dev_private; int used; @@ -123,7 +123,7 @@ static const struct file_operations i830_buffer_fops = { .fasync = drm_fasync, }; -static int i830_map_buffer(struct drm_buf * buf, struct drm_file *file_priv) +static int i830_map_buffer(struct drm_buf *buf, struct drm_file *file_priv) { struct drm_device *dev = file_priv->minor->dev; drm_i830_buf_priv_t *buf_priv = buf->dev_private; @@ -156,7 +156,7 @@ static int i830_map_buffer(struct drm_buf * buf, struct drm_file *file_priv) return retcode; } -static int i830_unmap_buffer(struct drm_buf * buf) +static int i830_unmap_buffer(struct drm_buf *buf) { drm_i830_buf_priv_t *buf_priv = buf->dev_private; int retcode = 0; @@ -176,7 +176,7 @@ static int i830_unmap_buffer(struct drm_buf * buf) return retcode; } -static int i830_dma_get_buffer(struct drm_device * dev, drm_i830_dma_t * d, +static int i830_dma_get_buffer(struct drm_device *dev, drm_i830_dma_t *d, struct drm_file *file_priv) { struct drm_buf *buf; @@ -206,7 +206,7 @@ static int i830_dma_get_buffer(struct drm_device * dev, drm_i830_dma_t * d, return retcode; } -static int i830_dma_cleanup(struct drm_device * dev) +static int i830_dma_cleanup(struct drm_device *dev) { struct drm_device_dma *dma = dev->dma; @@ -222,9 +222,8 @@ static int i830_dma_cleanup(struct drm_device * dev) drm_i830_private_t *dev_priv = (drm_i830_private_t *) dev->dev_private; - if (dev_priv->ring.virtual_start) { + if (dev_priv->ring.virtual_start) drm_core_ioremapfree(&dev_priv->ring.map, dev); - } if (dev_priv->hw_status_page) { pci_free_consistent(dev->pdev, PAGE_SIZE, dev_priv->hw_status_page, @@ -246,7 +245,7 @@ static int i830_dma_cleanup(struct drm_device * dev) return 0; } -int i830_wait_ring(struct drm_device * dev, int n, const char *caller) +int i830_wait_ring(struct drm_device *dev, int n, const char *caller) { drm_i830_private_t *dev_priv = dev->dev_private; drm_i830_ring_buffer_t *ring = &(dev_priv->ring); @@ -276,11 +275,11 @@ int i830_wait_ring(struct drm_device * dev, int n, const char *caller) dev_priv->sarea_priv->perf_boxes |= I830_BOX_WAIT; } - out_wait_ring: +out_wait_ring: return iters; } -static void i830_kernel_lost_context(struct drm_device * dev) +static void i830_kernel_lost_context(struct drm_device *dev) { drm_i830_private_t *dev_priv = dev->dev_private; drm_i830_ring_buffer_t *ring = &(dev_priv->ring); @@ -295,7 +294,7 @@ static void i830_kernel_lost_context(struct drm_device * dev) dev_priv->sarea_priv->perf_boxes |= I830_BOX_RING_EMPTY; } -static int i830_freelist_init(struct drm_device * dev, drm_i830_private_t * dev_priv) +static int i830_freelist_init(struct drm_device *dev, drm_i830_private_t *dev_priv) { struct drm_device_dma *dma = dev->dma; int my_idx = 36; @@ -329,9 +328,9 @@ static int i830_freelist_init(struct drm_device * dev, drm_i830_private_t * dev_ return 0; } -static int i830_dma_initialize(struct drm_device * dev, - drm_i830_private_t * dev_priv, - drm_i830_init_t * init) +static int i830_dma_initialize(struct drm_device *dev, + drm_i830_private_t *dev_priv, + drm_i830_init_t *init) { struct drm_map_list *r_list; @@ -482,7 +481,7 @@ static int i830_dma_init(struct drm_device *dev, void *data, /* Most efficient way to verify state for the i830 is as it is * emitted. Non-conformant state is silently dropped. */ -static void i830EmitContextVerified(struct drm_device * dev, unsigned int *code) +static void i830EmitContextVerified(struct drm_device *dev, unsigned int *code) { drm_i830_private_t *dev_priv = dev->dev_private; int i, j = 0; @@ -527,7 +526,7 @@ static void i830EmitContextVerified(struct drm_device * dev, unsigned int *code) ADVANCE_LP_RING(); } -static void i830EmitTexVerified(struct drm_device * dev, unsigned int *code) +static void i830EmitTexVerified(struct drm_device *dev, unsigned int *code) { drm_i830_private_t *dev_priv = dev->dev_private; int i, j = 0; @@ -561,7 +560,7 @@ static void i830EmitTexVerified(struct drm_device * dev, unsigned int *code) printk("rejected packet %x\n", code[0]); } -static void i830EmitTexBlendVerified(struct drm_device * dev, +static void i830EmitTexBlendVerified(struct drm_device *dev, unsigned int *code, unsigned int num) { drm_i830_private_t *dev_priv = dev->dev_private; @@ -586,7 +585,7 @@ static void i830EmitTexBlendVerified(struct drm_device * dev, ADVANCE_LP_RING(); } -static void i830EmitTexPalette(struct drm_device * dev, +static void i830EmitTexPalette(struct drm_device *dev, unsigned int *palette, int number, int is_shared) { drm_i830_private_t *dev_priv = dev->dev_private; @@ -603,9 +602,8 @@ static void i830EmitTexPalette(struct drm_device * dev, } else { OUT_RING(CMD_OP_MAP_PALETTE_LOAD | MAP_PALETTE_NUM(number)); } - for (i = 0; i < 256; i++) { + for (i = 0; i < 256; i++) OUT_RING(palette[i]); - } OUT_RING(0); /* KW: WHERE IS THE ADVANCE_LP_RING? This is effectively a noop! */ @@ -613,7 +611,7 @@ static void i830EmitTexPalette(struct drm_device * dev, /* Need to do some additional checking when setting the dest buffer. */ -static void i830EmitDestVerified(struct drm_device * dev, unsigned int *code) +static void i830EmitDestVerified(struct drm_device *dev, unsigned int *code) { drm_i830_private_t *dev_priv = dev->dev_private; unsigned int tmp; @@ -674,7 +672,7 @@ static void i830EmitDestVerified(struct drm_device * dev, unsigned int *code) ADVANCE_LP_RING(); } -static void i830EmitStippleVerified(struct drm_device * dev, unsigned int *code) +static void i830EmitStippleVerified(struct drm_device *dev, unsigned int *code) { drm_i830_private_t *dev_priv = dev->dev_private; RING_LOCALS; @@ -685,7 +683,7 @@ static void i830EmitStippleVerified(struct drm_device * dev, unsigned int *code) ADVANCE_LP_RING(); } -static void i830EmitState(struct drm_device * dev) +static void i830EmitState(struct drm_device *dev) { drm_i830_private_t *dev_priv = dev->dev_private; drm_i830_sarea_t *sarea_priv = dev_priv->sarea_priv; @@ -788,7 +786,7 @@ static void i830EmitState(struct drm_device * dev) * Performance monitoring functions */ -static void i830_fill_box(struct drm_device * dev, +static void i830_fill_box(struct drm_device *dev, int x, int y, int w, int h, int r, int g, int b) { drm_i830_private_t *dev_priv = dev->dev_private; @@ -816,17 +814,16 @@ static void i830_fill_box(struct drm_device * dev, OUT_RING((y << 16) | x); OUT_RING(((y + h) << 16) | (x + w)); - if (dev_priv->current_page == 1) { + if (dev_priv->current_page == 1) OUT_RING(dev_priv->front_offset); - } else { + else OUT_RING(dev_priv->back_offset); - } OUT_RING(color); ADVANCE_LP_RING(); } -static void i830_cp_performance_boxes(struct drm_device * dev) +static void i830_cp_performance_boxes(struct drm_device *dev) { drm_i830_private_t *dev_priv = dev->dev_private; @@ -871,7 +868,7 @@ static void i830_cp_performance_boxes(struct drm_device * dev) dev_priv->sarea_priv->perf_boxes = 0; } -static void i830_dma_dispatch_clear(struct drm_device * dev, int flags, +static void i830_dma_dispatch_clear(struct drm_device *dev, int flags, unsigned int clear_color, unsigned int clear_zval, unsigned int clear_depthmask) @@ -966,7 +963,7 @@ static void i830_dma_dispatch_clear(struct drm_device * dev, int flags, } } -static void i830_dma_dispatch_swap(struct drm_device * dev) +static void i830_dma_dispatch_swap(struct drm_device *dev) { drm_i830_private_t *dev_priv = dev->dev_private; drm_i830_sarea_t *sarea_priv = dev_priv->sarea_priv; @@ -1036,7 +1033,7 @@ static void i830_dma_dispatch_swap(struct drm_device * dev) } } -static void i830_dma_dispatch_flip(struct drm_device * dev) +static void i830_dma_dispatch_flip(struct drm_device *dev) { drm_i830_private_t *dev_priv = dev->dev_private; RING_LOCALS; @@ -1079,8 +1076,8 @@ static void i830_dma_dispatch_flip(struct drm_device * dev) dev_priv->sarea_priv->pf_current_page = dev_priv->current_page; } -static void i830_dma_dispatch_vertex(struct drm_device * dev, - struct drm_buf * buf, int discard, int used) +static void i830_dma_dispatch_vertex(struct drm_device *dev, + struct drm_buf *buf, int discard, int used) { drm_i830_private_t *dev_priv = dev->dev_private; drm_i830_buf_priv_t *buf_priv = buf->dev_private; @@ -1100,9 +1097,8 @@ static void i830_dma_dispatch_vertex(struct drm_device * dev, if (discard) { u = cmpxchg(buf_priv->in_use, I830_BUF_CLIENT, I830_BUF_HARDWARE); - if (u != I830_BUF_CLIENT) { + if (u != I830_BUF_CLIENT) DRM_DEBUG("xxxx 2\n"); - } } if (used > 4 * 1023) @@ -1191,7 +1187,7 @@ static void i830_dma_dispatch_vertex(struct drm_device * dev, } } -static void i830_dma_quiescent(struct drm_device * dev) +static void i830_dma_quiescent(struct drm_device *dev) { drm_i830_private_t *dev_priv = dev->dev_private; RING_LOCALS; @@ -1208,7 +1204,7 @@ static void i830_dma_quiescent(struct drm_device * dev) i830_wait_ring(dev, dev_priv->ring.Size - 8, __func__); } -static int i830_flush_queue(struct drm_device * dev) +static int i830_flush_queue(struct drm_device *dev) { drm_i830_private_t *dev_priv = dev->dev_private; struct drm_device_dma *dma = dev->dma; @@ -1241,7 +1237,7 @@ static int i830_flush_queue(struct drm_device * dev) } /* Must be called with the lock held */ -static void i830_reclaim_buffers(struct drm_device * dev, struct drm_file *file_priv) +static void i830_reclaim_buffers(struct drm_device *dev, struct drm_file *file_priv) { struct drm_device_dma *dma = dev->dma; int i; @@ -1316,9 +1312,8 @@ static int i830_clear_bufs(struct drm_device *dev, void *data, LOCK_TEST_WITH_RETURN(dev, file_priv); /* GH: Someone's doing nasty things... */ - if (!dev->dev_private) { + if (!dev->dev_private) return -EINVAL; - } i830_dma_dispatch_clear(dev, clear->flags, clear->clear_color, @@ -1339,7 +1334,7 @@ static int i830_swap_bufs(struct drm_device *dev, void *data, /* Not sure why this isn't set all the time: */ -static void i830_do_init_pageflip(struct drm_device * dev) +static void i830_do_init_pageflip(struct drm_device *dev) { drm_i830_private_t *dev_priv = dev->dev_private; @@ -1349,7 +1344,7 @@ static void i830_do_init_pageflip(struct drm_device * dev) dev_priv->sarea_priv->pf_current_page = dev_priv->current_page; } -static int i830_do_cleanup_pageflip(struct drm_device * dev) +static int i830_do_cleanup_pageflip(struct drm_device *dev) { drm_i830_private_t *dev_priv = dev->dev_private; @@ -1490,47 +1485,59 @@ int i830_driver_load(struct drm_device *dev, unsigned long flags) return 0; } -void i830_driver_lastclose(struct drm_device * dev) +void i830_driver_lastclose(struct drm_device *dev) { i830_dma_cleanup(dev); } -void i830_driver_preclose(struct drm_device * dev, struct drm_file *file_priv) +void i830_driver_preclose(struct drm_device *dev, struct drm_file *file_priv) { if (dev->dev_private) { drm_i830_private_t *dev_priv = dev->dev_private; - if (dev_priv->page_flipping) { + if (dev_priv->page_flipping) i830_do_cleanup_pageflip(dev); - } } } -void i830_driver_reclaim_buffers_locked(struct drm_device * dev, struct drm_file *file_priv) +void i830_driver_reclaim_buffers_locked(struct drm_device *dev, struct drm_file *file_priv) { i830_reclaim_buffers(dev, file_priv); } -int i830_driver_dma_quiescent(struct drm_device * dev) +int i830_driver_dma_quiescent(struct drm_device *dev) { i830_dma_quiescent(dev); return 0; } +/* + * call the drm_ioctl under the big kernel lock because + * to lock against the i830_mmap_buffers function. + */ +long i830_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + int ret; + lock_kernel(); + ret = drm_ioctl(file, cmd, arg); + unlock_kernel(); + return ret; +} + struct drm_ioctl_desc i830_ioctls[] = { - DRM_IOCTL_DEF(DRM_I830_INIT, i830_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_I830_VERTEX, i830_dma_vertex, DRM_AUTH), - DRM_IOCTL_DEF(DRM_I830_CLEAR, i830_clear_bufs, DRM_AUTH), - DRM_IOCTL_DEF(DRM_I830_FLUSH, i830_flush_ioctl, DRM_AUTH), - DRM_IOCTL_DEF(DRM_I830_GETAGE, i830_getage, DRM_AUTH), - DRM_IOCTL_DEF(DRM_I830_GETBUF, i830_getbuf, DRM_AUTH), - DRM_IOCTL_DEF(DRM_I830_SWAP, i830_swap_bufs, DRM_AUTH), - DRM_IOCTL_DEF(DRM_I830_COPY, i830_copybuf, DRM_AUTH), - DRM_IOCTL_DEF(DRM_I830_DOCOPY, i830_docopy, DRM_AUTH), - DRM_IOCTL_DEF(DRM_I830_FLIP, i830_flip_bufs, DRM_AUTH), - DRM_IOCTL_DEF(DRM_I830_IRQ_EMIT, i830_irq_emit, DRM_AUTH), - DRM_IOCTL_DEF(DRM_I830_IRQ_WAIT, i830_irq_wait, DRM_AUTH), - DRM_IOCTL_DEF(DRM_I830_GETPARAM, i830_getparam, DRM_AUTH), - DRM_IOCTL_DEF(DRM_I830_SETPARAM, i830_setparam, DRM_AUTH) + DRM_IOCTL_DEF(DRM_I830_INIT, i830_dma_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY|DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_I830_VERTEX, i830_dma_vertex, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_I830_CLEAR, i830_clear_bufs, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_I830_FLUSH, i830_flush_ioctl, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_I830_GETAGE, i830_getage, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_I830_GETBUF, i830_getbuf, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_I830_SWAP, i830_swap_bufs, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_I830_COPY, i830_copybuf, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_I830_DOCOPY, i830_docopy, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_I830_FLIP, i830_flip_bufs, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_I830_IRQ_EMIT, i830_irq_emit, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_I830_IRQ_WAIT, i830_irq_wait, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_I830_GETPARAM, i830_getparam, DRM_AUTH|DRM_UNLOCKED), + DRM_IOCTL_DEF(DRM_I830_SETPARAM, i830_setparam, DRM_AUTH|DRM_UNLOCKED), }; int i830_max_ioctl = DRM_ARRAY_SIZE(i830_ioctls); @@ -1546,7 +1553,7 @@ int i830_max_ioctl = DRM_ARRAY_SIZE(i830_ioctls); * \returns * A value of 1 is always retured to indictate every i8xx is AGP. */ -int i830_driver_device_is_agp(struct drm_device * dev) +int i830_driver_device_is_agp(struct drm_device *dev) { return 1; } diff --git a/drivers/gpu/drm/i830/i830_drv.c b/drivers/gpu/drm/i830/i830_drv.c index 44f990b..a5c66aa 100644 --- a/drivers/gpu/drm/i830/i830_drv.c +++ b/drivers/gpu/drm/i830/i830_drv.c @@ -70,7 +70,7 @@ static struct drm_driver driver = { .owner = THIS_MODULE, .open = drm_open, .release = drm_release, - .unlocked_ioctl = drm_ioctl, + .unlocked_ioctl = i830_ioctl, .mmap = drm_mmap, .poll = drm_poll, .fasync = drm_fasync, diff --git a/drivers/gpu/drm/i830/i830_drv.h b/drivers/gpu/drm/i830/i830_drv.h index da82afe..0df1c72 100644 --- a/drivers/gpu/drm/i830/i830_drv.h +++ b/drivers/gpu/drm/i830/i830_drv.h @@ -122,6 +122,7 @@ typedef struct drm_i830_private { } drm_i830_private_t; +long i830_ioctl(struct file *file, unsigned int cmd, unsigned long arg); extern struct drm_ioctl_desc i830_ioctls[]; extern int i830_max_ioctl; @@ -132,33 +133,33 @@ extern int i830_irq_wait(struct drm_device *dev, void *data, struct drm_file *file_priv); extern irqreturn_t i830_driver_irq_handler(DRM_IRQ_ARGS); -extern void i830_driver_irq_preinstall(struct drm_device * dev); -extern void i830_driver_irq_postinstall(struct drm_device * dev); -extern void i830_driver_irq_uninstall(struct drm_device * dev); +extern void i830_driver_irq_preinstall(struct drm_device *dev); +extern void i830_driver_irq_postinstall(struct drm_device *dev); +extern void i830_driver_irq_uninstall(struct drm_device *dev); extern int i830_driver_load(struct drm_device *, unsigned long flags); -extern void i830_driver_preclose(struct drm_device * dev, +extern void i830_driver_preclose(struct drm_device *dev, struct drm_file *file_priv); -extern void i830_driver_lastclose(struct drm_device * dev); -extern void i830_driver_reclaim_buffers_locked(struct drm_device * dev, +extern void i830_driver_lastclose(struct drm_device *dev); +extern void i830_driver_reclaim_buffers_locked(struct drm_device *dev, struct drm_file *file_priv); -extern int i830_driver_dma_quiescent(struct drm_device * dev); -extern int i830_driver_device_is_agp(struct drm_device * dev); +extern int i830_driver_dma_quiescent(struct drm_device *dev); +extern int i830_driver_device_is_agp(struct drm_device *dev); -#define I830_READ(reg) DRM_READ32(dev_priv->mmio_map, reg) -#define I830_WRITE(reg,val) DRM_WRITE32(dev_priv->mmio_map, reg, val) -#define I830_READ16(reg) DRM_READ16(dev_priv->mmio_map, reg) -#define I830_WRITE16(reg,val) DRM_WRITE16(dev_priv->mmio_map, reg, val) +#define I830_READ(reg) DRM_READ32(dev_priv->mmio_map, reg) +#define I830_WRITE(reg, val) DRM_WRITE32(dev_priv->mmio_map, reg, val) +#define I830_READ16(reg) DRM_READ16(dev_priv->mmio_map, reg) +#define I830_WRITE16(reg, val) DRM_WRITE16(dev_priv->mmio_map, reg, val) #define I830_VERBOSE 0 #define RING_LOCALS unsigned int outring, ringmask, outcount; \ - volatile char *virt; + volatile char *virt; #define BEGIN_LP_RING(n) do { \ if (I830_VERBOSE) \ printk("BEGIN_LP_RING(%d)\n", (n)); \ if (dev_priv->ring.space < n*4) \ - i830_wait_ring(dev, n*4, __func__); \ + i830_wait_ring(dev, n*4, __func__); \ outcount = 0; \ outring = dev_priv->ring.tail; \ ringmask = dev_priv->ring.tail_mask; \ @@ -166,21 +167,23 @@ extern int i830_driver_device_is_agp(struct drm_device * dev); } while (0) #define OUT_RING(n) do { \ - if (I830_VERBOSE) printk(" OUT_RING %x\n", (int)(n)); \ + if (I830_VERBOSE) \ + printk(" OUT_RING %x\n", (int)(n)); \ *(volatile unsigned int *)(virt + outring) = n; \ - outcount++; \ + outcount++; \ outring += 4; \ outring &= ringmask; \ } while (0) -#define ADVANCE_LP_RING() do { \ - if (I830_VERBOSE) printk("ADVANCE_LP_RING %x\n", outring); \ - dev_priv->ring.tail = outring; \ - dev_priv->ring.space -= outcount * 4; \ - I830_WRITE(LP_RING + RING_TAIL, outring); \ -} while(0) +#define ADVANCE_LP_RING() do { \ + if (I830_VERBOSE) \ + printk("ADVANCE_LP_RING %x\n", outring); \ + dev_priv->ring.tail = outring; \ + dev_priv->ring.space -= outcount * 4; \ + I830_WRITE(LP_RING + RING_TAIL, outring); \ +} while (0) -extern int i830_wait_ring(struct drm_device * dev, int n, const char *caller); +extern int i830_wait_ring(struct drm_device *dev, int n, const char *caller); #define GFX_OP_USER_INTERRUPT ((0<<29)|(2<<23)) #define GFX_OP_BREAKPOINT_INTERRUPT ((0<<29)|(1<<23)) diff --git a/drivers/gpu/drm/i830/i830_irq.c b/drivers/gpu/drm/i830/i830_irq.c index 91ec2bb..d1a6b95 100644 --- a/drivers/gpu/drm/i830/i830_irq.c +++ b/drivers/gpu/drm/i830/i830_irq.c @@ -53,7 +53,7 @@ irqreturn_t i830_driver_irq_handler(DRM_IRQ_ARGS) return IRQ_HANDLED; } -static int i830_emit_irq(struct drm_device * dev) +static int i830_emit_irq(struct drm_device *dev) { drm_i830_private_t *dev_priv = dev->dev_private; RING_LOCALS; @@ -70,7 +70,7 @@ static int i830_emit_irq(struct drm_device * dev) return atomic_read(&dev_priv->irq_emitted); } -static int i830_wait_irq(struct drm_device * dev, int irq_nr) +static int i830_wait_irq(struct drm_device *dev, int irq_nr) { drm_i830_private_t *dev_priv = (drm_i830_private_t *) dev->dev_private; DECLARE_WAITQUEUE(entry, current); @@ -156,7 +156,7 @@ int i830_irq_wait(struct drm_device *dev, void *data, /* drm_dma.h hooks */ -void i830_driver_irq_preinstall(struct drm_device * dev) +void i830_driver_irq_preinstall(struct drm_device *dev) { drm_i830_private_t *dev_priv = (drm_i830_private_t *) dev->dev_private; @@ -168,14 +168,14 @@ void i830_driver_irq_preinstall(struct drm_device * dev) init_waitqueue_head(&dev_priv->irq_queue); } -void i830_driver_irq_postinstall(struct drm_device * dev) +void i830_driver_irq_postinstall(struct drm_device *dev) { drm_i830_private_t *dev_priv = (drm_i830_private_t *) dev->dev_private; I830_WRITE16(I830REG_INT_ENABLE_R, 0x2); } -void i830_driver_irq_uninstall(struct drm_device * dev) +void i830_driver_irq_uninstall(struct drm_device *dev) { drm_i830_private_t *dev_priv = (drm_i830_private_t *) dev->dev_private; if (!dev_priv) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 2305a12..f19ffe8 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -34,12 +34,15 @@ #include "i915_drm.h" #include "i915_drv.h" #include "i915_trace.h" +#include <linux/pci.h> #include <linux/vgaarb.h> #include <linux/acpi.h> #include <linux/pnp.h> #include <linux/vga_switcheroo.h> #include <linux/slab.h> +extern int intel_max_stolen; /* from AGP driver */ + /** * Sets up the hardware status page for devices that need a physical address * in the register. @@ -1256,7 +1259,7 @@ static void i915_setup_compression(struct drm_device *dev, int size) drm_mm_put_block(compressed_fb); } - if (!IS_GM45(dev)) { + if (!(IS_GM45(dev) || IS_IRONLAKE_M(dev))) { compressed_llb = drm_mm_search_free(&dev_priv->vram, 4096, 4096, 0); if (!compressed_llb) { @@ -1282,8 +1285,9 @@ static void i915_setup_compression(struct drm_device *dev, int size) intel_disable_fbc(dev); dev_priv->compressed_fb = compressed_fb; - - if (IS_GM45(dev)) { + if (IS_IRONLAKE_M(dev)) + I915_WRITE(ILK_DPFC_CB_BASE, compressed_fb->start); + else if (IS_GM45(dev)) { I915_WRITE(DPFC_CB_BASE, compressed_fb->start); } else { I915_WRITE(FBC_CFB_BASE, cfb_base); @@ -1291,7 +1295,7 @@ static void i915_setup_compression(struct drm_device *dev, int size) dev_priv->compressed_llb = compressed_llb; } - DRM_DEBUG("FBC base 0x%08lx, ll base 0x%08lx, size %dM\n", cfb_base, + DRM_DEBUG_KMS("FBC base 0x%08lx, ll base 0x%08lx, size %dM\n", cfb_base, ll_base, size >> 20); } @@ -1354,7 +1358,7 @@ static int i915_load_modeset_init(struct drm_device *dev, int fb_bar = IS_I9XX(dev) ? 2 : 0; int ret = 0; - dev->mode_config.fb_base = drm_get_resource_start(dev, fb_bar) & + dev->mode_config.fb_base = pci_resource_start(dev->pdev, fb_bar) & 0xff000000; /* Basic memrange allocator for stolen space (aka vram) */ @@ -2063,8 +2067,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) /* Add register map (needed for suspend/resume) */ mmio_bar = IS_I9XX(dev) ? 0 : 1; - base = drm_get_resource_start(dev, mmio_bar); - size = drm_get_resource_len(dev, mmio_bar); + base = pci_resource_start(dev->pdev, mmio_bar); + size = pci_resource_len(dev->pdev, mmio_bar); if (i915_get_bridge_dev(dev)) { ret = -EIO; @@ -2104,6 +2108,12 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) if (ret) goto out_iomapfree; + if (prealloc_size > intel_max_stolen) { + DRM_INFO("detected %dM stolen memory, trimming to %dM\n", + prealloc_size >> 20, intel_max_stolen >> 20); + prealloc_size = intel_max_stolen; + } + dev_priv->wq = create_singlethread_workqueue("i915"); if (dev_priv->wq == NULL) { DRM_ERROR("Failed to create our workqueue.\n"); diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 423dc90..5044f65 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -93,11 +93,11 @@ static const struct intel_device_info intel_i945gm_info = { }; static const struct intel_device_info intel_i965g_info = { - .is_i965g = 1, .is_i9xx = 1, .has_hotplug = 1, + .is_broadwater = 1, .is_i965g = 1, .is_i9xx = 1, .has_hotplug = 1, }; static const struct intel_device_info intel_i965gm_info = { - .is_i965g = 1, .is_mobile = 1, .is_i965gm = 1, .is_i9xx = 1, + .is_crestline = 1, .is_i965g = 1, .is_i965gm = 1, .is_i9xx = 1, .is_mobile = 1, .has_fbc = 1, .has_rc6 = 1, .has_hotplug = 1, }; @@ -114,7 +114,7 @@ static const struct intel_device_info intel_g45_info = { }; static const struct intel_device_info intel_gm45_info = { - .is_i965g = 1, .is_mobile = 1, .is_g4x = 1, .is_i9xx = 1, + .is_i965g = 1, .is_g4x = 1, .is_i9xx = 1, .is_mobile = 1, .need_gfx_hws = 1, .has_fbc = 1, .has_rc6 = 1, .has_pipe_cxsr = 1, .has_hotplug = 1, @@ -134,7 +134,7 @@ static const struct intel_device_info intel_ironlake_d_info = { static const struct intel_device_info intel_ironlake_m_info = { .is_ironlake = 1, .is_mobile = 1, .is_i965g = 1, .is_i9xx = 1, - .need_gfx_hws = 1, .has_rc6 = 1, + .need_gfx_hws = 1, .has_fbc = 1, .has_rc6 = 1, .has_hotplug = 1, }; @@ -148,33 +148,33 @@ static const struct intel_device_info intel_sandybridge_m_info = { .has_hotplug = 1, .is_gen6 = 1, }; -static const struct pci_device_id pciidlist[] = { - INTEL_VGA_DEVICE(0x3577, &intel_i830_info), - INTEL_VGA_DEVICE(0x2562, &intel_845g_info), - INTEL_VGA_DEVICE(0x3582, &intel_i85x_info), +static const struct pci_device_id pciidlist[] = { /* aka */ + INTEL_VGA_DEVICE(0x3577, &intel_i830_info), /* I830_M */ + INTEL_VGA_DEVICE(0x2562, &intel_845g_info), /* 845_G */ + INTEL_VGA_DEVICE(0x3582, &intel_i85x_info), /* I855_GM */ INTEL_VGA_DEVICE(0x358e, &intel_i85x_info), - INTEL_VGA_DEVICE(0x2572, &intel_i865g_info), - INTEL_VGA_DEVICE(0x2582, &intel_i915g_info), - INTEL_VGA_DEVICE(0x258a, &intel_i915g_info), - INTEL_VGA_DEVICE(0x2592, &intel_i915gm_info), - INTEL_VGA_DEVICE(0x2772, &intel_i945g_info), - INTEL_VGA_DEVICE(0x27a2, &intel_i945gm_info), - INTEL_VGA_DEVICE(0x27ae, &intel_i945gm_info), - INTEL_VGA_DEVICE(0x2972, &intel_i965g_info), - INTEL_VGA_DEVICE(0x2982, &intel_i965g_info), - INTEL_VGA_DEVICE(0x2992, &intel_i965g_info), - INTEL_VGA_DEVICE(0x29a2, &intel_i965g_info), - INTEL_VGA_DEVICE(0x29b2, &intel_g33_info), - INTEL_VGA_DEVICE(0x29c2, &intel_g33_info), - INTEL_VGA_DEVICE(0x29d2, &intel_g33_info), - INTEL_VGA_DEVICE(0x2a02, &intel_i965gm_info), - INTEL_VGA_DEVICE(0x2a12, &intel_i965gm_info), - INTEL_VGA_DEVICE(0x2a42, &intel_gm45_info), - INTEL_VGA_DEVICE(0x2e02, &intel_g45_info), - INTEL_VGA_DEVICE(0x2e12, &intel_g45_info), - INTEL_VGA_DEVICE(0x2e22, &intel_g45_info), - INTEL_VGA_DEVICE(0x2e32, &intel_g45_info), - INTEL_VGA_DEVICE(0x2e42, &intel_g45_info), + INTEL_VGA_DEVICE(0x2572, &intel_i865g_info), /* I865_G */ + INTEL_VGA_DEVICE(0x2582, &intel_i915g_info), /* I915_G */ + INTEL_VGA_DEVICE(0x258a, &intel_i915g_info), /* E7221_G */ + INTEL_VGA_DEVICE(0x2592, &intel_i915gm_info), /* I915_GM */ + INTEL_VGA_DEVICE(0x2772, &intel_i945g_info), /* I945_G */ + INTEL_VGA_DEVICE(0x27a2, &intel_i945gm_info), /* I945_GM */ + INTEL_VGA_DEVICE(0x27ae, &intel_i945gm_info), /* I945_GME */ + INTEL_VGA_DEVICE(0x2972, &intel_i965g_info), /* I946_GZ */ + INTEL_VGA_DEVICE(0x2982, &intel_i965g_info), /* G35_G */ + INTEL_VGA_DEVICE(0x2992, &intel_i965g_info), /* I965_Q */ + INTEL_VGA_DEVICE(0x29a2, &intel_i965g_info), /* I965_G */ + INTEL_VGA_DEVICE(0x29b2, &intel_g33_info), /* Q35_G */ + INTEL_VGA_DEVICE(0x29c2, &intel_g33_info), /* G33_G */ + INTEL_VGA_DEVICE(0x29d2, &intel_g33_info), /* Q33_G */ + INTEL_VGA_DEVICE(0x2a02, &intel_i965gm_info), /* I965_GM */ + INTEL_VGA_DEVICE(0x2a12, &intel_i965gm_info), /* I965_GME */ + INTEL_VGA_DEVICE(0x2a42, &intel_gm45_info), /* GM45_G */ + INTEL_VGA_DEVICE(0x2e02, &intel_g45_info), /* IGD_E_G */ + INTEL_VGA_DEVICE(0x2e12, &intel_g45_info), /* Q45_G */ + INTEL_VGA_DEVICE(0x2e22, &intel_g45_info), /* G45_G */ + INTEL_VGA_DEVICE(0x2e32, &intel_g45_info), /* G41_G */ + INTEL_VGA_DEVICE(0x2e42, &intel_g45_info), /* B43_G */ INTEL_VGA_DEVICE(0xa001, &intel_pineview_info), INTEL_VGA_DEVICE(0xa011, &intel_pineview_info), INTEL_VGA_DEVICE(0x0042, &intel_ironlake_d_info), @@ -340,7 +340,7 @@ int i965_reset(struct drm_device *dev, u8 flags) /* * Clear request list */ - i915_gem_retire_requests(dev, &dev_priv->render_ring); + i915_gem_retire_requests(dev); if (need_display) i915_save_display(dev); @@ -413,7 +413,7 @@ int i965_reset(struct drm_device *dev, u8 flags) static int __devinit i915_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { - return drm_get_dev(pdev, ent, &driver); + return drm_get_pci_dev(pdev, ent, &driver); } static void @@ -482,7 +482,7 @@ static int i915_pm_poweroff(struct device *dev) return i915_drm_freeze(drm_dev); } -const struct dev_pm_ops i915_pm_ops = { +static const struct dev_pm_ops i915_pm_ops = { .suspend = i915_pm_suspend, .resume = i915_pm_resume, .freeze = i915_pm_freeze, diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 2e1744d..906663b 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -176,7 +176,8 @@ struct drm_i915_display_funcs { int (*get_display_clock_speed)(struct drm_device *dev); int (*get_fifo_size)(struct drm_device *dev, int plane); void (*update_wm)(struct drm_device *dev, int planea_clock, - int planeb_clock, int sr_hdisplay, int pixel_size); + int planeb_clock, int sr_hdisplay, int sr_htotal, + int pixel_size); /* clock updates for mode set */ /* cursor updates */ /* render clock increase/decrease */ @@ -200,6 +201,8 @@ struct intel_device_info { u8 need_gfx_hws : 1; u8 is_g4x : 1; u8 is_pineview : 1; + u8 is_broadwater : 1; + u8 is_crestline : 1; u8 is_ironlake : 1; u8 is_gen6 : 1; u8 has_fbc : 1; @@ -288,6 +291,8 @@ typedef struct drm_i915_private { struct timer_list hangcheck_timer; int hangcheck_count; uint32_t last_acthd; + uint32_t last_instdone; + uint32_t last_instdone1; struct drm_mm vram; @@ -547,6 +552,14 @@ typedef struct drm_i915_private { struct list_head fence_list; /** + * List of objects currently pending being freed. + * + * These objects are no longer in use, but due to a signal + * we were prevented from freeing them at the appointed time. + */ + struct list_head deferred_free_list; + + /** * We leave the user IRQ off as much as possible, * but this means that requests will finish and never * be retired once the system goes idle. Set a timer to @@ -677,7 +690,7 @@ struct drm_i915_gem_object { * * Size: 4 bits for 16 fences + sign (for FENCE_REG_NONE) */ - int fence_reg : 5; + signed int fence_reg : 5; /** * Used for checking the object doesn't appear more than once @@ -713,7 +726,7 @@ struct drm_i915_gem_object { * * In the worst case this is 1 + 1 + 1 + 2*2 = 7. That would fit into 3 * bits with absolutely no headroom. So use 4 bits. */ - int pin_count : 4; + unsigned int pin_count : 4; #define DRM_I915_GEM_OBJECT_MAX_PIN_COUNT 0xf /** AGP memory structure for our GTT binding. */ @@ -743,7 +756,7 @@ struct drm_i915_gem_object { uint32_t stride; /** Record of address bit 17 of each page at last unbind. */ - long *bit_17; + unsigned long *bit_17; /** AGP mapping type (AGP_USER_MEMORY or AGP_USER_CACHED_MEMORY */ uint32_t agp_type; @@ -955,8 +968,7 @@ uint32_t i915_get_gem_seqno(struct drm_device *dev, bool i915_seqno_passed(uint32_t seq1, uint32_t seq2); int i915_gem_object_get_fence_reg(struct drm_gem_object *obj); int i915_gem_object_put_fence_reg(struct drm_gem_object *obj); -void i915_gem_retire_requests(struct drm_device *dev, - struct intel_ring_buffer *ring); +void i915_gem_retire_requests(struct drm_device *dev); void i915_gem_retire_work_handler(struct work_struct *work); void i915_gem_clflush_object(struct drm_gem_object *obj); int i915_gem_object_set_domain(struct drm_gem_object *obj, @@ -986,7 +998,7 @@ void i915_gem_free_all_phys_object(struct drm_device *dev); int i915_gem_object_get_pages(struct drm_gem_object *obj, gfp_t gfpmask); void i915_gem_object_put_pages(struct drm_gem_object *obj); void i915_gem_release(struct drm_device * dev, struct drm_file *file_priv); -void i915_gem_object_flush_write_domain(struct drm_gem_object *obj); +int i915_gem_object_flush_write_domain(struct drm_gem_object *obj); void i915_gem_shrinker_init(void); void i915_gem_shrinker_exit(void); @@ -1046,6 +1058,7 @@ extern void intel_modeset_cleanup(struct drm_device *dev); extern int intel_modeset_vga_set_state(struct drm_device *dev, bool state); extern void i8xx_disable_fbc(struct drm_device *dev); extern void g4x_disable_fbc(struct drm_device *dev); +extern void ironlake_disable_fbc(struct drm_device *dev); extern void intel_disable_fbc(struct drm_device *dev); extern void intel_enable_fbc(struct drm_crtc *crtc, unsigned long interval); extern bool intel_fbc_enabled(struct drm_device *dev); @@ -1135,6 +1148,8 @@ extern int intel_trans_dp_port_sel (struct drm_crtc *crtc); #define IS_I945GM(dev) (INTEL_INFO(dev)->is_i945gm) #define IS_I965G(dev) (INTEL_INFO(dev)->is_i965g) #define IS_I965GM(dev) (INTEL_INFO(dev)->is_i965gm) +#define IS_BROADWATER(dev) (INTEL_INFO(dev)->is_broadwater) +#define IS_CRESTLINE(dev) (INTEL_INFO(dev)->is_crestline) #define IS_GM45(dev) ((dev)->pci_device == 0x2A42) #define IS_G4X(dev) (INTEL_INFO(dev)->is_g4x) #define IS_PINEVIEW_G(dev) ((dev)->pci_device == 0xa001) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 5aa747f..2a4ed7c 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -35,7 +35,7 @@ #include <linux/swap.h> #include <linux/pci.h> -static void i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj); +static int i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj); static void i915_gem_object_flush_gtt_write_domain(struct drm_gem_object *obj); static void i915_gem_object_flush_cpu_write_domain(struct drm_gem_object *obj); static int i915_gem_object_set_to_cpu_domain(struct drm_gem_object *obj, @@ -53,6 +53,7 @@ static int i915_gem_evict_from_inactive_list(struct drm_device *dev); static int i915_gem_phys_pwrite(struct drm_device *dev, struct drm_gem_object *obj, struct drm_i915_gem_pwrite *args, struct drm_file *file_priv); +static void i915_gem_free_object_tail(struct drm_gem_object *obj); static LIST_HEAD(shrink_list); static DEFINE_SPINLOCK(shrink_list_lock); @@ -127,8 +128,7 @@ i915_gem_create_ioctl(struct drm_device *dev, void *data, return -ENOMEM; ret = drm_gem_handle_create(file_priv, obj, &handle); - drm_gem_object_handle_unreference_unlocked(obj); - + drm_gem_object_unreference_unlocked(obj); if (ret) return ret; @@ -496,10 +496,10 @@ fast_user_write(struct io_mapping *mapping, char *vaddr_atomic; unsigned long unwritten; - vaddr_atomic = io_mapping_map_atomic_wc(mapping, page_base); + vaddr_atomic = io_mapping_map_atomic_wc(mapping, page_base, KM_USER0); unwritten = __copy_from_user_inatomic_nocache(vaddr_atomic + page_offset, user_data, length); - io_mapping_unmap_atomic(vaddr_atomic); + io_mapping_unmap_atomic(vaddr_atomic, KM_USER0); if (unwritten) return -EFAULT; return 0; @@ -1709,9 +1709,9 @@ i915_get_gem_seqno(struct drm_device *dev, /** * This function clears the request list as sequence numbers are passed. */ -void -i915_gem_retire_requests(struct drm_device *dev, - struct intel_ring_buffer *ring) +static void +i915_gem_retire_requests_ring(struct drm_device *dev, + struct intel_ring_buffer *ring) { drm_i915_private_t *dev_priv = dev->dev_private; uint32_t seqno; @@ -1751,6 +1751,30 @@ i915_gem_retire_requests(struct drm_device *dev, } void +i915_gem_retire_requests(struct drm_device *dev) +{ + drm_i915_private_t *dev_priv = dev->dev_private; + + if (!list_empty(&dev_priv->mm.deferred_free_list)) { + struct drm_i915_gem_object *obj_priv, *tmp; + + /* We must be careful that during unbind() we do not + * accidentally infinitely recurse into retire requests. + * Currently: + * retire -> free -> unbind -> wait -> retire_ring + */ + list_for_each_entry_safe(obj_priv, tmp, + &dev_priv->mm.deferred_free_list, + list) + i915_gem_free_object_tail(&obj_priv->base); + } + + i915_gem_retire_requests_ring(dev, &dev_priv->render_ring); + if (HAS_BSD(dev)) + i915_gem_retire_requests_ring(dev, &dev_priv->bsd_ring); +} + +void i915_gem_retire_work_handler(struct work_struct *work) { drm_i915_private_t *dev_priv; @@ -1761,10 +1785,7 @@ i915_gem_retire_work_handler(struct work_struct *work) dev = dev_priv->dev; mutex_lock(&dev->struct_mutex); - i915_gem_retire_requests(dev, &dev_priv->render_ring); - - if (HAS_BSD(dev)) - i915_gem_retire_requests(dev, &dev_priv->bsd_ring); + i915_gem_retire_requests(dev); if (!dev_priv->mm.suspended && (!list_empty(&dev_priv->render_ring.request_list) || @@ -1832,7 +1853,7 @@ i915_do_wait_request(struct drm_device *dev, uint32_t seqno, * a separate wait queue to handle that. */ if (ret == 0) - i915_gem_retire_requests(dev, ring); + i915_gem_retire_requests_ring(dev, ring); return ret; } @@ -1945,11 +1966,12 @@ i915_gem_object_unbind(struct drm_gem_object *obj) * before we unbind. */ ret = i915_gem_object_set_to_cpu_domain(obj, 1); - if (ret) { - if (ret != -ERESTARTSYS) - DRM_ERROR("set_domain failed: %d\n", ret); + if (ret == -ERESTARTSYS) return ret; - } + /* Continue on if we fail due to EIO, the GPU is hung so we + * should be safe and we need to cleanup or else we might + * cause memory corruption through use-after-free. + */ BUG_ON(obj_priv->active); @@ -1985,7 +2007,7 @@ i915_gem_object_unbind(struct drm_gem_object *obj) trace_i915_gem_object_unbind(obj); - return 0; + return ret; } static struct drm_gem_object * @@ -2107,10 +2129,7 @@ i915_gem_evict_something(struct drm_device *dev, int min_size) struct intel_ring_buffer *render_ring = &dev_priv->render_ring; struct intel_ring_buffer *bsd_ring = &dev_priv->bsd_ring; for (;;) { - i915_gem_retire_requests(dev, render_ring); - - if (HAS_BSD(dev)) - i915_gem_retire_requests(dev, bsd_ring); + i915_gem_retire_requests(dev); /* If there's an inactive buffer available now, grab it * and be done. @@ -2583,7 +2602,10 @@ i915_gem_object_put_fence_reg(struct drm_gem_object *obj) if (!IS_I965G(dev)) { int ret; - i915_gem_object_flush_gpu_write_domain(obj); + ret = i915_gem_object_flush_gpu_write_domain(obj); + if (ret != 0) + return ret; + ret = i915_gem_object_wait_rendering(obj); if (ret != 0) return ret; @@ -2634,10 +2656,8 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment) if (free_space != NULL) { obj_priv->gtt_space = drm_mm_get_block(free_space, obj->size, alignment); - if (obj_priv->gtt_space != NULL) { - obj_priv->gtt_space->private = obj; + if (obj_priv->gtt_space != NULL) obj_priv->gtt_offset = obj_priv->gtt_space->start; - } } if (obj_priv->gtt_space == NULL) { /* If the gtt is empty and we're still having trouble @@ -2733,7 +2753,7 @@ i915_gem_clflush_object(struct drm_gem_object *obj) } /** Flushes any GPU write domain for the object if it's dirty. */ -static void +static int i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj) { struct drm_device *dev = obj->dev; @@ -2741,17 +2761,18 @@ i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj) struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); if ((obj->write_domain & I915_GEM_GPU_DOMAINS) == 0) - return; + return 0; /* Queue the GPU write cache flushing we need. */ old_write_domain = obj->write_domain; i915_gem_flush(dev, 0, obj->write_domain); - (void) i915_add_request(dev, NULL, obj->write_domain, obj_priv->ring); - BUG_ON(obj->write_domain); + if (i915_add_request(dev, NULL, obj->write_domain, obj_priv->ring) == 0) + return -ENOMEM; trace_i915_gem_object_change_domain(obj, obj->read_domains, old_write_domain); + return 0; } /** Flushes the GTT write domain for the object if it's dirty. */ @@ -2795,9 +2816,11 @@ i915_gem_object_flush_cpu_write_domain(struct drm_gem_object *obj) old_write_domain); } -void +int i915_gem_object_flush_write_domain(struct drm_gem_object *obj) { + int ret = 0; + switch (obj->write_domain) { case I915_GEM_DOMAIN_GTT: i915_gem_object_flush_gtt_write_domain(obj); @@ -2806,9 +2829,11 @@ i915_gem_object_flush_write_domain(struct drm_gem_object *obj) i915_gem_object_flush_cpu_write_domain(obj); break; default: - i915_gem_object_flush_gpu_write_domain(obj); + ret = i915_gem_object_flush_gpu_write_domain(obj); break; } + + return ret; } /** @@ -2828,7 +2853,10 @@ i915_gem_object_set_to_gtt_domain(struct drm_gem_object *obj, int write) if (obj_priv->gtt_space == NULL) return -EINVAL; - i915_gem_object_flush_gpu_write_domain(obj); + ret = i915_gem_object_flush_gpu_write_domain(obj); + if (ret != 0) + return ret; + /* Wait on any GPU rendering and flushing to occur. */ ret = i915_gem_object_wait_rendering(obj); if (ret != 0) @@ -2878,7 +2906,9 @@ i915_gem_object_set_to_display_plane(struct drm_gem_object *obj) if (obj_priv->gtt_space == NULL) return -EINVAL; - i915_gem_object_flush_gpu_write_domain(obj); + ret = i915_gem_object_flush_gpu_write_domain(obj); + if (ret) + return ret; /* Wait on any GPU rendering and flushing to occur. */ if (obj_priv->active) { @@ -2926,7 +2956,10 @@ i915_gem_object_set_to_cpu_domain(struct drm_gem_object *obj, int write) uint32_t old_write_domain, old_read_domains; int ret; - i915_gem_object_flush_gpu_write_domain(obj); + ret = i915_gem_object_flush_gpu_write_domain(obj); + if (ret) + return ret; + /* Wait on any GPU rendering and flushing to occur. */ ret = i915_gem_object_wait_rendering(obj); if (ret != 0) @@ -3216,7 +3249,10 @@ i915_gem_object_set_cpu_read_domain_range(struct drm_gem_object *obj, if (offset == 0 && size == obj->size) return i915_gem_object_set_to_cpu_domain(obj, 0); - i915_gem_object_flush_gpu_write_domain(obj); + ret = i915_gem_object_flush_gpu_write_domain(obj); + if (ret) + return ret; + /* Wait on any GPU rendering and flushing to occur. */ ret = i915_gem_object_wait_rendering(obj); if (ret != 0) @@ -3451,7 +3487,8 @@ i915_gem_object_pin_and_relocate(struct drm_gem_object *obj, reloc_offset = obj_priv->gtt_offset + reloc->offset; reloc_page = io_mapping_map_atomic_wc(dev_priv->mm.gtt_mapping, (reloc_offset & - ~(PAGE_SIZE - 1))); + ~(PAGE_SIZE - 1)), + KM_USER0); reloc_entry = (uint32_t __iomem *)(reloc_page + (reloc_offset & (PAGE_SIZE - 1))); reloc_val = target_obj_priv->gtt_offset + reloc->delta; @@ -3462,7 +3499,7 @@ i915_gem_object_pin_and_relocate(struct drm_gem_object *obj, readl(reloc_entry), reloc_val); #endif writel(reloc_val, reloc_entry); - io_mapping_unmap_atomic(reloc_page); + io_mapping_unmap_atomic(reloc_page, KM_USER0); /* The updated presumed offset for this entry will be * copied back out to the user. @@ -4313,7 +4350,6 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data, struct drm_i915_gem_busy *args = data; struct drm_gem_object *obj; struct drm_i915_gem_object *obj_priv; - drm_i915_private_t *dev_priv = dev->dev_private; obj = drm_gem_object_lookup(dev, file_priv, args->handle); if (obj == NULL) { @@ -4328,10 +4364,7 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data, * actually unmasked, and our working set ends up being larger than * required. */ - i915_gem_retire_requests(dev, &dev_priv->render_ring); - - if (HAS_BSD(dev)) - i915_gem_retire_requests(dev, &dev_priv->bsd_ring); + i915_gem_retire_requests(dev); obj_priv = to_intel_bo(obj); /* Don't count being on the flushing list against the object being @@ -4441,20 +4474,19 @@ int i915_gem_init_object(struct drm_gem_object *obj) return 0; } -void i915_gem_free_object(struct drm_gem_object *obj) +static void i915_gem_free_object_tail(struct drm_gem_object *obj) { struct drm_device *dev = obj->dev; + drm_i915_private_t *dev_priv = dev->dev_private; struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); + int ret; - trace_i915_gem_object_destroy(obj); - - while (obj_priv->pin_count > 0) - i915_gem_object_unpin(obj); - - if (obj_priv->phys_obj) - i915_gem_detach_phys_object(dev, obj); - - i915_gem_object_unbind(obj); + ret = i915_gem_object_unbind(obj); + if (ret == -ERESTARTSYS) { + list_move(&obj_priv->list, + &dev_priv->mm.deferred_free_list); + return; + } if (obj_priv->mmap_offset) i915_gem_free_mmap_offset(obj); @@ -4466,6 +4498,22 @@ void i915_gem_free_object(struct drm_gem_object *obj) kfree(obj_priv); } +void i915_gem_free_object(struct drm_gem_object *obj) +{ + struct drm_device *dev = obj->dev; + struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); + + trace_i915_gem_object_destroy(obj); + + while (obj_priv->pin_count > 0) + i915_gem_object_unpin(obj); + + if (obj_priv->phys_obj) + i915_gem_detach_phys_object(dev, obj); + + i915_gem_free_object_tail(obj); +} + /** Unbinds all inactive objects. */ static int i915_gem_evict_from_inactive_list(struct drm_device *dev) @@ -4689,9 +4737,19 @@ i915_gem_entervt_ioctl(struct drm_device *dev, void *data, BUG_ON(HAS_BSD(dev) && !list_empty(&dev_priv->bsd_ring.request_list)); mutex_unlock(&dev->struct_mutex); - drm_irq_install(dev); + ret = drm_irq_install(dev); + if (ret) + goto cleanup_ringbuffer; return 0; + +cleanup_ringbuffer: + mutex_lock(&dev->struct_mutex); + i915_gem_cleanup_ringbuffer(dev); + dev_priv->mm.suspended = 1; + mutex_unlock(&dev->struct_mutex); + + return ret; } int @@ -4729,6 +4787,7 @@ i915_gem_load(struct drm_device *dev) INIT_LIST_HEAD(&dev_priv->mm.gpu_write_list); INIT_LIST_HEAD(&dev_priv->mm.inactive_list); INIT_LIST_HEAD(&dev_priv->mm.fence_list); + INIT_LIST_HEAD(&dev_priv->mm.deferred_free_list); INIT_LIST_HEAD(&dev_priv->render_ring.active_list); INIT_LIST_HEAD(&dev_priv->render_ring.request_list); if (HAS_BSD(dev)) { @@ -5027,10 +5086,7 @@ rescan: continue; spin_unlock(&shrink_list_lock); - i915_gem_retire_requests(dev, &dev_priv->render_ring); - - if (HAS_BSD(dev)) - i915_gem_retire_requests(dev, &dev_priv->bsd_ring); + i915_gem_retire_requests(dev); list_for_each_entry_safe(obj_priv, next_obj, &dev_priv->mm.inactive_list, diff --git a/drivers/gpu/drm/i915/i915_gem_tiling.c b/drivers/gpu/drm/i915/i915_gem_tiling.c index 4b7c49d..155719e 100644 --- a/drivers/gpu/drm/i915/i915_gem_tiling.c +++ b/drivers/gpu/drm/i915/i915_gem_tiling.c @@ -333,8 +333,6 @@ i915_gem_set_tiling(struct drm_device *dev, void *data, i915_gem_release_mmap(obj); if (ret != 0) { - WARN(ret != -ERESTARTSYS, - "failed to reset object for tiling switch"); args->tiling_mode = obj_priv->tiling_mode; args->stride = obj_priv->stride; goto err; diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index dba53d4..85785a8 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -171,10 +171,10 @@ void intel_enable_asle (struct drm_device *dev) ironlake_enable_display_irq(dev_priv, DE_GSE); else { i915_enable_pipestat(dev_priv, 1, - I915_LEGACY_BLC_EVENT_ENABLE); + PIPE_LEGACY_BLC_EVENT_ENABLE); if (IS_I965G(dev)) i915_enable_pipestat(dev_priv, 0, - I915_LEGACY_BLC_EVENT_ENABLE); + PIPE_LEGACY_BLC_EVENT_ENABLE); } } @@ -842,7 +842,6 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) u32 iir, new_iir; u32 pipea_stats, pipeb_stats; u32 vblank_status; - u32 vblank_enable; int vblank = 0; unsigned long irqflags; int irq_received; @@ -856,13 +855,10 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) iir = I915_READ(IIR); - if (IS_I965G(dev)) { - vblank_status = I915_START_VBLANK_INTERRUPT_STATUS; - vblank_enable = PIPE_START_VBLANK_INTERRUPT_ENABLE; - } else { - vblank_status = I915_VBLANK_INTERRUPT_STATUS; - vblank_enable = I915_VBLANK_INTERRUPT_ENABLE; - } + if (IS_I965G(dev)) + vblank_status = PIPE_START_VBLANK_INTERRUPT_STATUS; + else + vblank_status = PIPE_VBLANK_INTERRUPT_STATUS; for (;;) { irq_received = iir != 0; @@ -966,8 +962,8 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS) intel_finish_page_flip(dev, 1); } - if ((pipea_stats & I915_LEGACY_BLC_EVENT_STATUS) || - (pipeb_stats & I915_LEGACY_BLC_EVENT_STATUS) || + if ((pipea_stats & PIPE_LEGACY_BLC_EVENT_STATUS) || + (pipeb_stats & PIPE_LEGACY_BLC_EVENT_STATUS) || (iir & I915_ASLE_INTERRUPT)) opregion_asle_intr(dev); @@ -1233,16 +1229,21 @@ void i915_hangcheck_elapsed(unsigned long data) { struct drm_device *dev = (struct drm_device *)data; drm_i915_private_t *dev_priv = dev->dev_private; - uint32_t acthd; + uint32_t acthd, instdone, instdone1; /* No reset support on this chip yet. */ if (IS_GEN6(dev)) return; - if (!IS_I965G(dev)) + if (!IS_I965G(dev)) { acthd = I915_READ(ACTHD); - else + instdone = I915_READ(INSTDONE); + instdone1 = 0; + } else { acthd = I915_READ(ACTHD_I965); + instdone = I915_READ(INSTDONE_I965); + instdone1 = I915_READ(INSTDONE1); + } /* If all work is done then ACTHD clearly hasn't advanced. */ if (list_empty(&dev_priv->render_ring.request_list) || @@ -1253,21 +1254,24 @@ void i915_hangcheck_elapsed(unsigned long data) return; } - if (dev_priv->last_acthd == acthd && dev_priv->hangcheck_count > 0) { - DRM_ERROR("Hangcheck timer elapsed... GPU hung\n"); - i915_handle_error(dev, true); - return; - } + if (dev_priv->last_acthd == acthd && + dev_priv->last_instdone == instdone && + dev_priv->last_instdone1 == instdone1) { + if (dev_priv->hangcheck_count++ > 1) { + DRM_ERROR("Hangcheck timer elapsed... GPU hung\n"); + i915_handle_error(dev, true); + return; + } + } else { + dev_priv->hangcheck_count = 0; + + dev_priv->last_acthd = acthd; + dev_priv->last_instdone = instdone; + dev_priv->last_instdone1 = instdone1; + } /* Reset timer case chip hangs without another request being added */ mod_timer(&dev_priv->hangcheck_timer, jiffies + DRM_I915_HANGCHECK_PERIOD); - - if (acthd != dev_priv->last_acthd) - dev_priv->hangcheck_count = 0; - else - dev_priv->hangcheck_count++; - - dev_priv->last_acthd = acthd; } /* drm_dma.h hooks diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index cf41c67..281db6e 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -442,7 +442,7 @@ #define GEN6_RENDER_IMR 0x20a8 #define GEN6_RENDER_CONTEXT_SWITCH_INTERRUPT (1 << 8) #define GEN6_RENDER_PPGTT_PAGE_FAULT (1 << 7) -#define GEN6_RENDER TIMEOUT_COUNTER_EXPIRED (1 << 6) +#define GEN6_RENDER_TIMEOUT_COUNTER_EXPIRED (1 << 6) #define GEN6_RENDER_L3_PARITY_ERROR (1 << 5) #define GEN6_RENDER_PIPE_CONTROL_NOTIFY_INTERRUPT (1 << 4) #define GEN6_RENDER_COMMAND_PARSER_MASTER_ERROR (1 << 3) @@ -530,6 +530,21 @@ #define DPFC_CHICKEN 0x3224 #define DPFC_HT_MODIFY (1<<31) +/* Framebuffer compression for Ironlake */ +#define ILK_DPFC_CB_BASE 0x43200 +#define ILK_DPFC_CONTROL 0x43208 +/* The bit 28-8 is reserved */ +#define DPFC_RESERVED (0x1FFFFF00) +#define ILK_DPFC_RECOMP_CTL 0x4320c +#define ILK_DPFC_STATUS 0x43210 +#define ILK_DPFC_FENCE_YOFF 0x43218 +#define ILK_DPFC_CHICKEN 0x43224 +#define ILK_FBC_RT_BASE 0x2128 +#define ILK_FBC_RT_VALID (1<<0) + +#define ILK_DISPLAY_CHICKEN1 0x42000 +#define ILK_FBCQ_DIS (1<<22) + /* * GPIO regs */ @@ -595,32 +610,6 @@ #define DPLL_FPA01_P1_POST_DIV_MASK 0x00ff0000 /* i915 */ #define DPLL_FPA01_P1_POST_DIV_MASK_PINEVIEW 0x00ff8000 /* Pineview */ -#define I915_FIFO_UNDERRUN_STATUS (1UL<<31) -#define I915_CRC_ERROR_ENABLE (1UL<<29) -#define I915_CRC_DONE_ENABLE (1UL<<28) -#define I915_GMBUS_EVENT_ENABLE (1UL<<27) -#define I915_VSYNC_INTERRUPT_ENABLE (1UL<<25) -#define I915_DISPLAY_LINE_COMPARE_ENABLE (1UL<<24) -#define I915_DPST_EVENT_ENABLE (1UL<<23) -#define I915_LEGACY_BLC_EVENT_ENABLE (1UL<<22) -#define I915_ODD_FIELD_INTERRUPT_ENABLE (1UL<<21) -#define I915_EVEN_FIELD_INTERRUPT_ENABLE (1UL<<20) -#define I915_START_VBLANK_INTERRUPT_ENABLE (1UL<<18) /* 965 or later */ -#define I915_VBLANK_INTERRUPT_ENABLE (1UL<<17) -#define I915_OVERLAY_UPDATED_ENABLE (1UL<<16) -#define I915_CRC_ERROR_INTERRUPT_STATUS (1UL<<13) -#define I915_CRC_DONE_INTERRUPT_STATUS (1UL<<12) -#define I915_GMBUS_INTERRUPT_STATUS (1UL<<11) -#define I915_VSYNC_INTERRUPT_STATUS (1UL<<9) -#define I915_DISPLAY_LINE_COMPARE_STATUS (1UL<<8) -#define I915_DPST_EVENT_STATUS (1UL<<7) -#define I915_LEGACY_BLC_EVENT_STATUS (1UL<<6) -#define I915_ODD_FIELD_INTERRUPT_STATUS (1UL<<5) -#define I915_EVEN_FIELD_INTERRUPT_STATUS (1UL<<4) -#define I915_START_VBLANK_INTERRUPT_STATUS (1UL<<2) /* 965 or later */ -#define I915_VBLANK_INTERRUPT_STATUS (1UL<<1) -#define I915_OVERLAY_UPDATED_STATUS (1UL<<0) - #define SRX_INDEX 0x3c4 #define SRX_DATA 0x3c5 #define SR01 1 @@ -2166,7 +2155,8 @@ #define I830_FIFO_LINE_SIZE 32 #define G4X_FIFO_SIZE 127 -#define I945_FIFO_SIZE 127 /* 945 & 965 */ +#define I965_FIFO_SIZE 512 +#define I945_FIFO_SIZE 127 #define I915_FIFO_SIZE 95 #define I855GM_FIFO_SIZE 127 /* In cachelines */ #define I830_FIFO_SIZE 95 @@ -2185,6 +2175,9 @@ #define PINEVIEW_CURSOR_DFT_WM 0 #define PINEVIEW_CURSOR_GUARD_WM 5 +#define I965_CURSOR_FIFO 64 +#define I965_CURSOR_MAX_WM 32 +#define I965_CURSOR_DFT_WM 8 /* define the Watermark register on Ironlake */ #define WM0_PIPEA_ILK 0x45100 @@ -2212,6 +2205,9 @@ #define ILK_DISPLAY_FIFO 128 #define ILK_DISPLAY_MAXWM 64 #define ILK_DISPLAY_DFTWM 8 +#define ILK_CURSOR_FIFO 32 +#define ILK_CURSOR_MAXWM 16 +#define ILK_CURSOR_DFTWM 8 #define ILK_DISPLAY_SR_FIFO 512 #define ILK_DISPLAY_MAX_SRWM 0x1ff @@ -2510,6 +2506,10 @@ #define ILK_VSDPFD_FULL (1<<21) #define ILK_DSPCLK_GATE 0x42020 #define ILK_DPARB_CLK_GATE (1<<5) +/* According to spec this bit 7/8/9 of 0x42020 should be set to enable FBC */ +#define ILK_CLK_FBC (1<<7) +#define ILK_DPFC_DIS1 (1<<8) +#define ILK_DPFC_DIS2 (1<<9) #define DISP_ARB_CTL 0x45000 #define DISP_TILE_SURFACE_SWIZZLING (1<<13) diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c index 60a5800..6e20252 100644 --- a/drivers/gpu/drm/i915/i915_suspend.c +++ b/drivers/gpu/drm/i915/i915_suspend.c @@ -602,7 +602,9 @@ void i915_save_display(struct drm_device *dev) /* Only save FBC state on the platform that supports FBC */ if (I915_HAS_FBC(dev)) { - if (IS_GM45(dev)) { + if (IS_IRONLAKE_M(dev)) { + dev_priv->saveDPFC_CB_BASE = I915_READ(ILK_DPFC_CB_BASE); + } else if (IS_GM45(dev)) { dev_priv->saveDPFC_CB_BASE = I915_READ(DPFC_CB_BASE); } else { dev_priv->saveFBC_CFB_BASE = I915_READ(FBC_CFB_BASE); @@ -706,7 +708,10 @@ void i915_restore_display(struct drm_device *dev) /* only restore FBC info on the platform that supports FBC*/ if (I915_HAS_FBC(dev)) { - if (IS_GM45(dev)) { + if (IS_IRONLAKE_M(dev)) { + ironlake_disable_fbc(dev); + I915_WRITE(ILK_DPFC_CB_BASE, dev_priv->saveDPFC_CB_BASE); + } else if (IS_GM45(dev)) { g4x_disable_fbc(dev); I915_WRITE(DPFC_CB_BASE, dev_priv->saveDPFC_CB_BASE); } else { diff --git a/drivers/gpu/drm/i915/i915_trace.h b/drivers/gpu/drm/i915/i915_trace.h index fab2176..fea97a2 100644 --- a/drivers/gpu/drm/i915/i915_trace.h +++ b/drivers/gpu/drm/i915/i915_trace.h @@ -262,6 +262,42 @@ DEFINE_EVENT(i915_ring, i915_ring_wait_end, TP_ARGS(dev) ); +TRACE_EVENT(i915_flip_request, + TP_PROTO(int plane, struct drm_gem_object *obj), + + TP_ARGS(plane, obj), + + TP_STRUCT__entry( + __field(int, plane) + __field(struct drm_gem_object *, obj) + ), + + TP_fast_assign( + __entry->plane = plane; + __entry->obj = obj; + ), + + TP_printk("plane=%d, obj=%p", __entry->plane, __entry->obj) +); + +TRACE_EVENT(i915_flip_complete, + TP_PROTO(int plane, struct drm_gem_object *obj), + + TP_ARGS(plane, obj), + + TP_STRUCT__entry( + __field(int, plane) + __field(struct drm_gem_object *, obj) + ), + + TP_fast_assign( + __entry->plane = plane; + __entry->obj = obj; + ), + + TP_printk("plane=%d, obj=%p", __entry->plane, __entry->obj) +); + #endif /* _I915_TRACE_H_ */ /* This part must be outside protection */ diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 5e21b31..1e5e0d3 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -33,6 +33,7 @@ #include "intel_drv.h" #include "i915_drm.h" #include "i915_drv.h" +#include "i915_trace.h" #include "drm_dp_helper.h" #include "drm_crtc_helper.h" @@ -42,6 +43,7 @@ bool intel_pipe_has_type (struct drm_crtc *crtc, int type); static void intel_update_watermarks(struct drm_device *dev); static void intel_increase_pllclock(struct drm_crtc *crtc, bool schedule); +static void intel_crtc_update_cursor(struct drm_crtc *crtc); typedef struct { /* given values */ @@ -322,6 +324,9 @@ struct intel_limit { #define IRONLAKE_DP_P1_MIN 1 #define IRONLAKE_DP_P1_MAX 2 +/* FDI */ +#define IRONLAKE_FDI_FREQ 2700000 /* in kHz for mode->clock */ + static bool intel_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc, int target, int refclk, intel_clock_t *best_clock); @@ -975,7 +980,10 @@ void intel_wait_for_vblank(struct drm_device *dev) { /* Wait for 20ms, i.e. one cycle at 50hz. */ - msleep(20); + if (in_dbg_master()) + mdelay(20); /* The kernel debugger cannot call msleep() */ + else + msleep(20); } /* Parameters have changed, update FBC info */ @@ -1122,6 +1130,67 @@ static bool g4x_fbc_enabled(struct drm_device *dev) return I915_READ(DPFC_CONTROL) & DPFC_CTL_EN; } +static void ironlake_enable_fbc(struct drm_crtc *crtc, unsigned long interval) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_framebuffer *fb = crtc->fb; + struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb); + struct drm_i915_gem_object *obj_priv = to_intel_bo(intel_fb->obj); + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + int plane = (intel_crtc->plane == 0) ? DPFC_CTL_PLANEA : + DPFC_CTL_PLANEB; + unsigned long stall_watermark = 200; + u32 dpfc_ctl; + + dev_priv->cfb_pitch = (dev_priv->cfb_pitch / 64) - 1; + dev_priv->cfb_fence = obj_priv->fence_reg; + dev_priv->cfb_plane = intel_crtc->plane; + + dpfc_ctl = I915_READ(ILK_DPFC_CONTROL); + dpfc_ctl &= DPFC_RESERVED; + dpfc_ctl |= (plane | DPFC_CTL_LIMIT_1X); + if (obj_priv->tiling_mode != I915_TILING_NONE) { + dpfc_ctl |= (DPFC_CTL_FENCE_EN | dev_priv->cfb_fence); + I915_WRITE(ILK_DPFC_CHICKEN, DPFC_HT_MODIFY); + } else { + I915_WRITE(ILK_DPFC_CHICKEN, ~DPFC_HT_MODIFY); + } + + I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl); + I915_WRITE(ILK_DPFC_RECOMP_CTL, DPFC_RECOMP_STALL_EN | + (stall_watermark << DPFC_RECOMP_STALL_WM_SHIFT) | + (interval << DPFC_RECOMP_TIMER_COUNT_SHIFT)); + I915_WRITE(ILK_DPFC_FENCE_YOFF, crtc->y); + I915_WRITE(ILK_FBC_RT_BASE, obj_priv->gtt_offset | ILK_FBC_RT_VALID); + /* enable it... */ + I915_WRITE(ILK_DPFC_CONTROL, I915_READ(ILK_DPFC_CONTROL) | + DPFC_CTL_EN); + + DRM_DEBUG_KMS("enabled fbc on plane %d\n", intel_crtc->plane); +} + +void ironlake_disable_fbc(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u32 dpfc_ctl; + + /* Disable compression */ + dpfc_ctl = I915_READ(ILK_DPFC_CONTROL); + dpfc_ctl &= ~DPFC_CTL_EN; + I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl); + intel_wait_for_vblank(dev); + + DRM_DEBUG_KMS("disabled FBC\n"); +} + +static bool ironlake_fbc_enabled(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + return I915_READ(ILK_DPFC_CONTROL) & DPFC_CTL_EN; +} + bool intel_fbc_enabled(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -1248,6 +1317,10 @@ static void intel_update_fbc(struct drm_crtc *crtc, goto out_disable; } + /* If the kernel debugger is active, always disable compression */ + if (in_dbg_master()) + goto out_disable; + if (intel_fbc_enabled(dev)) { /* We can re-enable it in this case, but need to update pitch */ if ((fb->pitch > dev_priv->cfb_pitch) || @@ -1279,7 +1352,12 @@ intel_pin_and_fence_fb_obj(struct drm_device *dev, struct drm_gem_object *obj) switch (obj_priv->tiling_mode) { case I915_TILING_NONE: - alignment = 64 * 1024; + if (IS_BROADWATER(dev) || IS_CRESTLINE(dev)) + alignment = 128 * 1024; + else if (IS_I965G(dev)) + alignment = 4 * 1024; + else + alignment = 64 * 1024; break; case I915_TILING_X: /* pin() will align the object as required by fence */ @@ -1314,6 +1392,98 @@ intel_pin_and_fence_fb_obj(struct drm_device *dev, struct drm_gem_object *obj) return 0; } +/* Assume fb object is pinned & idle & fenced and just update base pointers */ +static int +intel_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb, + int x, int y) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct intel_framebuffer *intel_fb; + struct drm_i915_gem_object *obj_priv; + struct drm_gem_object *obj; + int plane = intel_crtc->plane; + unsigned long Start, Offset; + int dspbase = (plane == 0 ? DSPAADDR : DSPBADDR); + int dspsurf = (plane == 0 ? DSPASURF : DSPBSURF); + int dspstride = (plane == 0) ? DSPASTRIDE : DSPBSTRIDE; + int dsptileoff = (plane == 0 ? DSPATILEOFF : DSPBTILEOFF); + int dspcntr_reg = (plane == 0) ? DSPACNTR : DSPBCNTR; + u32 dspcntr; + + switch (plane) { + case 0: + case 1: + break; + default: + DRM_ERROR("Can't update plane %d in SAREA\n", plane); + return -EINVAL; + } + + intel_fb = to_intel_framebuffer(fb); + obj = intel_fb->obj; + obj_priv = to_intel_bo(obj); + + dspcntr = I915_READ(dspcntr_reg); + /* Mask out pixel format bits in case we change it */ + dspcntr &= ~DISPPLANE_PIXFORMAT_MASK; + switch (fb->bits_per_pixel) { + case 8: + dspcntr |= DISPPLANE_8BPP; + break; + case 16: + if (fb->depth == 15) + dspcntr |= DISPPLANE_15_16BPP; + else + dspcntr |= DISPPLANE_16BPP; + break; + case 24: + case 32: + dspcntr |= DISPPLANE_32BPP_NO_ALPHA; + break; + default: + DRM_ERROR("Unknown color depth\n"); + return -EINVAL; + } + if (IS_I965G(dev)) { + if (obj_priv->tiling_mode != I915_TILING_NONE) + dspcntr |= DISPPLANE_TILED; + else + dspcntr &= ~DISPPLANE_TILED; + } + + if (IS_IRONLAKE(dev)) + /* must disable */ + dspcntr |= DISPPLANE_TRICKLE_FEED_DISABLE; + + I915_WRITE(dspcntr_reg, dspcntr); + + Start = obj_priv->gtt_offset; + Offset = y * fb->pitch + x * (fb->bits_per_pixel / 8); + + DRM_DEBUG("Writing base %08lX %08lX %d %d\n", Start, Offset, x, y); + I915_WRITE(dspstride, fb->pitch); + if (IS_I965G(dev)) { + I915_WRITE(dspbase, Offset); + I915_READ(dspbase); + I915_WRITE(dspsurf, Start); + I915_READ(dspsurf); + I915_WRITE(dsptileoff, (y << 16) | x); + } else { + I915_WRITE(dspbase, Start + Offset); + I915_READ(dspbase); + } + + if ((IS_I965G(dev) || plane == 0)) + intel_update_fbc(crtc, &crtc->mode); + + intel_wait_for_vblank(dev); + intel_increase_pllclock(crtc, true); + + return 0; +} + static int intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, struct drm_framebuffer *old_fb) @@ -1554,6 +1724,15 @@ static void ironlake_fdi_link_train(struct drm_crtc *crtc) int fdi_rx_imr_reg = (pipe == 0) ? FDI_RXA_IMR : FDI_RXB_IMR; u32 temp, tries = 0; + /* Train 1: umask FDI RX Interrupt symbol_lock and bit_lock bit + for train result */ + temp = I915_READ(fdi_rx_imr_reg); + temp &= ~FDI_RX_SYMBOL_LOCK; + temp &= ~FDI_RX_BIT_LOCK; + I915_WRITE(fdi_rx_imr_reg, temp); + I915_READ(fdi_rx_imr_reg); + udelay(150); + /* enable CPU FDI TX and PCH FDI RX */ temp = I915_READ(fdi_tx_reg); temp |= FDI_TX_ENABLE; @@ -1571,16 +1750,7 @@ static void ironlake_fdi_link_train(struct drm_crtc *crtc) I915_READ(fdi_rx_reg); udelay(150); - /* Train 1: umask FDI RX Interrupt symbol_lock and bit_lock bit - for train result */ - temp = I915_READ(fdi_rx_imr_reg); - temp &= ~FDI_RX_SYMBOL_LOCK; - temp &= ~FDI_RX_BIT_LOCK; - I915_WRITE(fdi_rx_imr_reg, temp); - I915_READ(fdi_rx_imr_reg); - udelay(150); - - for (;;) { + for (tries = 0; tries < 5; tries++) { temp = I915_READ(fdi_rx_iir_reg); DRM_DEBUG_KMS("FDI_RX_IIR 0x%x\n", temp); @@ -1590,14 +1760,9 @@ static void ironlake_fdi_link_train(struct drm_crtc *crtc) temp | FDI_RX_BIT_LOCK); break; } - - tries++; - - if (tries > 5) { - DRM_DEBUG_KMS("FDI train 1 fail!\n"); - break; - } } + if (tries == 5) + DRM_DEBUG_KMS("FDI train 1 fail!\n"); /* Train 2 */ temp = I915_READ(fdi_tx_reg); @@ -1613,7 +1778,7 @@ static void ironlake_fdi_link_train(struct drm_crtc *crtc) tries = 0; - for (;;) { + for (tries = 0; tries < 5; tries++) { temp = I915_READ(fdi_rx_iir_reg); DRM_DEBUG_KMS("FDI_RX_IIR 0x%x\n", temp); @@ -1623,14 +1788,9 @@ static void ironlake_fdi_link_train(struct drm_crtc *crtc) DRM_DEBUG_KMS("FDI train 2 done.\n"); break; } - - tries++; - - if (tries > 5) { - DRM_DEBUG_KMS("FDI train 2 fail!\n"); - break; - } } + if (tries == 5) + DRM_DEBUG_KMS("FDI train 2 fail!\n"); DRM_DEBUG_KMS("FDI train done\n"); } @@ -1655,6 +1815,15 @@ static void gen6_fdi_link_train(struct drm_crtc *crtc) int fdi_rx_imr_reg = (pipe == 0) ? FDI_RXA_IMR : FDI_RXB_IMR; u32 temp, i; + /* Train 1: umask FDI RX Interrupt symbol_lock and bit_lock bit + for train result */ + temp = I915_READ(fdi_rx_imr_reg); + temp &= ~FDI_RX_SYMBOL_LOCK; + temp &= ~FDI_RX_BIT_LOCK; + I915_WRITE(fdi_rx_imr_reg, temp); + I915_READ(fdi_rx_imr_reg); + udelay(150); + /* enable CPU FDI TX and PCH FDI RX */ temp = I915_READ(fdi_tx_reg); temp |= FDI_TX_ENABLE; @@ -1680,15 +1849,6 @@ static void gen6_fdi_link_train(struct drm_crtc *crtc) I915_READ(fdi_rx_reg); udelay(150); - /* Train 1: umask FDI RX Interrupt symbol_lock and bit_lock bit - for train result */ - temp = I915_READ(fdi_rx_imr_reg); - temp &= ~FDI_RX_SYMBOL_LOCK; - temp &= ~FDI_RX_BIT_LOCK; - I915_WRITE(fdi_rx_imr_reg, temp); - I915_READ(fdi_rx_imr_reg); - udelay(150); - for (i = 0; i < 4; i++ ) { temp = I915_READ(fdi_tx_reg); temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK; @@ -1843,7 +2003,8 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode) } /* Enable panel fitting for LVDS */ - if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) { + if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) + || HAS_eDP || intel_pch_has_edp(crtc)) { temp = I915_READ(pf_ctl_reg); I915_WRITE(pf_ctl_reg, temp | PF_ENABLE | PF_FILTER_MED_3x3); @@ -1938,9 +2099,12 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode) reg = I915_READ(trans_dp_ctl); reg &= ~TRANS_DP_PORT_SEL_MASK; reg = TRANS_DP_OUTPUT_ENABLE | - TRANS_DP_ENH_FRAMING | - TRANS_DP_VSYNC_ACTIVE_HIGH | - TRANS_DP_HSYNC_ACTIVE_HIGH; + TRANS_DP_ENH_FRAMING; + + if (crtc->mode.flags & DRM_MODE_FLAG_PHSYNC) + reg |= TRANS_DP_HSYNC_ACTIVE_HIGH; + if (crtc->mode.flags & DRM_MODE_FLAG_PVSYNC) + reg |= TRANS_DP_VSYNC_ACTIVE_HIGH; switch (intel_trans_dp_port_sel(crtc)) { case PCH_DP_B: @@ -1980,6 +2144,8 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode) intel_crtc_load_lut(crtc); + intel_update_fbc(crtc, &crtc->mode); + break; case DRM_MODE_DPMS_OFF: DRM_DEBUG_KMS("crtc %d dpms off\n", pipe); @@ -1994,6 +2160,10 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode) I915_READ(dspbase_reg); } + if (dev_priv->cfb_plane == plane && + dev_priv->display.disable_fbc) + dev_priv->display.disable_fbc(dev); + i915_disable_vga(dev); /* disable cpu pipe, disable after all planes disabled */ @@ -2373,8 +2543,8 @@ static bool intel_crtc_mode_fixup(struct drm_crtc *crtc, struct drm_device *dev = crtc->dev; if (HAS_PCH_SPLIT(dev)) { /* FDI link clock is fixed at 2.7G */ - if (mode->clock * 3 > 27000 * 4) - return MODE_CLOCK_HIGH; + if (mode->clock * 3 > IRONLAKE_FDI_FREQ * 4) + return false; } return true; } @@ -2556,6 +2726,20 @@ static struct intel_watermark_params g4x_wm_info = { 2, G4X_FIFO_LINE_SIZE, }; +static struct intel_watermark_params g4x_cursor_wm_info = { + I965_CURSOR_FIFO, + I965_CURSOR_MAX_WM, + I965_CURSOR_DFT_WM, + 2, + G4X_FIFO_LINE_SIZE, +}; +static struct intel_watermark_params i965_cursor_wm_info = { + I965_CURSOR_FIFO, + I965_CURSOR_MAX_WM, + I965_CURSOR_DFT_WM, + 2, + I915_FIFO_LINE_SIZE, +}; static struct intel_watermark_params i945_wm_info = { I945_FIFO_SIZE, I915_MAX_WM, @@ -2593,6 +2777,14 @@ static struct intel_watermark_params ironlake_display_wm_info = { ILK_FIFO_LINE_SIZE }; +static struct intel_watermark_params ironlake_cursor_wm_info = { + ILK_CURSOR_FIFO, + ILK_CURSOR_MAXWM, + ILK_CURSOR_DFTWM, + 2, + ILK_FIFO_LINE_SIZE +}; + static struct intel_watermark_params ironlake_display_srwm_info = { ILK_DISPLAY_SR_FIFO, ILK_DISPLAY_MAX_SRWM, @@ -2642,7 +2834,7 @@ static unsigned long intel_calculate_wm(unsigned long clock_in_khz, */ entries_required = ((clock_in_khz / 1000) * pixel_size * latency_ns) / 1000; - entries_required /= wm->cacheline_size; + entries_required = DIV_ROUND_UP(entries_required, wm->cacheline_size); DRM_DEBUG_KMS("FIFO entries required for mode: %d\n", entries_required); @@ -2653,8 +2845,14 @@ static unsigned long intel_calculate_wm(unsigned long clock_in_khz, /* Don't promote wm_size to unsigned... */ if (wm_size > (long)wm->max_wm) wm_size = wm->max_wm; - if (wm_size <= 0) + if (wm_size <= 0) { wm_size = wm->default_wm; + DRM_ERROR("Insufficient FIFO for plane, expect flickering:" + " entries required = %ld, available = %lu.\n", + entries_required + wm->guard_size, + wm->fifo_size); + } + return wm_size; } @@ -2763,11 +2961,9 @@ static int i9xx_get_fifo_size(struct drm_device *dev, int plane) uint32_t dsparb = I915_READ(DSPARB); int size; - if (plane == 0) - size = dsparb & 0x7f; - else - size = ((dsparb >> DSPARB_CSTART_SHIFT) & 0x7f) - - (dsparb & 0x7f); + size = dsparb & 0x7f; + if (plane) + size = ((dsparb >> DSPARB_CSTART_SHIFT) & 0x7f) - size; DRM_DEBUG_KMS("FIFO size - (0x%08x) %s: %d\n", dsparb, plane ? "B" : "A", size); @@ -2781,11 +2977,9 @@ static int i85x_get_fifo_size(struct drm_device *dev, int plane) uint32_t dsparb = I915_READ(DSPARB); int size; - if (plane == 0) - size = dsparb & 0x1ff; - else - size = ((dsparb >> DSPARB_BEND_SHIFT) & 0x1ff) - - (dsparb & 0x1ff); + size = dsparb & 0x1ff; + if (plane) + size = ((dsparb >> DSPARB_BEND_SHIFT) & 0x1ff) - size; size >>= 1; /* Convert to cachelines */ DRM_DEBUG_KMS("FIFO size - (0x%08x) %s: %d\n", dsparb, @@ -2826,7 +3020,8 @@ static int i830_get_fifo_size(struct drm_device *dev, int plane) } static void pineview_update_wm(struct drm_device *dev, int planea_clock, - int planeb_clock, int sr_hdisplay, int pixel_size) + int planeb_clock, int sr_hdisplay, int unused, + int pixel_size) { struct drm_i915_private *dev_priv = dev->dev_private; u32 reg; @@ -2891,7 +3086,8 @@ static void pineview_update_wm(struct drm_device *dev, int planea_clock, } static void g4x_update_wm(struct drm_device *dev, int planea_clock, - int planeb_clock, int sr_hdisplay, int pixel_size) + int planeb_clock, int sr_hdisplay, int sr_htotal, + int pixel_size) { struct drm_i915_private *dev_priv = dev->dev_private; int total_size, cacheline_size; @@ -2915,12 +3111,12 @@ static void g4x_update_wm(struct drm_device *dev, int planea_clock, */ entries_required = ((planea_clock / 1000) * pixel_size * latency_ns) / 1000; - entries_required /= G4X_FIFO_LINE_SIZE; + entries_required = DIV_ROUND_UP(entries_required, G4X_FIFO_LINE_SIZE); planea_wm = entries_required + planea_params.guard_size; entries_required = ((planeb_clock / 1000) * pixel_size * latency_ns) / 1000; - entries_required /= G4X_FIFO_LINE_SIZE; + entries_required = DIV_ROUND_UP(entries_required, G4X_FIFO_LINE_SIZE); planeb_wm = entries_required + planeb_params.guard_size; cursora_wm = cursorb_wm = 16; @@ -2934,13 +3130,24 @@ static void g4x_update_wm(struct drm_device *dev, int planea_clock, static const int sr_latency_ns = 12000; sr_clock = planea_clock ? planea_clock : planeb_clock; - line_time_us = ((sr_hdisplay * 1000) / sr_clock); + line_time_us = ((sr_htotal * 1000) / sr_clock); /* Use ns/us then divide to preserve precision */ - sr_entries = (((sr_latency_ns / line_time_us) + 1) * - pixel_size * sr_hdisplay) / 1000; - sr_entries = roundup(sr_entries / cacheline_size, 1); - DRM_DEBUG("self-refresh entries: %d\n", sr_entries); + sr_entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) * + pixel_size * sr_hdisplay; + sr_entries = DIV_ROUND_UP(sr_entries, cacheline_size); + + entries_required = (((sr_latency_ns / line_time_us) + + 1000) / 1000) * pixel_size * 64; + entries_required = DIV_ROUND_UP(entries_required, + g4x_cursor_wm_info.cacheline_size); + cursor_sr = entries_required + g4x_cursor_wm_info.guard_size; + + if (cursor_sr > g4x_cursor_wm_info.max_wm) + cursor_sr = g4x_cursor_wm_info.max_wm; + DRM_DEBUG_KMS("self-refresh watermark: display plane %d " + "cursor %d\n", sr_entries, cursor_sr); + I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN); } else { /* Turn off self refresh if both pipes are enabled */ @@ -2965,11 +3172,13 @@ static void g4x_update_wm(struct drm_device *dev, int planea_clock, } static void i965_update_wm(struct drm_device *dev, int planea_clock, - int planeb_clock, int sr_hdisplay, int pixel_size) + int planeb_clock, int sr_hdisplay, int sr_htotal, + int pixel_size) { struct drm_i915_private *dev_priv = dev->dev_private; unsigned long line_time_us; int sr_clock, sr_entries, srwm = 1; + int cursor_sr = 16; /* Calc sr entries for one plane configs */ if (sr_hdisplay && (!planea_clock || !planeb_clock)) { @@ -2977,17 +3186,31 @@ static void i965_update_wm(struct drm_device *dev, int planea_clock, static const int sr_latency_ns = 12000; sr_clock = planea_clock ? planea_clock : planeb_clock; - line_time_us = ((sr_hdisplay * 1000) / sr_clock); + line_time_us = ((sr_htotal * 1000) / sr_clock); /* Use ns/us then divide to preserve precision */ - sr_entries = (((sr_latency_ns / line_time_us) + 1) * - pixel_size * sr_hdisplay) / 1000; - sr_entries = roundup(sr_entries / I915_FIFO_LINE_SIZE, 1); + sr_entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) * + pixel_size * sr_hdisplay; + sr_entries = DIV_ROUND_UP(sr_entries, I915_FIFO_LINE_SIZE); DRM_DEBUG("self-refresh entries: %d\n", sr_entries); - srwm = I945_FIFO_SIZE - sr_entries; + srwm = I965_FIFO_SIZE - sr_entries; if (srwm < 0) srwm = 1; - srwm &= 0x3f; + srwm &= 0x1ff; + + sr_entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) * + pixel_size * 64; + sr_entries = DIV_ROUND_UP(sr_entries, + i965_cursor_wm_info.cacheline_size); + cursor_sr = i965_cursor_wm_info.fifo_size - + (sr_entries + i965_cursor_wm_info.guard_size); + + if (cursor_sr > i965_cursor_wm_info.max_wm) + cursor_sr = i965_cursor_wm_info.max_wm; + + DRM_DEBUG_KMS("self-refresh watermark: display plane %d " + "cursor %d\n", srwm, cursor_sr); + if (IS_I965GM(dev)) I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN); } else { @@ -3004,10 +3227,13 @@ static void i965_update_wm(struct drm_device *dev, int planea_clock, I915_WRITE(DSPFW1, (srwm << DSPFW_SR_SHIFT) | (8 << 16) | (8 << 8) | (8 << 0)); I915_WRITE(DSPFW2, (8 << 8) | (8 << 0)); + /* update cursor SR watermark */ + I915_WRITE(DSPFW3, (cursor_sr << DSPFW_CURSOR_SR_SHIFT)); } static void i9xx_update_wm(struct drm_device *dev, int planea_clock, - int planeb_clock, int sr_hdisplay, int pixel_size) + int planeb_clock, int sr_hdisplay, int sr_htotal, + int pixel_size) { struct drm_i915_private *dev_priv = dev->dev_private; uint32_t fwater_lo; @@ -3052,12 +3278,12 @@ static void i9xx_update_wm(struct drm_device *dev, int planea_clock, static const int sr_latency_ns = 6000; sr_clock = planea_clock ? planea_clock : planeb_clock; - line_time_us = ((sr_hdisplay * 1000) / sr_clock); + line_time_us = ((sr_htotal * 1000) / sr_clock); /* Use ns/us then divide to preserve precision */ - sr_entries = (((sr_latency_ns / line_time_us) + 1) * - pixel_size * sr_hdisplay) / 1000; - sr_entries = roundup(sr_entries / cacheline_size, 1); + sr_entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) * + pixel_size * sr_hdisplay; + sr_entries = DIV_ROUND_UP(sr_entries, cacheline_size); DRM_DEBUG_KMS("self-refresh entries: %d\n", sr_entries); srwm = total_size - sr_entries; if (srwm < 0) @@ -3095,7 +3321,7 @@ static void i9xx_update_wm(struct drm_device *dev, int planea_clock, } static void i830_update_wm(struct drm_device *dev, int planea_clock, int unused, - int unused2, int pixel_size) + int unused2, int unused3, int pixel_size) { struct drm_i915_private *dev_priv = dev->dev_private; uint32_t fwater_lo = I915_READ(FW_BLC) & ~0xfff; @@ -3113,9 +3339,11 @@ static void i830_update_wm(struct drm_device *dev, int planea_clock, int unused, } #define ILK_LP0_PLANE_LATENCY 700 +#define ILK_LP0_CURSOR_LATENCY 1300 static void ironlake_update_wm(struct drm_device *dev, int planea_clock, - int planeb_clock, int sr_hdisplay, int pixel_size) + int planeb_clock, int sr_hdisplay, int sr_htotal, + int pixel_size) { struct drm_i915_private *dev_priv = dev->dev_private; int planea_wm, planeb_wm, cursora_wm, cursorb_wm; @@ -3123,20 +3351,48 @@ static void ironlake_update_wm(struct drm_device *dev, int planea_clock, unsigned long line_time_us; int sr_clock, entries_required; u32 reg_value; + int line_count; + int planea_htotal = 0, planeb_htotal = 0; + struct drm_crtc *crtc; + struct intel_crtc *intel_crtc; + + /* Need htotal for all active display plane */ + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + intel_crtc = to_intel_crtc(crtc); + if (crtc->enabled) { + if (intel_crtc->plane == 0) + planea_htotal = crtc->mode.htotal; + else + planeb_htotal = crtc->mode.htotal; + } + } /* Calculate and update the watermark for plane A */ if (planea_clock) { entries_required = ((planea_clock / 1000) * pixel_size * ILK_LP0_PLANE_LATENCY) / 1000; entries_required = DIV_ROUND_UP(entries_required, - ironlake_display_wm_info.cacheline_size); + ironlake_display_wm_info.cacheline_size); planea_wm = entries_required + ironlake_display_wm_info.guard_size; if (planea_wm > (int)ironlake_display_wm_info.max_wm) planea_wm = ironlake_display_wm_info.max_wm; - cursora_wm = 16; + /* Use the large buffer method to calculate cursor watermark */ + line_time_us = (planea_htotal * 1000) / planea_clock; + + /* Use ns/us then divide to preserve precision */ + line_count = (ILK_LP0_CURSOR_LATENCY / line_time_us + 1000) / 1000; + + /* calculate the cursor watermark for cursor A */ + entries_required = line_count * 64 * pixel_size; + entries_required = DIV_ROUND_UP(entries_required, + ironlake_cursor_wm_info.cacheline_size); + cursora_wm = entries_required + ironlake_cursor_wm_info.guard_size; + if (cursora_wm > ironlake_cursor_wm_info.max_wm) + cursora_wm = ironlake_cursor_wm_info.max_wm; + reg_value = I915_READ(WM0_PIPEA_ILK); reg_value &= ~(WM0_PIPE_PLANE_MASK | WM0_PIPE_CURSOR_MASK); reg_value |= (planea_wm << WM0_PIPE_PLANE_SHIFT) | @@ -3150,14 +3406,27 @@ static void ironlake_update_wm(struct drm_device *dev, int planea_clock, entries_required = ((planeb_clock / 1000) * pixel_size * ILK_LP0_PLANE_LATENCY) / 1000; entries_required = DIV_ROUND_UP(entries_required, - ironlake_display_wm_info.cacheline_size); + ironlake_display_wm_info.cacheline_size); planeb_wm = entries_required + ironlake_display_wm_info.guard_size; if (planeb_wm > (int)ironlake_display_wm_info.max_wm) planeb_wm = ironlake_display_wm_info.max_wm; - cursorb_wm = 16; + /* Use the large buffer method to calculate cursor watermark */ + line_time_us = (planeb_htotal * 1000) / planeb_clock; + + /* Use ns/us then divide to preserve precision */ + line_count = (ILK_LP0_CURSOR_LATENCY / line_time_us + 1000) / 1000; + + /* calculate the cursor watermark for cursor B */ + entries_required = line_count * 64 * pixel_size; + entries_required = DIV_ROUND_UP(entries_required, + ironlake_cursor_wm_info.cacheline_size); + cursorb_wm = entries_required + ironlake_cursor_wm_info.guard_size; + if (cursorb_wm > ironlake_cursor_wm_info.max_wm) + cursorb_wm = ironlake_cursor_wm_info.max_wm; + reg_value = I915_READ(WM0_PIPEB_ILK); reg_value &= ~(WM0_PIPE_PLANE_MASK | WM0_PIPE_CURSOR_MASK); reg_value |= (planeb_wm << WM0_PIPE_PLANE_SHIFT) | @@ -3172,12 +3441,12 @@ static void ironlake_update_wm(struct drm_device *dev, int planea_clock, * display plane is used. */ if (!planea_clock || !planeb_clock) { - int line_count; + /* Read the self-refresh latency. The unit is 0.5us */ int ilk_sr_latency = I915_READ(MLTR_ILK) & ILK_SRLT_MASK; sr_clock = planea_clock ? planea_clock : planeb_clock; - line_time_us = ((sr_hdisplay * 1000) / sr_clock); + line_time_us = ((sr_htotal * 1000) / sr_clock); /* Use ns/us then divide to preserve precision */ line_count = ((ilk_sr_latency * 500) / line_time_us + 1000) @@ -3186,14 +3455,14 @@ static void ironlake_update_wm(struct drm_device *dev, int planea_clock, /* calculate the self-refresh watermark for display plane */ entries_required = line_count * sr_hdisplay * pixel_size; entries_required = DIV_ROUND_UP(entries_required, - ironlake_display_srwm_info.cacheline_size); + ironlake_display_srwm_info.cacheline_size); sr_wm = entries_required + ironlake_display_srwm_info.guard_size; /* calculate the self-refresh watermark for display cursor */ entries_required = line_count * pixel_size * 64; entries_required = DIV_ROUND_UP(entries_required, - ironlake_cursor_srwm_info.cacheline_size); + ironlake_cursor_srwm_info.cacheline_size); cursor_wm = entries_required + ironlake_cursor_srwm_info.guard_size; @@ -3237,6 +3506,7 @@ static void ironlake_update_wm(struct drm_device *dev, int planea_clock, * bytes per pixel * where * line time = htotal / dotclock + * surface width = hdisplay for normal plane and 64 for cursor * and latency is assumed to be high, as above. * * The final value programmed to the register should always be rounded up, @@ -3253,6 +3523,7 @@ static void intel_update_watermarks(struct drm_device *dev) int sr_hdisplay = 0; unsigned long planea_clock = 0, planeb_clock = 0, sr_clock = 0; int enabled = 0, pixel_size = 0; + int sr_htotal = 0; if (!dev_priv->display.update_wm) return; @@ -3273,6 +3544,7 @@ static void intel_update_watermarks(struct drm_device *dev) } sr_hdisplay = crtc->mode.hdisplay; sr_clock = crtc->mode.clock; + sr_htotal = crtc->mode.htotal; if (crtc->fb) pixel_size = crtc->fb->bits_per_pixel / 8; else @@ -3284,7 +3556,7 @@ static void intel_update_watermarks(struct drm_device *dev) return; dev_priv->display.update_wm(dev, planea_clock, planeb_clock, - sr_hdisplay, pixel_size); + sr_hdisplay, sr_htotal, pixel_size); } static int intel_crtc_mode_set(struct drm_crtc *crtc, @@ -3403,6 +3675,9 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, return -EINVAL; } + /* Ensure that the cursor is valid for the new mode before changing... */ + intel_crtc_update_cursor(crtc); + if (is_lvds && dev_priv->lvds_downclock_avail) { has_reduced_clock = limit->find_pll(limit, crtc, dev_priv->lvds_downclock, @@ -3469,7 +3744,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, temp |= PIPE_8BPC; else temp |= PIPE_6BPC; - } else if (is_edp) { + } else if (is_edp || (is_dp && intel_pch_has_edp(crtc))) { switch (dev_priv->edp_bpp/3) { case 8: temp |= PIPE_8BPC; @@ -3712,6 +3987,11 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, udelay(150); } + if (HAS_PCH_SPLIT(dev)) { + pipeconf &= ~PIPE_ENABLE_DITHER; + pipeconf &= ~PIPE_DITHER_TYPE_MASK; + } + /* The LVDS pin pair needs to be on before the DPLLs are enabled. * This is an exception to the general rule that mode_set doesn't turn * things on. @@ -3754,16 +4034,13 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, if (dev_priv->lvds_dither) { if (HAS_PCH_SPLIT(dev)) { pipeconf |= PIPE_ENABLE_DITHER; - pipeconf &= ~PIPE_DITHER_TYPE_MASK; pipeconf |= PIPE_DITHER_TYPE_ST01; } else lvds |= LVDS_ENABLE_DITHER; } else { - if (HAS_PCH_SPLIT(dev)) { - pipeconf &= ~PIPE_ENABLE_DITHER; - pipeconf &= ~PIPE_DITHER_TYPE_MASK; - } else + if (!HAS_PCH_SPLIT(dev)) { lvds &= ~LVDS_ENABLE_DITHER; + } } } I915_WRITE(lvds_reg, lvds); @@ -3939,6 +4216,85 @@ void intel_crtc_load_lut(struct drm_crtc *crtc) } } +/* If no-part of the cursor is visible on the framebuffer, then the GPU may hang... */ +static void intel_crtc_update_cursor(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + int pipe = intel_crtc->pipe; + int x = intel_crtc->cursor_x; + int y = intel_crtc->cursor_y; + uint32_t base, pos; + bool visible; + + pos = 0; + + if (crtc->fb) { + base = intel_crtc->cursor_addr; + if (x > (int) crtc->fb->width) + base = 0; + + if (y > (int) crtc->fb->height) + base = 0; + } else + base = 0; + + if (x < 0) { + if (x + intel_crtc->cursor_width < 0) + base = 0; + + pos |= CURSOR_POS_SIGN << CURSOR_X_SHIFT; + x = -x; + } + pos |= x << CURSOR_X_SHIFT; + + if (y < 0) { + if (y + intel_crtc->cursor_height < 0) + base = 0; + + pos |= CURSOR_POS_SIGN << CURSOR_Y_SHIFT; + y = -y; + } + pos |= y << CURSOR_Y_SHIFT; + + visible = base != 0; + if (!visible && !intel_crtc->cursor_visble) + return; + + I915_WRITE(pipe == 0 ? CURAPOS : CURBPOS, pos); + if (intel_crtc->cursor_visble != visible) { + uint32_t cntl = I915_READ(pipe == 0 ? CURACNTR : CURBCNTR); + if (base) { + /* Hooray for CUR*CNTR differences */ + if (IS_MOBILE(dev) || IS_I9XX(dev)) { + cntl &= ~(CURSOR_MODE | MCURSOR_PIPE_SELECT); + cntl |= CURSOR_MODE_64_ARGB_AX | MCURSOR_GAMMA_ENABLE; + cntl |= pipe << 28; /* Connect to correct pipe */ + } else { + cntl &= ~(CURSOR_FORMAT_MASK); + cntl |= CURSOR_ENABLE; + cntl |= CURSOR_FORMAT_ARGB | CURSOR_GAMMA_ENABLE; + } + } else { + if (IS_MOBILE(dev) || IS_I9XX(dev)) { + cntl &= ~(CURSOR_MODE | MCURSOR_GAMMA_ENABLE); + cntl |= CURSOR_MODE_DISABLE; + } else { + cntl &= ~(CURSOR_ENABLE | CURSOR_GAMMA_ENABLE); + } + } + I915_WRITE(pipe == 0 ? CURACNTR : CURBCNTR, cntl); + + intel_crtc->cursor_visble = visible; + } + /* and commit changes on next vblank */ + I915_WRITE(pipe == 0 ? CURABASE : CURBBASE, base); + + if (visible) + intel_mark_busy(dev, to_intel_framebuffer(crtc->fb)->obj); +} + static int intel_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv, uint32_t handle, @@ -3949,11 +4305,7 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc, struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct drm_gem_object *bo; struct drm_i915_gem_object *obj_priv; - int pipe = intel_crtc->pipe; - uint32_t control = (pipe == 0) ? CURACNTR : CURBCNTR; - uint32_t base = (pipe == 0) ? CURABASE : CURBBASE; - uint32_t temp = I915_READ(control); - size_t addr; + uint32_t addr; int ret; DRM_DEBUG_KMS("\n"); @@ -3961,12 +4313,6 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc, /* if we want to turn off the cursor ignore width and height */ if (!handle) { DRM_DEBUG_KMS("cursor off\n"); - if (IS_MOBILE(dev) || IS_I9XX(dev)) { - temp &= ~(CURSOR_MODE | MCURSOR_GAMMA_ENABLE); - temp |= CURSOR_MODE_DISABLE; - } else { - temp &= ~(CURSOR_ENABLE | CURSOR_GAMMA_ENABLE); - } addr = 0; bo = NULL; mutex_lock(&dev->struct_mutex); @@ -4008,7 +4354,8 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc, addr = obj_priv->gtt_offset; } else { - ret = i915_gem_attach_phys_object(dev, bo, (pipe == 0) ? I915_GEM_PHYS_CURSOR_0 : I915_GEM_PHYS_CURSOR_1); + ret = i915_gem_attach_phys_object(dev, bo, + (intel_crtc->pipe == 0) ? I915_GEM_PHYS_CURSOR_0 : I915_GEM_PHYS_CURSOR_1); if (ret) { DRM_ERROR("failed to attach phys object\n"); goto fail_locked; @@ -4019,21 +4366,7 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc, if (!IS_I9XX(dev)) I915_WRITE(CURSIZE, (height << 12) | width); - /* Hooray for CUR*CNTR differences */ - if (IS_MOBILE(dev) || IS_I9XX(dev)) { - temp &= ~(CURSOR_MODE | MCURSOR_PIPE_SELECT); - temp |= CURSOR_MODE_64_ARGB_AX | MCURSOR_GAMMA_ENABLE; - temp |= (pipe << 28); /* Connect to correct pipe */ - } else { - temp &= ~(CURSOR_FORMAT_MASK); - temp |= CURSOR_ENABLE; - temp |= CURSOR_FORMAT_ARGB | CURSOR_GAMMA_ENABLE; - } - finish: - I915_WRITE(control, temp); - I915_WRITE(base, addr); - if (intel_crtc->cursor_bo) { if (dev_priv->info->cursor_needs_physical) { if (intel_crtc->cursor_bo != bo) @@ -4047,6 +4380,10 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc, intel_crtc->cursor_addr = addr; intel_crtc->cursor_bo = bo; + intel_crtc->cursor_width = width; + intel_crtc->cursor_height = height; + + intel_crtc_update_cursor(crtc); return 0; fail_unpin: @@ -4060,34 +4397,12 @@ fail: static int intel_crtc_cursor_move(struct drm_crtc *crtc, int x, int y) { - struct drm_device *dev = crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - struct intel_framebuffer *intel_fb; - int pipe = intel_crtc->pipe; - uint32_t temp = 0; - uint32_t adder; - - if (crtc->fb) { - intel_fb = to_intel_framebuffer(crtc->fb); - intel_mark_busy(dev, intel_fb->obj); - } - - if (x < 0) { - temp |= CURSOR_POS_SIGN << CURSOR_X_SHIFT; - x = -x; - } - if (y < 0) { - temp |= CURSOR_POS_SIGN << CURSOR_Y_SHIFT; - y = -y; - } - temp |= x << CURSOR_X_SHIFT; - temp |= y << CURSOR_Y_SHIFT; + intel_crtc->cursor_x = x; + intel_crtc->cursor_y = y; - adder = intel_crtc->cursor_addr; - I915_WRITE((pipe == 0) ? CURAPOS : CURBPOS, temp); - I915_WRITE((pipe == 0) ? CURABASE : CURBBASE, adder); + intel_crtc_update_cursor(crtc); return 0; } @@ -4671,6 +4986,8 @@ static void do_intel_finish_page_flip(struct drm_device *dev, atomic_dec_and_test(&obj_priv->pending_flip)) DRM_WAKEUP(&dev_priv->pending_flip_queue); schedule_work(&work->work); + + trace_i915_flip_complete(intel_crtc->plane, work->pending_flip_obj); } void intel_finish_page_flip(struct drm_device *dev, int pipe) @@ -4748,27 +5065,22 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, mutex_lock(&dev->struct_mutex); ret = intel_pin_and_fence_fb_obj(dev, obj); - if (ret != 0) { - mutex_unlock(&dev->struct_mutex); - - spin_lock_irqsave(&dev->event_lock, flags); - intel_crtc->unpin_work = NULL; - spin_unlock_irqrestore(&dev->event_lock, flags); - - kfree(work); - - DRM_DEBUG_DRIVER("flip queue: %p pin & fence failed\n", - to_intel_bo(obj)); - return ret; - } + if (ret) + goto cleanup_work; /* Reference the objects for the scheduled work. */ drm_gem_object_reference(work->old_fb_obj); drm_gem_object_reference(obj); crtc->fb = fb; - i915_gem_object_flush_write_domain(obj); - drm_vblank_get(dev, intel_crtc->pipe); + ret = i915_gem_object_flush_write_domain(obj); + if (ret) + goto cleanup_objs; + + ret = drm_vblank_get(dev, intel_crtc->pipe); + if (ret) + goto cleanup_objs; + obj_priv = to_intel_bo(obj); atomic_inc(&obj_priv->pending_flip); work->pending_flip_obj = obj; @@ -4806,7 +5118,23 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, mutex_unlock(&dev->struct_mutex); + trace_i915_flip_request(intel_crtc->plane, obj); + return 0; + +cleanup_objs: + drm_gem_object_unreference(work->old_fb_obj); + drm_gem_object_unreference(obj); +cleanup_work: + mutex_unlock(&dev->struct_mutex); + + spin_lock_irqsave(&dev->event_lock, flags); + intel_crtc->unpin_work = NULL; + spin_unlock_irqrestore(&dev->event_lock, flags); + + kfree(work); + + return ret; } static const struct drm_crtc_helper_funcs intel_helper_funcs = { @@ -4814,6 +5142,7 @@ static const struct drm_crtc_helper_funcs intel_helper_funcs = { .mode_fixup = intel_crtc_mode_fixup, .mode_set = intel_crtc_mode_set, .mode_set_base = intel_pipe_set_base, + .mode_set_base_atomic = intel_pipe_set_base_atomic, .prepare = intel_crtc_prepare, .commit = intel_crtc_commit, .load_lut = intel_crtc_load_lut, @@ -4932,19 +5261,26 @@ static void intel_setup_outputs(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; struct drm_encoder *encoder; + bool dpd_is_edp = false; - intel_crt_init(dev); - - /* Set up integrated LVDS */ if (IS_MOBILE(dev) && !IS_I830(dev)) intel_lvds_init(dev); if (HAS_PCH_SPLIT(dev)) { - int found; + dpd_is_edp = intel_dpd_is_edp(dev); if (IS_MOBILE(dev) && (I915_READ(DP_A) & DP_DETECTED)) intel_dp_init(dev, DP_A); + if (dpd_is_edp && (I915_READ(PCH_DP_D) & DP_DETECTED)) + intel_dp_init(dev, PCH_DP_D); + } + + intel_crt_init(dev); + + if (HAS_PCH_SPLIT(dev)) { + int found; + if (I915_READ(HDMIB) & PORT_DETECTED) { /* PCH SDVOB multiplex with HDMIB */ found = intel_sdvo_init(dev, PCH_SDVOB); @@ -4963,7 +5299,7 @@ static void intel_setup_outputs(struct drm_device *dev) if (I915_READ(PCH_DP_C) & DP_DETECTED) intel_dp_init(dev, PCH_DP_C); - if (I915_READ(PCH_DP_D) & DP_DETECTED) + if (!dpd_is_edp && (I915_READ(PCH_DP_D) & DP_DETECTED)) intel_dp_init(dev, PCH_DP_D); } else if (SUPPORTS_DIGITAL_OUTPUTS(dev)) { @@ -5372,6 +5708,26 @@ void intel_init_clock_gating(struct drm_device *dev) (I915_READ(DISP_ARB_CTL) | DISP_FBC_WM_DIS)); } + /* + * Based on the document from hardware guys the following bits + * should be set unconditionally in order to enable FBC. + * The bit 22 of 0x42000 + * The bit 22 of 0x42004 + * The bit 7,8,9 of 0x42020. + */ + if (IS_IRONLAKE_M(dev)) { + I915_WRITE(ILK_DISPLAY_CHICKEN1, + I915_READ(ILK_DISPLAY_CHICKEN1) | + ILK_FBCQ_DIS); + I915_WRITE(ILK_DISPLAY_CHICKEN2, + I915_READ(ILK_DISPLAY_CHICKEN2) | + ILK_DPARB_GATE); + I915_WRITE(ILK_DSPCLK_GATE, + I915_READ(ILK_DSPCLK_GATE) | + ILK_DPFC_DIS1 | + ILK_DPFC_DIS2 | + ILK_CLK_FBC); + } return; } else if (IS_G4X(dev)) { uint32_t dspclk_gate; @@ -5450,7 +5806,11 @@ static void intel_init_display(struct drm_device *dev) dev_priv->display.dpms = i9xx_crtc_dpms; if (I915_HAS_FBC(dev)) { - if (IS_GM45(dev)) { + if (IS_IRONLAKE_M(dev)) { + dev_priv->display.fbc_enabled = ironlake_fbc_enabled; + dev_priv->display.enable_fbc = ironlake_enable_fbc; + dev_priv->display.disable_fbc = ironlake_disable_fbc; + } else if (IS_GM45(dev)) { dev_priv->display.fbc_enabled = g4x_fbc_enabled; dev_priv->display.enable_fbc = g4x_enable_fbc; dev_priv->display.disable_fbc = g4x_disable_fbc; diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 5dde80f..40be1fa 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -43,6 +43,7 @@ #define DP_LINK_CONFIGURATION_SIZE 9 #define IS_eDP(i) ((i)->type == INTEL_OUTPUT_EDP) +#define IS_PCH_eDP(dp_priv) ((dp_priv)->is_pch_edp) struct intel_dp_priv { uint32_t output_reg; @@ -56,6 +57,7 @@ struct intel_dp_priv { struct intel_encoder *intel_encoder; struct i2c_adapter adapter; struct i2c_algo_dp_aux_data algo; + bool is_pch_edp; }; static void @@ -128,8 +130,9 @@ intel_dp_link_required(struct drm_device *dev, struct intel_encoder *intel_encoder, int pixel_clock) { struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_dp_priv *dp_priv = intel_encoder->dev_priv; - if (IS_eDP(intel_encoder)) + if (IS_eDP(intel_encoder) || IS_PCH_eDP(dp_priv)) return (pixel_clock * dev_priv->edp_bpp) / 8; else return pixel_clock * 3; @@ -147,9 +150,21 @@ intel_dp_mode_valid(struct drm_connector *connector, { struct drm_encoder *encoder = intel_attached_encoder(connector); struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); + struct intel_dp_priv *dp_priv = intel_encoder->dev_priv; + struct drm_device *dev = connector->dev; + struct drm_i915_private *dev_priv = dev->dev_private; int max_link_clock = intel_dp_link_clock(intel_dp_max_link_bw(intel_encoder)); int max_lanes = intel_dp_max_lane_count(intel_encoder); + if ((IS_eDP(intel_encoder) || IS_PCH_eDP(dp_priv)) && + dev_priv->panel_fixed_mode) { + if (mode->hdisplay > dev_priv->panel_fixed_mode->hdisplay) + return MODE_PANEL; + + if (mode->vdisplay > dev_priv->panel_fixed_mode->vdisplay) + return MODE_PANEL; + } + /* only refuse the mode on non eDP since we have seen some wierd eDP panels which are outside spec tolerances but somehow work by magic */ if (!IS_eDP(intel_encoder) && @@ -508,11 +523,37 @@ intel_dp_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode, { struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); struct intel_dp_priv *dp_priv = intel_encoder->dev_priv; + struct drm_device *dev = encoder->dev; + struct drm_i915_private *dev_priv = dev->dev_private; int lane_count, clock; int max_lane_count = intel_dp_max_lane_count(intel_encoder); int max_clock = intel_dp_max_link_bw(intel_encoder) == DP_LINK_BW_2_7 ? 1 : 0; static int bws[2] = { DP_LINK_BW_1_62, DP_LINK_BW_2_7 }; + if ((IS_eDP(intel_encoder) || IS_PCH_eDP(dp_priv)) && + dev_priv->panel_fixed_mode) { + struct drm_display_mode *fixed_mode = dev_priv->panel_fixed_mode; + + adjusted_mode->hdisplay = fixed_mode->hdisplay; + adjusted_mode->hsync_start = fixed_mode->hsync_start; + adjusted_mode->hsync_end = fixed_mode->hsync_end; + adjusted_mode->htotal = fixed_mode->htotal; + + adjusted_mode->vdisplay = fixed_mode->vdisplay; + adjusted_mode->vsync_start = fixed_mode->vsync_start; + adjusted_mode->vsync_end = fixed_mode->vsync_end; + adjusted_mode->vtotal = fixed_mode->vtotal; + + adjusted_mode->clock = fixed_mode->clock; + drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V); + + /* + * the mode->clock is used to calculate the Data&Link M/N + * of the pipe. For the eDP the fixed clock should be used. + */ + mode->clock = dev_priv->panel_fixed_mode->clock; + } + for (lane_count = 1; lane_count <= max_lane_count; lane_count <<= 1) { for (clock = 0; clock <= max_clock; clock++) { int link_avail = intel_dp_max_data_rate(intel_dp_link_clock(bws[clock]), lane_count); @@ -531,7 +572,7 @@ intel_dp_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode, } } - if (IS_eDP(intel_encoder)) { + if (IS_eDP(intel_encoder) || IS_PCH_eDP(dp_priv)) { /* okay we failed just pick the highest */ dp_priv->lane_count = max_lane_count; dp_priv->link_bw = bws[max_clock]; @@ -563,14 +604,14 @@ intel_reduce_ratio(uint32_t *num, uint32_t *den) } static void -intel_dp_compute_m_n(int bytes_per_pixel, +intel_dp_compute_m_n(int bpp, int nlanes, int pixel_clock, int link_clock, struct intel_dp_m_n *m_n) { m_n->tu = 64; - m_n->gmch_m = pixel_clock * bytes_per_pixel; + m_n->gmch_m = (pixel_clock * bpp) >> 3; m_n->gmch_n = link_clock * nlanes; intel_reduce_ratio(&m_n->gmch_m, &m_n->gmch_n); m_n->link_m = pixel_clock; @@ -578,6 +619,28 @@ intel_dp_compute_m_n(int bytes_per_pixel, intel_reduce_ratio(&m_n->link_m, &m_n->link_n); } +bool intel_pch_has_edp(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct drm_mode_config *mode_config = &dev->mode_config; + struct drm_encoder *encoder; + + list_for_each_entry(encoder, &mode_config->encoder_list, head) { + struct intel_encoder *intel_encoder; + struct intel_dp_priv *dp_priv; + + if (!encoder || encoder->crtc != crtc) + continue; + + intel_encoder = enc_to_intel_encoder(encoder); + dp_priv = intel_encoder->dev_priv; + + if (intel_encoder->type == INTEL_OUTPUT_DISPLAYPORT) + return dp_priv->is_pch_edp; + } + return false; +} + void intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) @@ -587,7 +650,7 @@ intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode, struct drm_encoder *encoder; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - int lane_count = 4; + int lane_count = 4, bpp = 24; struct intel_dp_m_n m_n; /* @@ -605,6 +668,8 @@ intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode, if (intel_encoder->type == INTEL_OUTPUT_DISPLAYPORT) { lane_count = dp_priv->lane_count; + if (IS_PCH_eDP(dp_priv)) + bpp = dev_priv->edp_bpp; break; } } @@ -614,7 +679,7 @@ intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode, * the number of bytes_per_pixel post-LUT, which we always * set up for 8-bits of R/G/B, or 3 bytes total. */ - intel_dp_compute_m_n(3, lane_count, + intel_dp_compute_m_n(bpp, lane_count, mode->clock, adjusted_mode->clock, &m_n); if (HAS_PCH_SPLIT(dev)) { @@ -796,7 +861,7 @@ intel_dp_dpms(struct drm_encoder *encoder, int mode) if (mode != DRM_MODE_DPMS_ON) { if (dp_reg & DP_PORT_EN) { intel_dp_link_down(intel_encoder, dp_priv->DP); - if (IS_eDP(intel_encoder)) { + if (IS_eDP(intel_encoder) || IS_PCH_eDP(dp_priv)) { ironlake_edp_backlight_off(dev); ironlake_edp_panel_off(dev); } @@ -804,7 +869,7 @@ intel_dp_dpms(struct drm_encoder *encoder, int mode) } else { if (!(dp_reg & DP_PORT_EN)) { intel_dp_link_train(intel_encoder, dp_priv->DP, dp_priv->link_configuration); - if (IS_eDP(intel_encoder)) { + if (IS_eDP(intel_encoder) || IS_PCH_eDP(dp_priv)) { ironlake_edp_panel_on(dev); ironlake_edp_backlight_on(dev); } @@ -1340,17 +1405,32 @@ static int intel_dp_get_modes(struct drm_connector *connector) struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); struct drm_device *dev = intel_encoder->enc.dev; struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_dp_priv *dp_priv = intel_encoder->dev_priv; int ret; /* We should parse the EDID data and find out if it has an audio sink */ ret = intel_ddc_get_modes(connector, intel_encoder->ddc_bus); - if (ret) + if (ret) { + if ((IS_eDP(intel_encoder) || IS_PCH_eDP(dp_priv)) && + !dev_priv->panel_fixed_mode) { + struct drm_display_mode *newmode; + list_for_each_entry(newmode, &connector->probed_modes, + head) { + if (newmode->type & DRM_MODE_TYPE_PREFERRED) { + dev_priv->panel_fixed_mode = + drm_mode_duplicate(dev, newmode); + break; + } + } + } + return ret; + } /* if eDP has no EDID, try to use fixed panel mode from VBT */ - if (IS_eDP(intel_encoder)) { + if (IS_eDP(intel_encoder) || IS_PCH_eDP(dp_priv)) { if (dev_priv->panel_fixed_mode != NULL) { struct drm_display_mode *mode; mode = drm_mode_duplicate(dev, dev_priv->panel_fixed_mode); @@ -1435,6 +1515,26 @@ intel_trans_dp_port_sel (struct drm_crtc *crtc) return -1; } +/* check the VBT to see whether the eDP is on DP-D port */ +bool intel_dpd_is_edp(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct child_device_config *p_child; + int i; + + if (!dev_priv->child_dev_num) + return false; + + for (i = 0; i < dev_priv->child_dev_num; i++) { + p_child = dev_priv->child_dev + i; + + if (p_child->dvo_port == PORT_IDPD && + p_child->device_type == DEVICE_TYPE_eDP) + return true; + } + return false; +} + void intel_dp_init(struct drm_device *dev, int output_reg) { @@ -1444,6 +1544,7 @@ intel_dp_init(struct drm_device *dev, int output_reg) struct intel_connector *intel_connector; struct intel_dp_priv *dp_priv; const char *name = NULL; + int type; intel_encoder = kcalloc(sizeof(struct intel_encoder) + sizeof(struct intel_dp_priv), 1, GFP_KERNEL); @@ -1458,18 +1559,24 @@ intel_dp_init(struct drm_device *dev, int output_reg) dp_priv = (struct intel_dp_priv *)(intel_encoder + 1); + if (HAS_PCH_SPLIT(dev) && (output_reg == PCH_DP_D)) + if (intel_dpd_is_edp(dev)) + dp_priv->is_pch_edp = true; + + if (output_reg == DP_A || IS_PCH_eDP(dp_priv)) { + type = DRM_MODE_CONNECTOR_eDP; + intel_encoder->type = INTEL_OUTPUT_EDP; + } else { + type = DRM_MODE_CONNECTOR_DisplayPort; + intel_encoder->type = INTEL_OUTPUT_DISPLAYPORT; + } + connector = &intel_connector->base; - drm_connector_init(dev, connector, &intel_dp_connector_funcs, - DRM_MODE_CONNECTOR_DisplayPort); + drm_connector_init(dev, connector, &intel_dp_connector_funcs, type); drm_connector_helper_add(connector, &intel_dp_connector_helper_funcs); connector->polled = DRM_CONNECTOR_POLL_HPD; - if (output_reg == DP_A) - intel_encoder->type = INTEL_OUTPUT_EDP; - else - intel_encoder->type = INTEL_OUTPUT_DISPLAYPORT; - if (output_reg == DP_B || output_reg == PCH_DP_B) intel_encoder->clone_mask = (1 << INTEL_DP_B_CLONE_BIT); else if (output_reg == DP_C || output_reg == PCH_DP_C) @@ -1528,7 +1635,7 @@ intel_dp_init(struct drm_device *dev, int output_reg) intel_encoder->ddc_bus = &dp_priv->adapter; intel_encoder->hot_plug = intel_dp_hot_plug; - if (output_reg == DP_A) { + if (output_reg == DP_A || IS_PCH_eDP(dp_priv)) { /* initialize panel mode from VBT if available for eDP */ if (dev_priv->lfp_lvds_vbt_mode) { dev_priv->panel_fixed_mode = diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 2f7970b..b219014 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -143,8 +143,6 @@ struct intel_crtc { struct drm_crtc base; enum pipe pipe; enum plane plane; - struct drm_gem_object *cursor_bo; - uint32_t cursor_addr; u8 lut_r[256], lut_g[256], lut_b[256]; int dpms_mode; bool busy; /* is scanout buffer being updated frequently? */ @@ -153,6 +151,12 @@ struct intel_crtc { struct intel_overlay *overlay; struct intel_unpin_work *unpin_work; int fdi_lanes; + + struct drm_gem_object *cursor_bo; + uint32_t cursor_addr; + int16_t cursor_x, cursor_y; + int16_t cursor_width, cursor_height; + bool cursor_visble; }; #define to_intel_crtc(x) container_of(x, struct intel_crtc, base) @@ -179,6 +183,8 @@ extern void intel_dp_init(struct drm_device *dev, int dp_reg); void intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode); +extern bool intel_pch_has_edp(struct drm_crtc *crtc); +extern bool intel_dpd_is_edp(struct drm_device *dev); extern void intel_edp_link_config (struct intel_encoder *, int *, int *); diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c index 3e18c9e..54acd8b 100644 --- a/drivers/gpu/drm/i915/intel_fb.c +++ b/drivers/gpu/drm/i915/intel_fb.c @@ -61,6 +61,8 @@ static struct fb_ops intelfb_ops = { .fb_pan_display = drm_fb_helper_pan_display, .fb_blank = drm_fb_helper_blank, .fb_setcmap = drm_fb_helper_setcmap, + .fb_debug_enter = drm_fb_helper_debug_enter, + .fb_debug_leave = drm_fb_helper_debug_leave, }; static int intelfb_create(struct intel_fbdev *ifbdev, diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 83bd764..197887e 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -54,10 +54,11 @@ static void intel_hdmi_mode_set(struct drm_encoder *encoder, struct intel_hdmi_priv *hdmi_priv = intel_encoder->dev_priv; u32 sdvox; - sdvox = SDVO_ENCODING_HDMI | - SDVO_BORDER_ENABLE | - SDVO_VSYNC_ACTIVE_HIGH | - SDVO_HSYNC_ACTIVE_HIGH; + sdvox = SDVO_ENCODING_HDMI | SDVO_BORDER_ENABLE; + if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) + sdvox |= SDVO_VSYNC_ACTIVE_HIGH; + if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) + sdvox |= SDVO_HSYNC_ACTIVE_HIGH; if (hdmi_priv->has_hdmi_sink) { sdvox |= SDVO_AUDIO_ENABLE; diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 0eab8df..0a2e600 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -156,31 +156,73 @@ static int intel_lvds_mode_valid(struct drm_connector *connector, return MODE_OK; } +static void +centre_horizontally(struct drm_display_mode *mode, + int width) +{ + u32 border, sync_pos, blank_width, sync_width; + + /* keep the hsync and hblank widths constant */ + sync_width = mode->crtc_hsync_end - mode->crtc_hsync_start; + blank_width = mode->crtc_hblank_end - mode->crtc_hblank_start; + sync_pos = (blank_width - sync_width + 1) / 2; + + border = (mode->hdisplay - width + 1) / 2; + border += border & 1; /* make the border even */ + + mode->crtc_hdisplay = width; + mode->crtc_hblank_start = width + border; + mode->crtc_hblank_end = mode->crtc_hblank_start + blank_width; + + mode->crtc_hsync_start = mode->crtc_hblank_start + sync_pos; + mode->crtc_hsync_end = mode->crtc_hsync_start + sync_width; +} + +static void +centre_vertically(struct drm_display_mode *mode, + int height) +{ + u32 border, sync_pos, blank_width, sync_width; + + /* keep the vsync and vblank widths constant */ + sync_width = mode->crtc_vsync_end - mode->crtc_vsync_start; + blank_width = mode->crtc_vblank_end - mode->crtc_vblank_start; + sync_pos = (blank_width - sync_width + 1) / 2; + + border = (mode->vdisplay - height + 1) / 2; + + mode->crtc_vdisplay = height; + mode->crtc_vblank_start = height + border; + mode->crtc_vblank_end = mode->crtc_vblank_start + blank_width; + + mode->crtc_vsync_start = mode->crtc_vblank_start + sync_pos; + mode->crtc_vsync_end = mode->crtc_vsync_start + sync_width; +} + +static inline u32 panel_fitter_scaling(u32 source, u32 target) +{ + /* + * Floating point operation is not supported. So the FACTOR + * is defined, which can avoid the floating point computation + * when calculating the panel ratio. + */ +#define ACCURACY 12 +#define FACTOR (1 << ACCURACY) + u32 ratio = source * FACTOR / target; + return (FACTOR * ratio + FACTOR/2) / FACTOR; +} + static bool intel_lvds_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { - /* - * float point operation is not supported . So the PANEL_RATIO_FACTOR - * is defined, which can avoid the float point computation when - * calculating the panel ratio. - */ -#define PANEL_RATIO_FACTOR 8192 struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); struct drm_encoder *tmp_encoder; struct intel_encoder *intel_encoder = enc_to_intel_encoder(encoder); struct intel_lvds_priv *lvds_priv = intel_encoder->dev_priv; - u32 pfit_control = 0, pfit_pgm_ratios = 0; - int left_border = 0, right_border = 0, top_border = 0; - int bottom_border = 0; - bool border = 0; - int panel_ratio, desired_ratio, vert_scale, horiz_scale; - int horiz_ratio, vert_ratio; - u32 hsync_width, vsync_width; - u32 hblank_width, vblank_width; - u32 hsync_pos, vsync_pos; + u32 pfit_control = 0, pfit_pgm_ratios = 0, border = 0; /* Should never happen!! */ if (!IS_I965G(dev) && intel_crtc->pipe == 0) { @@ -200,27 +242,25 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder, if (dev_priv->panel_fixed_mode == NULL) return true; /* - * If we have timings from the BIOS for the panel, put them in + * We have timings from the BIOS for the panel, put them in * to the adjusted mode. The CRTC will be set up for this mode, * with the panel scaling set up to source from the H/VDisplay * of the original mode. */ - if (dev_priv->panel_fixed_mode != NULL) { - adjusted_mode->hdisplay = dev_priv->panel_fixed_mode->hdisplay; - adjusted_mode->hsync_start = - dev_priv->panel_fixed_mode->hsync_start; - adjusted_mode->hsync_end = - dev_priv->panel_fixed_mode->hsync_end; - adjusted_mode->htotal = dev_priv->panel_fixed_mode->htotal; - adjusted_mode->vdisplay = dev_priv->panel_fixed_mode->vdisplay; - adjusted_mode->vsync_start = - dev_priv->panel_fixed_mode->vsync_start; - adjusted_mode->vsync_end = - dev_priv->panel_fixed_mode->vsync_end; - adjusted_mode->vtotal = dev_priv->panel_fixed_mode->vtotal; - adjusted_mode->clock = dev_priv->panel_fixed_mode->clock; - drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V); - } + adjusted_mode->hdisplay = dev_priv->panel_fixed_mode->hdisplay; + adjusted_mode->hsync_start = + dev_priv->panel_fixed_mode->hsync_start; + adjusted_mode->hsync_end = + dev_priv->panel_fixed_mode->hsync_end; + adjusted_mode->htotal = dev_priv->panel_fixed_mode->htotal; + adjusted_mode->vdisplay = dev_priv->panel_fixed_mode->vdisplay; + adjusted_mode->vsync_start = + dev_priv->panel_fixed_mode->vsync_start; + adjusted_mode->vsync_end = + dev_priv->panel_fixed_mode->vsync_end; + adjusted_mode->vtotal = dev_priv->panel_fixed_mode->vtotal; + adjusted_mode->clock = dev_priv->panel_fixed_mode->clock; + drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V); /* Make sure pre-965s set dither correctly */ if (!IS_I965G(dev)) { @@ -230,11 +270,8 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder, /* Native modes don't need fitting */ if (adjusted_mode->hdisplay == mode->hdisplay && - adjusted_mode->vdisplay == mode->vdisplay) { - pfit_pgm_ratios = 0; - border = 0; + adjusted_mode->vdisplay == mode->vdisplay) goto out; - } /* full screen scale for now */ if (HAS_PCH_SPLIT(dev)) @@ -242,25 +279,9 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder, /* 965+ wants fuzzy fitting */ if (IS_I965G(dev)) - pfit_control |= (intel_crtc->pipe << PFIT_PIPE_SHIFT) | - PFIT_FILTER_FUZZY; - - hsync_width = adjusted_mode->crtc_hsync_end - - adjusted_mode->crtc_hsync_start; - vsync_width = adjusted_mode->crtc_vsync_end - - adjusted_mode->crtc_vsync_start; - hblank_width = adjusted_mode->crtc_hblank_end - - adjusted_mode->crtc_hblank_start; - vblank_width = adjusted_mode->crtc_vblank_end - - adjusted_mode->crtc_vblank_start; - /* - * Deal with panel fitting options. Figure out how to stretch the - * image based on its aspect ratio & the current panel fitting mode. - */ - panel_ratio = adjusted_mode->hdisplay * PANEL_RATIO_FACTOR / - adjusted_mode->vdisplay; - desired_ratio = mode->hdisplay * PANEL_RATIO_FACTOR / - mode->vdisplay; + pfit_control |= ((intel_crtc->pipe << PFIT_PIPE_SHIFT) | + PFIT_FILTER_FUZZY); + /* * Enable automatic panel scaling for non-native modes so that they fill * the screen. Should be enabled before the pipe is enabled, according @@ -278,170 +299,63 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder, * For centered modes, we have to calculate border widths & * heights and modify the values programmed into the CRTC. */ - left_border = (adjusted_mode->hdisplay - mode->hdisplay) / 2; - right_border = left_border; - if (mode->hdisplay & 1) - right_border++; - top_border = (adjusted_mode->vdisplay - mode->vdisplay) / 2; - bottom_border = top_border; - if (mode->vdisplay & 1) - bottom_border++; - /* Set active & border values */ - adjusted_mode->crtc_hdisplay = mode->hdisplay; - /* Keep the boder be even */ - if (right_border & 1) - right_border++; - /* use the border directly instead of border minuse one */ - adjusted_mode->crtc_hblank_start = mode->hdisplay + - right_border; - /* keep the blank width constant */ - adjusted_mode->crtc_hblank_end = - adjusted_mode->crtc_hblank_start + hblank_width; - /* get the hsync pos relative to hblank start */ - hsync_pos = (hblank_width - hsync_width) / 2; - /* keep the hsync pos be even */ - if (hsync_pos & 1) - hsync_pos++; - adjusted_mode->crtc_hsync_start = - adjusted_mode->crtc_hblank_start + hsync_pos; - /* keep the hsync width constant */ - adjusted_mode->crtc_hsync_end = - adjusted_mode->crtc_hsync_start + hsync_width; - adjusted_mode->crtc_vdisplay = mode->vdisplay; - /* use the border instead of border minus one */ - adjusted_mode->crtc_vblank_start = mode->vdisplay + - bottom_border; - /* keep the vblank width constant */ - adjusted_mode->crtc_vblank_end = - adjusted_mode->crtc_vblank_start + vblank_width; - /* get the vsync start postion relative to vblank start */ - vsync_pos = (vblank_width - vsync_width) / 2; - adjusted_mode->crtc_vsync_start = - adjusted_mode->crtc_vblank_start + vsync_pos; - /* keep the vsync width constant */ - adjusted_mode->crtc_vsync_end = - adjusted_mode->crtc_vsync_start + vsync_width; - border = 1; + centre_horizontally(adjusted_mode, mode->hdisplay); + centre_vertically(adjusted_mode, mode->vdisplay); + border = LVDS_BORDER_ENABLE; break; + case DRM_MODE_SCALE_ASPECT: - /* Scale but preserve the spect ratio */ - pfit_control |= PFIT_ENABLE; + /* Scale but preserve the aspect ratio */ if (IS_I965G(dev)) { + u32 scaled_width = adjusted_mode->hdisplay * mode->vdisplay; + u32 scaled_height = mode->hdisplay * adjusted_mode->vdisplay; + + pfit_control |= PFIT_ENABLE; /* 965+ is easy, it does everything in hw */ - if (panel_ratio > desired_ratio) + if (scaled_width > scaled_height) pfit_control |= PFIT_SCALING_PILLAR; - else if (panel_ratio < desired_ratio) + else if (scaled_width < scaled_height) pfit_control |= PFIT_SCALING_LETTER; else pfit_control |= PFIT_SCALING_AUTO; } else { + u32 scaled_width = adjusted_mode->hdisplay * mode->vdisplay; + u32 scaled_height = mode->hdisplay * adjusted_mode->vdisplay; /* * For earlier chips we have to calculate the scaling * ratio by hand and program it into the * PFIT_PGM_RATIO register */ - u32 horiz_bits, vert_bits, bits = 12; - horiz_ratio = mode->hdisplay * PANEL_RATIO_FACTOR/ - adjusted_mode->hdisplay; - vert_ratio = mode->vdisplay * PANEL_RATIO_FACTOR/ - adjusted_mode->vdisplay; - horiz_scale = adjusted_mode->hdisplay * - PANEL_RATIO_FACTOR / mode->hdisplay; - vert_scale = adjusted_mode->vdisplay * - PANEL_RATIO_FACTOR / mode->vdisplay; - - /* retain aspect ratio */ - if (panel_ratio > desired_ratio) { /* Pillar */ - u32 scaled_width; - scaled_width = mode->hdisplay * vert_scale / - PANEL_RATIO_FACTOR; - horiz_ratio = vert_ratio; - pfit_control |= (VERT_AUTO_SCALE | - VERT_INTERP_BILINEAR | - HORIZ_INTERP_BILINEAR); - /* Pillar will have left/right borders */ - left_border = (adjusted_mode->hdisplay - - scaled_width) / 2; - right_border = left_border; - if (mode->hdisplay & 1) /* odd resolutions */ - right_border++; - /* keep the border be even */ - if (right_border & 1) - right_border++; - adjusted_mode->crtc_hdisplay = scaled_width; - /* use border instead of border minus one */ - adjusted_mode->crtc_hblank_start = - scaled_width + right_border; - /* keep the hblank width constant */ - adjusted_mode->crtc_hblank_end = - adjusted_mode->crtc_hblank_start + - hblank_width; - /* - * get the hsync start pos relative to - * hblank start - */ - hsync_pos = (hblank_width - hsync_width) / 2; - /* keep the hsync_pos be even */ - if (hsync_pos & 1) - hsync_pos++; - adjusted_mode->crtc_hsync_start = - adjusted_mode->crtc_hblank_start + - hsync_pos; - /* keept hsync width constant */ - adjusted_mode->crtc_hsync_end = - adjusted_mode->crtc_hsync_start + - hsync_width; - border = 1; - } else if (panel_ratio < desired_ratio) { /* letter */ - u32 scaled_height = mode->vdisplay * - horiz_scale / PANEL_RATIO_FACTOR; - vert_ratio = horiz_ratio; - pfit_control |= (HORIZ_AUTO_SCALE | - VERT_INTERP_BILINEAR | - HORIZ_INTERP_BILINEAR); - /* Letterbox will have top/bottom border */ - top_border = (adjusted_mode->vdisplay - - scaled_height) / 2; - bottom_border = top_border; - if (mode->vdisplay & 1) - bottom_border++; - adjusted_mode->crtc_vdisplay = scaled_height; - /* use border instead of border minus one */ - adjusted_mode->crtc_vblank_start = - scaled_height + bottom_border; - /* keep the vblank width constant */ - adjusted_mode->crtc_vblank_end = - adjusted_mode->crtc_vblank_start + - vblank_width; - /* - * get the vsync start pos relative to - * vblank start - */ - vsync_pos = (vblank_width - vsync_width) / 2; - adjusted_mode->crtc_vsync_start = - adjusted_mode->crtc_vblank_start + - vsync_pos; - /* keep the vsync width constant */ - adjusted_mode->crtc_vsync_end = - adjusted_mode->crtc_vsync_start + - vsync_width; - border = 1; - } else { - /* Aspects match, Let hw scale both directions */ - pfit_control |= (VERT_AUTO_SCALE | - HORIZ_AUTO_SCALE | + if (scaled_width > scaled_height) { /* pillar */ + centre_horizontally(adjusted_mode, scaled_height / mode->vdisplay); + + border = LVDS_BORDER_ENABLE; + if (mode->vdisplay != adjusted_mode->vdisplay) { + u32 bits = panel_fitter_scaling(mode->vdisplay, adjusted_mode->vdisplay); + pfit_pgm_ratios |= (bits << PFIT_HORIZ_SCALE_SHIFT | + bits << PFIT_VERT_SCALE_SHIFT); + pfit_control |= (PFIT_ENABLE | + VERT_INTERP_BILINEAR | + HORIZ_INTERP_BILINEAR); + } + } else if (scaled_width < scaled_height) { /* letter */ + centre_vertically(adjusted_mode, scaled_width / mode->hdisplay); + + border = LVDS_BORDER_ENABLE; + if (mode->hdisplay != adjusted_mode->hdisplay) { + u32 bits = panel_fitter_scaling(mode->hdisplay, adjusted_mode->hdisplay); + pfit_pgm_ratios |= (bits << PFIT_HORIZ_SCALE_SHIFT | + bits << PFIT_VERT_SCALE_SHIFT); + pfit_control |= (PFIT_ENABLE | + VERT_INTERP_BILINEAR | + HORIZ_INTERP_BILINEAR); + } + } else + /* Aspects match, Let hw scale both directions */ + pfit_control |= (PFIT_ENABLE | + VERT_AUTO_SCALE | HORIZ_AUTO_SCALE | VERT_INTERP_BILINEAR | HORIZ_INTERP_BILINEAR); - } - horiz_bits = (1 << bits) * horiz_ratio / - PANEL_RATIO_FACTOR; - vert_bits = (1 << bits) * vert_ratio / - PANEL_RATIO_FACTOR; - pfit_pgm_ratios = - ((vert_bits << PFIT_VERT_SCALE_SHIFT) & - PFIT_VERT_SCALE_MASK) | - ((horiz_bits << PFIT_HORIZ_SCALE_SHIFT) & - PFIT_HORIZ_SCALE_MASK); } break; @@ -458,6 +372,7 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder, VERT_INTERP_BILINEAR | HORIZ_INTERP_BILINEAR); break; + default: break; } @@ -465,14 +380,8 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder, out: lvds_priv->pfit_control = pfit_control; lvds_priv->pfit_pgm_ratios = pfit_pgm_ratios; - /* - * When there exists the border, it means that the LVDS_BORDR - * should be enabled. - */ - if (border) - dev_priv->lvds_border_bits |= LVDS_BORDER_ENABLE; - else - dev_priv->lvds_border_bits &= ~(LVDS_BORDER_ENABLE); + dev_priv->lvds_border_bits = border; + /* * XXX: It would be nice to support lower refresh rates on the * panels to reduce power consumption, and perhaps match the diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c index d7ad513..d39aea2 100644 --- a/drivers/gpu/drm/i915/intel_overlay.c +++ b/drivers/gpu/drm/i915/intel_overlay.c @@ -65,7 +65,7 @@ #define OCMD_YUV_410_PLANAR (0xe<<10) /* also 411 */ #define OCMD_TVSYNCFLIP_PARITY (0x1<<9) #define OCMD_TVSYNCFLIP_ENABLE (0x1<<7) -#define OCMD_BUF_TYPE_MASK (Ox1<<5) +#define OCMD_BUF_TYPE_MASK (0x1<<5) #define OCMD_BUF_TYPE_FRAME (0x0<<5) #define OCMD_BUF_TYPE_FIELD (0x1<<5) #define OCMD_TEST_MODE (0x1<<4) @@ -185,7 +185,8 @@ static struct overlay_registers *intel_overlay_map_regs_atomic(struct intel_over if (OVERLAY_NONPHYSICAL(overlay->dev)) { regs = io_mapping_map_atomic_wc(dev_priv->mm.gtt_mapping, - overlay->reg_bo->gtt_offset); + overlay->reg_bo->gtt_offset, + KM_USER0); if (!regs) { DRM_ERROR("failed to map overlay regs in GTT\n"); @@ -200,7 +201,7 @@ static struct overlay_registers *intel_overlay_map_regs_atomic(struct intel_over static void intel_overlay_unmap_regs_atomic(struct intel_overlay *overlay) { if (OVERLAY_NONPHYSICAL(overlay->dev)) - io_mapping_unmap_atomic(overlay->virt_addr); + io_mapping_unmap_atomic(overlay->virt_addr, KM_USER0); overlay->virt_addr = NULL; @@ -958,7 +959,7 @@ static int check_overlay_src(struct drm_device *dev, || rec->src_width < N_HORIZ_Y_TAPS*4) return -EINVAL; - /* check alingment constrains */ + /* check alignment constraints */ switch (rec->flags & I915_OVERLAY_TYPE_MASK) { case I915_OVERLAY_RGB: /* not implemented */ @@ -990,7 +991,10 @@ static int check_overlay_src(struct drm_device *dev, return -EINVAL; /* stride checking */ - stride_mask = 63; + if (IS_I830(dev) || IS_845G(dev)) + stride_mask = 255; + else + stride_mask = 63; if (rec->stride_Y & stride_mask || rec->stride_UV & stride_mask) return -EINVAL; diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 03c231b..d9d4d51 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -1237,9 +1237,11 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder, /* Set the SDVO control regs. */ if (IS_I965G(dev)) { - sdvox |= SDVO_BORDER_ENABLE | - SDVO_VSYNC_ACTIVE_HIGH | - SDVO_HSYNC_ACTIVE_HIGH; + sdvox |= SDVO_BORDER_ENABLE; + if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) + sdvox |= SDVO_VSYNC_ACTIVE_HIGH; + if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) + sdvox |= SDVO_HSYNC_ACTIVE_HIGH; } else { sdvox |= I915_READ(sdvo_priv->sdvo_reg); switch (sdvo_priv->sdvo_reg) { diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c index d2d4e40..cc3726a 100644 --- a/drivers/gpu/drm/i915/intel_tv.c +++ b/drivers/gpu/drm/i915/intel_tv.c @@ -476,7 +476,7 @@ static const struct tv_mode tv_modes[] = { .vi_end_f1 = 20, .vi_end_f2 = 21, .nbr_end = 240, - .burst_ena = 8, + .burst_ena = true, .hburst_start = 72, .hburst_len = 34, .vburst_start_f1 = 9, .vburst_end_f1 = 240, .vburst_start_f2 = 10, .vburst_end_f2 = 240, @@ -896,8 +896,6 @@ static const struct tv_mode tv_modes[] = { }, }; -#define NUM_TV_MODES sizeof(tv_modes) / sizeof (tv_modes[0]) - static void intel_tv_dpms(struct drm_encoder *encoder, int mode) { @@ -1512,7 +1510,7 @@ intel_tv_set_property(struct drm_connector *connector, struct drm_property *prop tv_priv->margin[TV_MARGIN_BOTTOM] = val; changed = true; } else if (property == dev->mode_config.tv_mode_property) { - if (val >= NUM_TV_MODES) { + if (val >= ARRAY_SIZE(tv_modes)) { ret = -EINVAL; goto out; } @@ -1693,13 +1691,13 @@ intel_tv_init(struct drm_device *dev) connector->doublescan_allowed = false; /* Create TV properties then attach current values */ - tv_format_names = kmalloc(sizeof(char *) * NUM_TV_MODES, + tv_format_names = kmalloc(sizeof(char *) * ARRAY_SIZE(tv_modes), GFP_KERNEL); if (!tv_format_names) goto out; - for (i = 0; i < NUM_TV_MODES; i++) + for (i = 0; i < ARRAY_SIZE(tv_modes); i++) tv_format_names[i] = tv_modes[i].name; - drm_mode_create_tv_properties(dev, NUM_TV_MODES, tv_format_names); + drm_mode_create_tv_properties(dev, ARRAY_SIZE(tv_modes), tv_format_names); drm_connector_attach_property(connector, dev->mode_config.tv_mode_property, initial_mode); diff --git a/drivers/gpu/drm/mga/mga_dma.c b/drivers/gpu/drm/mga/mga_dma.c index 3c917fb..08868ac 100644 --- a/drivers/gpu/drm/mga/mga_dma.c +++ b/drivers/gpu/drm/mga/mga_dma.c @@ -52,7 +52,7 @@ static int mga_do_cleanup_dma(struct drm_device *dev, int full_cleanup); * Engine control */ -int mga_do_wait_for_idle(drm_mga_private_t * dev_priv) +int mga_do_wait_for_idle(drm_mga_private_t *dev_priv) { u32 status = 0; int i; @@ -74,7 +74,7 @@ int mga_do_wait_for_idle(drm_mga_private_t * dev_priv) return -EBUSY; } -static int mga_do_dma_reset(drm_mga_private_t * dev_priv) +static int mga_do_dma_reset(drm_mga_private_t *dev_priv) { drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; drm_mga_primary_buffer_t *primary = &dev_priv->prim; @@ -102,7 +102,7 @@ static int mga_do_dma_reset(drm_mga_private_t * dev_priv) * Primary DMA stream */ -void mga_do_dma_flush(drm_mga_private_t * dev_priv) +void mga_do_dma_flush(drm_mga_private_t *dev_priv) { drm_mga_primary_buffer_t *primary = &dev_priv->prim; u32 head, tail; @@ -142,11 +142,10 @@ void mga_do_dma_flush(drm_mga_private_t * dev_priv) head = MGA_READ(MGA_PRIMADDRESS); - if (head <= tail) { + if (head <= tail) primary->space = primary->size - primary->tail; - } else { + else primary->space = head - tail; - } DRM_DEBUG(" head = 0x%06lx\n", (unsigned long)(head - dev_priv->primary->offset)); DRM_DEBUG(" tail = 0x%06lx\n", (unsigned long)(tail - dev_priv->primary->offset)); @@ -158,7 +157,7 @@ void mga_do_dma_flush(drm_mga_private_t * dev_priv) DRM_DEBUG("done.\n"); } -void mga_do_dma_wrap_start(drm_mga_private_t * dev_priv) +void mga_do_dma_wrap_start(drm_mga_private_t *dev_priv) { drm_mga_primary_buffer_t *primary = &dev_priv->prim; u32 head, tail; @@ -181,11 +180,10 @@ void mga_do_dma_wrap_start(drm_mga_private_t * dev_priv) head = MGA_READ(MGA_PRIMADDRESS); - if (head == dev_priv->primary->offset) { + if (head == dev_priv->primary->offset) primary->space = primary->size; - } else { + else primary->space = head - dev_priv->primary->offset; - } DRM_DEBUG(" head = 0x%06lx\n", (unsigned long)(head - dev_priv->primary->offset)); DRM_DEBUG(" tail = 0x%06x\n", primary->tail); @@ -199,7 +197,7 @@ void mga_do_dma_wrap_start(drm_mga_private_t * dev_priv) DRM_DEBUG("done.\n"); } -void mga_do_dma_wrap_end(drm_mga_private_t * dev_priv) +void mga_do_dma_wrap_end(drm_mga_private_t *dev_priv) { drm_mga_primary_buffer_t *primary = &dev_priv->prim; drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; @@ -220,11 +218,11 @@ void mga_do_dma_wrap_end(drm_mga_private_t * dev_priv) * Freelist management */ -#define MGA_BUFFER_USED ~0 +#define MGA_BUFFER_USED (~0) #define MGA_BUFFER_FREE 0 #if MGA_FREELIST_DEBUG -static void mga_freelist_print(struct drm_device * dev) +static void mga_freelist_print(struct drm_device *dev) { drm_mga_private_t *dev_priv = dev->dev_private; drm_mga_freelist_t *entry; @@ -245,7 +243,7 @@ static void mga_freelist_print(struct drm_device * dev) } #endif -static int mga_freelist_init(struct drm_device * dev, drm_mga_private_t * dev_priv) +static int mga_freelist_init(struct drm_device *dev, drm_mga_private_t *dev_priv) { struct drm_device_dma *dma = dev->dma; struct drm_buf *buf; @@ -288,7 +286,7 @@ static int mga_freelist_init(struct drm_device * dev, drm_mga_private_t * dev_pr return 0; } -static void mga_freelist_cleanup(struct drm_device * dev) +static void mga_freelist_cleanup(struct drm_device *dev) { drm_mga_private_t *dev_priv = dev->dev_private; drm_mga_freelist_t *entry; @@ -308,7 +306,7 @@ static void mga_freelist_cleanup(struct drm_device * dev) #if 0 /* FIXME: Still needed? */ -static void mga_freelist_reset(struct drm_device * dev) +static void mga_freelist_reset(struct drm_device *dev) { struct drm_device_dma *dma = dev->dma; struct drm_buf *buf; @@ -356,7 +354,7 @@ static struct drm_buf *mga_freelist_get(struct drm_device * dev) return NULL; } -int mga_freelist_put(struct drm_device * dev, struct drm_buf * buf) +int mga_freelist_put(struct drm_device *dev, struct drm_buf *buf) { drm_mga_private_t *dev_priv = dev->dev_private; drm_mga_buf_priv_t *buf_priv = buf->dev_private; @@ -391,7 +389,7 @@ int mga_freelist_put(struct drm_device * dev, struct drm_buf * buf) * DMA initialization, cleanup */ -int mga_driver_load(struct drm_device * dev, unsigned long flags) +int mga_driver_load(struct drm_device *dev, unsigned long flags) { drm_mga_private_t *dev_priv; int ret; @@ -405,8 +403,8 @@ int mga_driver_load(struct drm_device * dev, unsigned long flags) dev_priv->usec_timeout = MGA_DEFAULT_USEC_TIMEOUT; dev_priv->chipset = flags; - dev_priv->mmio_base = drm_get_resource_start(dev, 1); - dev_priv->mmio_size = drm_get_resource_len(dev, 1); + dev_priv->mmio_base = pci_resource_start(dev->pdev, 1); + dev_priv->mmio_size = pci_resource_len(dev->pdev, 1); dev->counters += 3; dev->types[6] = _DRM_STAT_IRQ; @@ -439,8 +437,8 @@ int mga_driver_load(struct drm_device * dev, unsigned long flags) * * \sa mga_do_dma_bootstrap, mga_do_pci_dma_bootstrap */ -static int mga_do_agp_dma_bootstrap(struct drm_device * dev, - drm_mga_dma_bootstrap_t * dma_bs) +static int mga_do_agp_dma_bootstrap(struct drm_device *dev, + drm_mga_dma_bootstrap_t *dma_bs) { drm_mga_private_t *const dev_priv = (drm_mga_private_t *) dev->dev_private; @@ -481,11 +479,10 @@ static int mga_do_agp_dma_bootstrap(struct drm_device * dev, */ if (dev_priv->chipset == MGA_CARD_TYPE_G200) { - if (mode.mode & 0x02) { + if (mode.mode & 0x02) MGA_WRITE(MGA_AGP_PLL, MGA_AGP2XPLL_ENABLE); - } else { + else MGA_WRITE(MGA_AGP_PLL, MGA_AGP2XPLL_DISABLE); - } } /* Allocate and bind AGP memory. */ @@ -593,8 +590,8 @@ static int mga_do_agp_dma_bootstrap(struct drm_device * dev, return 0; } #else -static int mga_do_agp_dma_bootstrap(struct drm_device * dev, - drm_mga_dma_bootstrap_t * dma_bs) +static int mga_do_agp_dma_bootstrap(struct drm_device *dev, + drm_mga_dma_bootstrap_t *dma_bs) { return -EINVAL; } @@ -614,8 +611,8 @@ static int mga_do_agp_dma_bootstrap(struct drm_device * dev, * * \sa mga_do_dma_bootstrap, mga_do_agp_dma_bootstrap */ -static int mga_do_pci_dma_bootstrap(struct drm_device * dev, - drm_mga_dma_bootstrap_t * dma_bs) +static int mga_do_pci_dma_bootstrap(struct drm_device *dev, + drm_mga_dma_bootstrap_t *dma_bs) { drm_mga_private_t *const dev_priv = (drm_mga_private_t *) dev->dev_private; @@ -678,9 +675,8 @@ static int mga_do_pci_dma_bootstrap(struct drm_device * dev, req.size = dma_bs->secondary_bin_size; err = drm_addbufs_pci(dev, &req); - if (!err) { + if (!err) break; - } } if (bin_count == 0) { @@ -704,8 +700,8 @@ static int mga_do_pci_dma_bootstrap(struct drm_device * dev, return 0; } -static int mga_do_dma_bootstrap(struct drm_device * dev, - drm_mga_dma_bootstrap_t * dma_bs) +static int mga_do_dma_bootstrap(struct drm_device *dev, + drm_mga_dma_bootstrap_t *dma_bs) { const int is_agp = (dma_bs->agp_mode != 0) && drm_device_is_agp(dev); int err; @@ -737,17 +733,15 @@ static int mga_do_dma_bootstrap(struct drm_device * dev, * carve off portions of it for internal uses. The remaining memory * is returned to user-mode to be used for AGP textures. */ - if (is_agp) { + if (is_agp) err = mga_do_agp_dma_bootstrap(dev, dma_bs); - } /* If we attempted to initialize the card for AGP DMA but failed, * clean-up any mess that may have been created. */ - if (err) { + if (err) mga_do_cleanup_dma(dev, MINIMAL_CLEANUP); - } /* Not only do we want to try and initialized PCI cards for PCI DMA, * but we also try to initialized AGP cards that could not be @@ -757,9 +751,8 @@ static int mga_do_dma_bootstrap(struct drm_device * dev, * AGP memory, etc. */ - if (!is_agp || err) { + if (!is_agp || err) err = mga_do_pci_dma_bootstrap(dev, dma_bs); - } return err; } @@ -792,7 +785,7 @@ int mga_dma_bootstrap(struct drm_device *dev, void *data, return err; } -static int mga_do_init_dma(struct drm_device * dev, drm_mga_init_t * init) +static int mga_do_init_dma(struct drm_device *dev, drm_mga_init_t *init) { drm_mga_private_t *dev_priv; int ret; @@ -800,11 +793,10 @@ static int mga_do_init_dma(struct drm_device * dev, drm_mga_init_t * init) dev_priv = dev->dev_private; - if (init->sgram) { + if (init->sgram) dev_priv->clear_cmd = MGA_DWGCTL_CLEAR | MGA_ATYPE_BLK; - } else { + else dev_priv->clear_cmd = MGA_DWGCTL_CLEAR | MGA_ATYPE_RSTR; - } dev_priv->maccess = init->maccess; dev_priv->fb_cpp = init->fb_cpp; @@ -975,9 +967,8 @@ static int mga_do_cleanup_dma(struct drm_device *dev, int full_cleanup) dev_priv->agp_handle = 0; } - if ((dev->agp != NULL) && dev->agp->acquired) { + if ((dev->agp != NULL) && dev->agp->acquired) err = drm_agp_release(dev); - } #endif } @@ -998,9 +989,8 @@ static int mga_do_cleanup_dma(struct drm_device *dev, int full_cleanup) memset(dev_priv->warp_pipe_phys, 0, sizeof(dev_priv->warp_pipe_phys)); - if (dev_priv->head != NULL) { + if (dev_priv->head != NULL) mga_freelist_cleanup(dev); - } } return err; @@ -1017,9 +1007,8 @@ int mga_dma_init(struct drm_device *dev, void *data, switch (init->func) { case MGA_INIT_DMA: err = mga_do_init_dma(dev, init); - if (err) { + if (err) (void)mga_do_cleanup_dma(dev, FULL_CLEANUP); - } return err; case MGA_CLEANUP_DMA: return mga_do_cleanup_dma(dev, FULL_CLEANUP); @@ -1047,9 +1036,8 @@ int mga_dma_flush(struct drm_device *dev, void *data, WRAP_WAIT_WITH_RETURN(dev_priv); - if (lock->flags & (_DRM_LOCK_FLUSH | _DRM_LOCK_FLUSH_ALL)) { + if (lock->flags & (_DRM_LOCK_FLUSH | _DRM_LOCK_FLUSH_ALL)) mga_do_dma_flush(dev_priv); - } if (lock->flags & _DRM_LOCK_QUIESCENT) { #if MGA_DMA_DEBUG @@ -1079,8 +1067,8 @@ int mga_dma_reset(struct drm_device *dev, void *data, * DMA buffer management */ -static int mga_dma_get_buffers(struct drm_device * dev, - struct drm_file *file_priv, struct drm_dma * d) +static int mga_dma_get_buffers(struct drm_device *dev, + struct drm_file *file_priv, struct drm_dma *d) { struct drm_buf *buf; int i; @@ -1134,9 +1122,8 @@ int mga_dma_buffers(struct drm_device *dev, void *data, d->granted_count = 0; - if (d->request_count) { + if (d->request_count) ret = mga_dma_get_buffers(dev, file_priv, d); - } return ret; } @@ -1144,7 +1131,7 @@ int mga_dma_buffers(struct drm_device *dev, void *data, /** * Called just before the module is unloaded. */ -int mga_driver_unload(struct drm_device * dev) +int mga_driver_unload(struct drm_device *dev) { kfree(dev->dev_private); dev->dev_private = NULL; @@ -1155,12 +1142,12 @@ int mga_driver_unload(struct drm_device * dev) /** * Called when the last opener of the device is closed. */ -void mga_driver_lastclose(struct drm_device * dev) +void mga_driver_lastclose(struct drm_device *dev) { mga_do_cleanup_dma(dev, FULL_CLEANUP); } -int mga_driver_dma_quiescent(struct drm_device * dev) +int mga_driver_dma_quiescent(struct drm_device *dev) { drm_mga_private_t *dev_priv = dev->dev_private; return mga_do_wait_for_idle(dev_priv); diff --git a/drivers/gpu/drm/mga/mga_drv.c b/drivers/gpu/drm/mga/mga_drv.c index ddfe161..26d0d8c 100644 --- a/drivers/gpu/drm/mga/mga_drv.c +++ b/drivers/gpu/drm/mga/mga_drv.c @@ -36,7 +36,7 @@ #include "drm_pciids.h" -static int mga_driver_device_is_agp(struct drm_device * dev); +static int mga_driver_device_is_agp(struct drm_device *dev); static struct pci_device_id pciidlist[] = { mga_PCI_IDS @@ -119,7 +119,7 @@ MODULE_LICENSE("GPL and additional rights"); * \returns * If the device is a PCI G450, zero is returned. Otherwise 2 is returned. */ -static int mga_driver_device_is_agp(struct drm_device * dev) +static int mga_driver_device_is_agp(struct drm_device *dev) { const struct pci_dev *const pdev = dev->pdev; diff --git a/drivers/gpu/drm/mga/mga_drv.h b/drivers/gpu/drm/mga/mga_drv.h index be6c6b9..1084fa4 100644 --- a/drivers/gpu/drm/mga/mga_drv.h +++ b/drivers/gpu/drm/mga/mga_drv.h @@ -164,59 +164,59 @@ extern int mga_dma_reset(struct drm_device *dev, void *data, extern int mga_dma_buffers(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int mga_driver_load(struct drm_device *dev, unsigned long flags); -extern int mga_driver_unload(struct drm_device * dev); -extern void mga_driver_lastclose(struct drm_device * dev); -extern int mga_driver_dma_quiescent(struct drm_device * dev); +extern int mga_driver_unload(struct drm_device *dev); +extern void mga_driver_lastclose(struct drm_device *dev); +extern int mga_driver_dma_quiescent(struct drm_device *dev); -extern int mga_do_wait_for_idle(drm_mga_private_t * dev_priv); +extern int mga_do_wait_for_idle(drm_mga_private_t *dev_priv); -extern void mga_do_dma_flush(drm_mga_private_t * dev_priv); -extern void mga_do_dma_wrap_start(drm_mga_private_t * dev_priv); -extern void mga_do_dma_wrap_end(drm_mga_private_t * dev_priv); +extern void mga_do_dma_flush(drm_mga_private_t *dev_priv); +extern void mga_do_dma_wrap_start(drm_mga_private_t *dev_priv); +extern void mga_do_dma_wrap_end(drm_mga_private_t *dev_priv); -extern int mga_freelist_put(struct drm_device * dev, struct drm_buf * buf); +extern int mga_freelist_put(struct drm_device *dev, struct drm_buf *buf); /* mga_warp.c */ -extern int mga_warp_install_microcode(drm_mga_private_t * dev_priv); -extern int mga_warp_init(drm_mga_private_t * dev_priv); +extern int mga_warp_install_microcode(drm_mga_private_t *dev_priv); +extern int mga_warp_init(drm_mga_private_t *dev_priv); /* mga_irq.c */ extern int mga_enable_vblank(struct drm_device *dev, int crtc); extern void mga_disable_vblank(struct drm_device *dev, int crtc); extern u32 mga_get_vblank_counter(struct drm_device *dev, int crtc); -extern int mga_driver_fence_wait(struct drm_device * dev, unsigned int *sequence); -extern int mga_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence); +extern int mga_driver_fence_wait(struct drm_device *dev, unsigned int *sequence); +extern int mga_driver_vblank_wait(struct drm_device *dev, unsigned int *sequence); extern irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS); -extern void mga_driver_irq_preinstall(struct drm_device * dev); +extern void mga_driver_irq_preinstall(struct drm_device *dev); extern int mga_driver_irq_postinstall(struct drm_device *dev); -extern void mga_driver_irq_uninstall(struct drm_device * dev); +extern void mga_driver_irq_uninstall(struct drm_device *dev); extern long mga_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); #define mga_flush_write_combine() DRM_WRITEMEMORYBARRIER() #if defined(__linux__) && defined(__alpha__) -#define MGA_BASE( reg ) ((unsigned long)(dev_priv->mmio->handle)) -#define MGA_ADDR( reg ) (MGA_BASE(reg) + reg) +#define MGA_BASE(reg) ((unsigned long)(dev_priv->mmio->handle)) +#define MGA_ADDR(reg) (MGA_BASE(reg) + reg) -#define MGA_DEREF( reg ) *(volatile u32 *)MGA_ADDR( reg ) -#define MGA_DEREF8( reg ) *(volatile u8 *)MGA_ADDR( reg ) +#define MGA_DEREF(reg) (*(volatile u32 *)MGA_ADDR(reg)) +#define MGA_DEREF8(reg) (*(volatile u8 *)MGA_ADDR(reg)) -#define MGA_READ( reg ) (_MGA_READ((u32 *)MGA_ADDR(reg))) -#define MGA_READ8( reg ) (_MGA_READ((u8 *)MGA_ADDR(reg))) -#define MGA_WRITE( reg, val ) do { DRM_WRITEMEMORYBARRIER(); MGA_DEREF( reg ) = val; } while (0) -#define MGA_WRITE8( reg, val ) do { DRM_WRITEMEMORYBARRIER(); MGA_DEREF8( reg ) = val; } while (0) +#define MGA_READ(reg) (_MGA_READ((u32 *)MGA_ADDR(reg))) +#define MGA_READ8(reg) (_MGA_READ((u8 *)MGA_ADDR(reg))) +#define MGA_WRITE(reg, val) do { DRM_WRITEMEMORYBARRIER(); MGA_DEREF(reg) = val; } while (0) +#define MGA_WRITE8(reg, val) do { DRM_WRITEMEMORYBARRIER(); MGA_DEREF8(reg) = val; } while (0) -static inline u32 _MGA_READ(u32 * addr) +static inline u32 _MGA_READ(u32 *addr) { DRM_MEMORYBARRIER(); return *(volatile u32 *)addr; } #else -#define MGA_READ8( reg ) DRM_READ8(dev_priv->mmio, (reg)) -#define MGA_READ( reg ) DRM_READ32(dev_priv->mmio, (reg)) -#define MGA_WRITE8( reg, val ) DRM_WRITE8(dev_priv->mmio, (reg), (val)) -#define MGA_WRITE( reg, val ) DRM_WRITE32(dev_priv->mmio, (reg), (val)) +#define MGA_READ8(reg) DRM_READ8(dev_priv->mmio, (reg)) +#define MGA_READ(reg) DRM_READ32(dev_priv->mmio, (reg)) +#define MGA_WRITE8(reg, val) DRM_WRITE8(dev_priv->mmio, (reg), (val)) +#define MGA_WRITE(reg, val) DRM_WRITE32(dev_priv->mmio, (reg), (val)) #endif #define DWGREG0 0x1c00 @@ -233,40 +233,39 @@ static inline u32 _MGA_READ(u32 * addr) * Helper macross... */ -#define MGA_EMIT_STATE( dev_priv, dirty ) \ +#define MGA_EMIT_STATE(dev_priv, dirty) \ do { \ - if ( (dirty) & ~MGA_UPLOAD_CLIPRECTS ) { \ - if ( dev_priv->chipset >= MGA_CARD_TYPE_G400 ) { \ - mga_g400_emit_state( dev_priv ); \ - } else { \ - mga_g200_emit_state( dev_priv ); \ - } \ + if ((dirty) & ~MGA_UPLOAD_CLIPRECTS) { \ + if (dev_priv->chipset >= MGA_CARD_TYPE_G400) \ + mga_g400_emit_state(dev_priv); \ + else \ + mga_g200_emit_state(dev_priv); \ } \ } while (0) -#define WRAP_TEST_WITH_RETURN( dev_priv ) \ +#define WRAP_TEST_WITH_RETURN(dev_priv) \ do { \ - if ( test_bit( 0, &dev_priv->prim.wrapped ) ) { \ - if ( mga_is_idle( dev_priv ) ) { \ - mga_do_dma_wrap_end( dev_priv ); \ - } else if ( dev_priv->prim.space < \ - dev_priv->prim.high_mark ) { \ - if ( MGA_DMA_DEBUG ) \ - DRM_INFO( "wrap...\n"); \ - return -EBUSY; \ + if (test_bit(0, &dev_priv->prim.wrapped)) { \ + if (mga_is_idle(dev_priv)) { \ + mga_do_dma_wrap_end(dev_priv); \ + } else if (dev_priv->prim.space < \ + dev_priv->prim.high_mark) { \ + if (MGA_DMA_DEBUG) \ + DRM_INFO("wrap...\n"); \ + return -EBUSY; \ } \ } \ } while (0) -#define WRAP_WAIT_WITH_RETURN( dev_priv ) \ +#define WRAP_WAIT_WITH_RETURN(dev_priv) \ do { \ - if ( test_bit( 0, &dev_priv->prim.wrapped ) ) { \ - if ( mga_do_wait_for_idle( dev_priv ) < 0 ) { \ - if ( MGA_DMA_DEBUG ) \ - DRM_INFO( "wrap...\n"); \ - return -EBUSY; \ + if (test_bit(0, &dev_priv->prim.wrapped)) { \ + if (mga_do_wait_for_idle(dev_priv) < 0) { \ + if (MGA_DMA_DEBUG) \ + DRM_INFO("wrap...\n"); \ + return -EBUSY; \ } \ - mga_do_dma_wrap_end( dev_priv ); \ + mga_do_dma_wrap_end(dev_priv); \ } \ } while (0) @@ -280,12 +279,12 @@ do { \ #define DMA_BLOCK_SIZE (5 * sizeof(u32)) -#define BEGIN_DMA( n ) \ +#define BEGIN_DMA(n) \ do { \ - if ( MGA_VERBOSE ) { \ - DRM_INFO( "BEGIN_DMA( %d )\n", (n) ); \ - DRM_INFO( " space=0x%x req=0x%Zx\n", \ - dev_priv->prim.space, (n) * DMA_BLOCK_SIZE ); \ + if (MGA_VERBOSE) { \ + DRM_INFO("BEGIN_DMA(%d)\n", (n)); \ + DRM_INFO(" space=0x%x req=0x%Zx\n", \ + dev_priv->prim.space, (n) * DMA_BLOCK_SIZE); \ } \ prim = dev_priv->prim.start; \ write = dev_priv->prim.tail; \ @@ -293,9 +292,9 @@ do { \ #define BEGIN_DMA_WRAP() \ do { \ - if ( MGA_VERBOSE ) { \ - DRM_INFO( "BEGIN_DMA()\n" ); \ - DRM_INFO( " space=0x%x\n", dev_priv->prim.space ); \ + if (MGA_VERBOSE) { \ + DRM_INFO("BEGIN_DMA()\n"); \ + DRM_INFO(" space=0x%x\n", dev_priv->prim.space); \ } \ prim = dev_priv->prim.start; \ write = dev_priv->prim.tail; \ @@ -304,72 +303,68 @@ do { \ #define ADVANCE_DMA() \ do { \ dev_priv->prim.tail = write; \ - if ( MGA_VERBOSE ) { \ - DRM_INFO( "ADVANCE_DMA() tail=0x%05x sp=0x%x\n", \ - write, dev_priv->prim.space ); \ - } \ + if (MGA_VERBOSE) \ + DRM_INFO("ADVANCE_DMA() tail=0x%05x sp=0x%x\n", \ + write, dev_priv->prim.space); \ } while (0) #define FLUSH_DMA() \ do { \ - if ( 0 ) { \ - DRM_INFO( "\n" ); \ - DRM_INFO( " tail=0x%06x head=0x%06lx\n", \ - dev_priv->prim.tail, \ - (unsigned long)(MGA_READ(MGA_PRIMADDRESS) - \ - dev_priv->primary->offset)); \ + if (0) { \ + DRM_INFO("\n"); \ + DRM_INFO(" tail=0x%06x head=0x%06lx\n", \ + dev_priv->prim.tail, \ + (unsigned long)(MGA_READ(MGA_PRIMADDRESS) - \ + dev_priv->primary->offset)); \ } \ - if ( !test_bit( 0, &dev_priv->prim.wrapped ) ) { \ - if ( dev_priv->prim.space < \ - dev_priv->prim.high_mark ) { \ - mga_do_dma_wrap_start( dev_priv ); \ - } else { \ - mga_do_dma_flush( dev_priv ); \ - } \ + if (!test_bit(0, &dev_priv->prim.wrapped)) { \ + if (dev_priv->prim.space < dev_priv->prim.high_mark) \ + mga_do_dma_wrap_start(dev_priv); \ + else \ + mga_do_dma_flush(dev_priv); \ } \ } while (0) /* Never use this, always use DMA_BLOCK(...) for primary DMA output. */ -#define DMA_WRITE( offset, val ) \ +#define DMA_WRITE(offset, val) \ do { \ - if ( MGA_VERBOSE ) { \ - DRM_INFO( " DMA_WRITE( 0x%08x ) at 0x%04Zx\n", \ - (u32)(val), write + (offset) * sizeof(u32) ); \ - } \ + if (MGA_VERBOSE) \ + DRM_INFO(" DMA_WRITE( 0x%08x ) at 0x%04Zx\n", \ + (u32)(val), write + (offset) * sizeof(u32)); \ *(volatile u32 *)(prim + write + (offset) * sizeof(u32)) = val; \ } while (0) -#define DMA_BLOCK( reg0, val0, reg1, val1, reg2, val2, reg3, val3 ) \ +#define DMA_BLOCK(reg0, val0, reg1, val1, reg2, val2, reg3, val3) \ do { \ - DMA_WRITE( 0, ((DMAREG( reg0 ) << 0) | \ - (DMAREG( reg1 ) << 8) | \ - (DMAREG( reg2 ) << 16) | \ - (DMAREG( reg3 ) << 24)) ); \ - DMA_WRITE( 1, val0 ); \ - DMA_WRITE( 2, val1 ); \ - DMA_WRITE( 3, val2 ); \ - DMA_WRITE( 4, val3 ); \ + DMA_WRITE(0, ((DMAREG(reg0) << 0) | \ + (DMAREG(reg1) << 8) | \ + (DMAREG(reg2) << 16) | \ + (DMAREG(reg3) << 24))); \ + DMA_WRITE(1, val0); \ + DMA_WRITE(2, val1); \ + DMA_WRITE(3, val2); \ + DMA_WRITE(4, val3); \ write += DMA_BLOCK_SIZE; \ } while (0) /* Buffer aging via primary DMA stream head pointer. */ -#define SET_AGE( age, h, w ) \ +#define SET_AGE(age, h, w) \ do { \ (age)->head = h; \ (age)->wrap = w; \ } while (0) -#define TEST_AGE( age, h, w ) ( (age)->wrap < w || \ - ( (age)->wrap == w && \ - (age)->head < h ) ) +#define TEST_AGE(age, h, w) ((age)->wrap < w || \ + ((age)->wrap == w && \ + (age)->head < h)) -#define AGE_BUFFER( buf_priv ) \ +#define AGE_BUFFER(buf_priv) \ do { \ drm_mga_freelist_t *entry = (buf_priv)->list_entry; \ - if ( (buf_priv)->dispatched ) { \ + if ((buf_priv)->dispatched) { \ entry->age.head = (dev_priv->prim.tail + \ dev_priv->primary->offset); \ entry->age.wrap = dev_priv->sarea_priv->last_wrap; \ @@ -681,7 +676,7 @@ do { \ /* Simple idle test. */ -static __inline__ int mga_is_idle(drm_mga_private_t * dev_priv) +static __inline__ int mga_is_idle(drm_mga_private_t *dev_priv) { u32 status = MGA_READ(MGA_STATUS) & MGA_ENGINE_IDLE_MASK; return (status == MGA_ENDPRDMASTS); diff --git a/drivers/gpu/drm/mga/mga_irq.c b/drivers/gpu/drm/mga/mga_irq.c index daa6041..2581202 100644 --- a/drivers/gpu/drm/mga/mga_irq.c +++ b/drivers/gpu/drm/mga/mga_irq.c @@ -76,9 +76,8 @@ irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS) /* In addition to clearing the interrupt-pending bit, we * have to write to MGA_PRIMEND to re-start the DMA operation. */ - if ((prim_start & ~0x03) != (prim_end & ~0x03)) { + if ((prim_start & ~0x03) != (prim_end & ~0x03)) MGA_WRITE(MGA_PRIMEND, prim_end); - } atomic_inc(&dev_priv->last_fence_retired); DRM_WAKEUP(&dev_priv->fence_queue); @@ -120,7 +119,7 @@ void mga_disable_vblank(struct drm_device *dev, int crtc) /* MGA_WRITE(MGA_IEN, MGA_VLINEIEN | MGA_SOFTRAPEN); */ } -int mga_driver_fence_wait(struct drm_device * dev, unsigned int *sequence) +int mga_driver_fence_wait(struct drm_device *dev, unsigned int *sequence) { drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private; unsigned int cur_fence; @@ -139,7 +138,7 @@ int mga_driver_fence_wait(struct drm_device * dev, unsigned int *sequence) return ret; } -void mga_driver_irq_preinstall(struct drm_device * dev) +void mga_driver_irq_preinstall(struct drm_device *dev) { drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private; @@ -162,7 +161,7 @@ int mga_driver_irq_postinstall(struct drm_device *dev) return 0; } -void mga_driver_irq_uninstall(struct drm_device * dev) +void mga_driver_irq_uninstall(struct drm_device *dev) { drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private; if (!dev_priv) diff --git a/drivers/gpu/drm/mga/mga_state.c b/drivers/gpu/drm/mga/mga_state.c index a53b848..fff8204 100644 --- a/drivers/gpu/drm/mga/mga_state.c +++ b/drivers/gpu/drm/mga/mga_state.c @@ -41,8 +41,8 @@ * DMA hardware state programming functions */ -static void mga_emit_clip_rect(drm_mga_private_t * dev_priv, - struct drm_clip_rect * box) +static void mga_emit_clip_rect(drm_mga_private_t *dev_priv, + struct drm_clip_rect *box) { drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; drm_mga_context_regs_t *ctx = &sarea_priv->context_state; @@ -66,7 +66,7 @@ static void mga_emit_clip_rect(drm_mga_private_t * dev_priv, ADVANCE_DMA(); } -static __inline__ void mga_g200_emit_context(drm_mga_private_t * dev_priv) +static __inline__ void mga_g200_emit_context(drm_mga_private_t *dev_priv) { drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; drm_mga_context_regs_t *ctx = &sarea_priv->context_state; @@ -89,7 +89,7 @@ static __inline__ void mga_g200_emit_context(drm_mga_private_t * dev_priv) ADVANCE_DMA(); } -static __inline__ void mga_g400_emit_context(drm_mga_private_t * dev_priv) +static __inline__ void mga_g400_emit_context(drm_mga_private_t *dev_priv) { drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; drm_mga_context_regs_t *ctx = &sarea_priv->context_state; @@ -116,7 +116,7 @@ static __inline__ void mga_g400_emit_context(drm_mga_private_t * dev_priv) ADVANCE_DMA(); } -static __inline__ void mga_g200_emit_tex0(drm_mga_private_t * dev_priv) +static __inline__ void mga_g200_emit_tex0(drm_mga_private_t *dev_priv) { drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; drm_mga_texture_regs_t *tex = &sarea_priv->tex_state[0]; @@ -144,7 +144,7 @@ static __inline__ void mga_g200_emit_tex0(drm_mga_private_t * dev_priv) ADVANCE_DMA(); } -static __inline__ void mga_g400_emit_tex0(drm_mga_private_t * dev_priv) +static __inline__ void mga_g400_emit_tex0(drm_mga_private_t *dev_priv) { drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; drm_mga_texture_regs_t *tex = &sarea_priv->tex_state[0]; @@ -184,7 +184,7 @@ static __inline__ void mga_g400_emit_tex0(drm_mga_private_t * dev_priv) ADVANCE_DMA(); } -static __inline__ void mga_g400_emit_tex1(drm_mga_private_t * dev_priv) +static __inline__ void mga_g400_emit_tex1(drm_mga_private_t *dev_priv) { drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; drm_mga_texture_regs_t *tex = &sarea_priv->tex_state[1]; @@ -223,7 +223,7 @@ static __inline__ void mga_g400_emit_tex1(drm_mga_private_t * dev_priv) ADVANCE_DMA(); } -static __inline__ void mga_g200_emit_pipe(drm_mga_private_t * dev_priv) +static __inline__ void mga_g200_emit_pipe(drm_mga_private_t *dev_priv) { drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; unsigned int pipe = sarea_priv->warp_pipe; @@ -250,7 +250,7 @@ static __inline__ void mga_g200_emit_pipe(drm_mga_private_t * dev_priv) ADVANCE_DMA(); } -static __inline__ void mga_g400_emit_pipe(drm_mga_private_t * dev_priv) +static __inline__ void mga_g400_emit_pipe(drm_mga_private_t *dev_priv) { drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; unsigned int pipe = sarea_priv->warp_pipe; @@ -327,7 +327,7 @@ static __inline__ void mga_g400_emit_pipe(drm_mga_private_t * dev_priv) ADVANCE_DMA(); } -static void mga_g200_emit_state(drm_mga_private_t * dev_priv) +static void mga_g200_emit_state(drm_mga_private_t *dev_priv) { drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; unsigned int dirty = sarea_priv->dirty; @@ -348,7 +348,7 @@ static void mga_g200_emit_state(drm_mga_private_t * dev_priv) } } -static void mga_g400_emit_state(drm_mga_private_t * dev_priv) +static void mga_g400_emit_state(drm_mga_private_t *dev_priv) { drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; unsigned int dirty = sarea_priv->dirty; @@ -381,7 +381,7 @@ static void mga_g400_emit_state(drm_mga_private_t * dev_priv) /* Disallow all write destinations except the front and backbuffer. */ -static int mga_verify_context(drm_mga_private_t * dev_priv) +static int mga_verify_context(drm_mga_private_t *dev_priv) { drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; drm_mga_context_regs_t *ctx = &sarea_priv->context_state; @@ -400,7 +400,7 @@ static int mga_verify_context(drm_mga_private_t * dev_priv) /* Disallow texture reads from PCI space. */ -static int mga_verify_tex(drm_mga_private_t * dev_priv, int unit) +static int mga_verify_tex(drm_mga_private_t *dev_priv, int unit) { drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; drm_mga_texture_regs_t *tex = &sarea_priv->tex_state[unit]; @@ -417,7 +417,7 @@ static int mga_verify_tex(drm_mga_private_t * dev_priv, int unit) return 0; } -static int mga_verify_state(drm_mga_private_t * dev_priv) +static int mga_verify_state(drm_mga_private_t *dev_priv) { drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; unsigned int dirty = sarea_priv->dirty; @@ -446,7 +446,7 @@ static int mga_verify_state(drm_mga_private_t * dev_priv) return (ret == 0); } -static int mga_verify_iload(drm_mga_private_t * dev_priv, +static int mga_verify_iload(drm_mga_private_t *dev_priv, unsigned int dstorg, unsigned int length) { if (dstorg < dev_priv->texture_offset || @@ -465,7 +465,7 @@ static int mga_verify_iload(drm_mga_private_t * dev_priv, return 0; } -static int mga_verify_blit(drm_mga_private_t * dev_priv, +static int mga_verify_blit(drm_mga_private_t *dev_priv, unsigned int srcorg, unsigned int dstorg) { if ((srcorg & 0x3) == (MGA_SRCACC_PCI | MGA_SRCMAP_SYSMEM) || @@ -480,7 +480,7 @@ static int mga_verify_blit(drm_mga_private_t * dev_priv, * */ -static void mga_dma_dispatch_clear(struct drm_device * dev, drm_mga_clear_t * clear) +static void mga_dma_dispatch_clear(struct drm_device *dev, drm_mga_clear_t *clear) { drm_mga_private_t *dev_priv = dev->dev_private; drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; @@ -568,7 +568,7 @@ static void mga_dma_dispatch_clear(struct drm_device * dev, drm_mga_clear_t * cl FLUSH_DMA(); } -static void mga_dma_dispatch_swap(struct drm_device * dev) +static void mga_dma_dispatch_swap(struct drm_device *dev) { drm_mga_private_t *dev_priv = dev->dev_private; drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; @@ -622,7 +622,7 @@ static void mga_dma_dispatch_swap(struct drm_device * dev) DRM_DEBUG("... done.\n"); } -static void mga_dma_dispatch_vertex(struct drm_device * dev, struct drm_buf * buf) +static void mga_dma_dispatch_vertex(struct drm_device *dev, struct drm_buf *buf) { drm_mga_private_t *dev_priv = dev->dev_private; drm_mga_buf_priv_t *buf_priv = buf->dev_private; @@ -669,7 +669,7 @@ static void mga_dma_dispatch_vertex(struct drm_device * dev, struct drm_buf * bu FLUSH_DMA(); } -static void mga_dma_dispatch_indices(struct drm_device * dev, struct drm_buf * buf, +static void mga_dma_dispatch_indices(struct drm_device *dev, struct drm_buf *buf, unsigned int start, unsigned int end) { drm_mga_private_t *dev_priv = dev->dev_private; @@ -718,7 +718,7 @@ static void mga_dma_dispatch_indices(struct drm_device * dev, struct drm_buf * b /* This copies a 64 byte aligned agp region to the frambuffer with a * standard blit, the ioctl needs to do checking. */ -static void mga_dma_dispatch_iload(struct drm_device * dev, struct drm_buf * buf, +static void mga_dma_dispatch_iload(struct drm_device *dev, struct drm_buf *buf, unsigned int dstorg, unsigned int length) { drm_mga_private_t *dev_priv = dev->dev_private; @@ -766,7 +766,7 @@ static void mga_dma_dispatch_iload(struct drm_device * dev, struct drm_buf * buf FLUSH_DMA(); } -static void mga_dma_dispatch_blit(struct drm_device * dev, drm_mga_blit_t * blit) +static void mga_dma_dispatch_blit(struct drm_device *dev, drm_mga_blit_t *blit) { drm_mga_private_t *dev_priv = dev->dev_private; drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; @@ -801,9 +801,8 @@ static void mga_dma_dispatch_blit(struct drm_device * dev, drm_mga_blit_t * blit int w = pbox[i].x2 - pbox[i].x1 - 1; int start; - if (blit->ydir == -1) { + if (blit->ydir == -1) srcy = blit->height - srcy - 1; - } start = srcy * blit->src_pitch + srcx; diff --git a/drivers/gpu/drm/mga/mga_warp.c b/drivers/gpu/drm/mga/mga_warp.c index 9aad484..f172bd5 100644 --- a/drivers/gpu/drm/mga/mga_warp.c +++ b/drivers/gpu/drm/mga/mga_warp.c @@ -46,7 +46,7 @@ MODULE_FIRMWARE(FIRMWARE_G400); #define WARP_UCODE_SIZE(size) ALIGN(size, MGA_WARP_CODE_ALIGN) -int mga_warp_install_microcode(drm_mga_private_t * dev_priv) +int mga_warp_install_microcode(drm_mga_private_t *dev_priv) { unsigned char *vcbase = dev_priv->warp->handle; unsigned long pcbase = dev_priv->warp->offset; @@ -133,7 +133,7 @@ out: #define WMISC_EXPECTED (MGA_WUCODECACHE_ENABLE | MGA_WMASTER_ENABLE) -int mga_warp_init(drm_mga_private_t * dev_priv) +int mga_warp_init(drm_mga_private_t *dev_priv) { u32 wmisc; diff --git a/drivers/gpu/drm/nouveau/Kconfig b/drivers/gpu/drm/nouveau/Kconfig index 1175429..d2d2804 100644 --- a/drivers/gpu/drm/nouveau/Kconfig +++ b/drivers/gpu/drm/nouveau/Kconfig @@ -1,6 +1,6 @@ config DRM_NOUVEAU tristate "Nouveau (nVidia) cards" - depends on DRM + depends on DRM && PCI select FW_LOADER select DRM_KMS_HELPER select DRM_TTM @@ -41,4 +41,13 @@ config DRM_I2C_CH7006 This driver is currently only useful if you're also using the nouveau driver. + +config DRM_I2C_SIL164 + tristate "Silicon Image sil164 TMDS transmitter" + default m if DRM_NOUVEAU + help + Support for sil164 and similar single-link (or dual-link + when used in pairs) TMDS transmitters, used in some nVidia + video cards. + endmenu diff --git a/drivers/gpu/drm/nouveau/Makefile b/drivers/gpu/drm/nouveau/Makefile index acd31ed..2405d5e 100644 --- a/drivers/gpu/drm/nouveau/Makefile +++ b/drivers/gpu/drm/nouveau/Makefile @@ -9,10 +9,10 @@ nouveau-y := nouveau_drv.o nouveau_state.o nouveau_channel.o nouveau_mem.o \ nouveau_bo.o nouveau_fence.o nouveau_gem.o nouveau_ttm.o \ nouveau_hw.o nouveau_calc.o nouveau_bios.o nouveau_i2c.o \ nouveau_display.o nouveau_connector.o nouveau_fbcon.o \ - nouveau_dp.o nouveau_grctx.o \ + nouveau_dp.o \ nv04_timer.o \ nv04_mc.o nv40_mc.o nv50_mc.o \ - nv04_fb.o nv10_fb.o nv40_fb.o nv50_fb.o \ + nv04_fb.o nv10_fb.o nv30_fb.o nv40_fb.o nv50_fb.o \ nv04_fifo.o nv10_fifo.o nv40_fifo.o nv50_fifo.o \ nv04_graph.o nv10_graph.o nv20_graph.o \ nv40_graph.o nv50_graph.o \ @@ -22,7 +22,7 @@ nouveau-y := nouveau_drv.o nouveau_state.o nouveau_channel.o nouveau_mem.o \ nv50_cursor.o nv50_display.o nv50_fbcon.o \ nv04_dac.o nv04_dfp.o nv04_tv.o nv17_tv.o nv17_tv_modes.o \ nv04_crtc.o nv04_display.o nv04_cursor.o nv04_fbcon.o \ - nv17_gpio.o nv50_gpio.o \ + nv10_gpio.o nv50_gpio.o \ nv50_calc.o nouveau-$(CONFIG_DRM_NOUVEAU_DEBUG) += nouveau_debugfs.o diff --git a/drivers/gpu/drm/nouveau/nouveau_acpi.c b/drivers/gpu/drm/nouveau/nouveau_acpi.c index d4bcca8..c17a055 100644 --- a/drivers/gpu/drm/nouveau/nouveau_acpi.c +++ b/drivers/gpu/drm/nouveau/nouveau_acpi.c @@ -3,6 +3,7 @@ #include <linux/slab.h> #include <acpi/acpi_drivers.h> #include <acpi/acpi_bus.h> +#include <acpi/video.h> #include "drmP.h" #include "drm.h" @@ -11,6 +12,7 @@ #include "nouveau_drv.h" #include "nouveau_drm.h" #include "nv50_display.h" +#include "nouveau_connector.h" #include <linux/vga_switcheroo.h> @@ -42,7 +44,7 @@ static const char nouveau_dsm_muid[] = { 0xB3, 0x4D, 0x7E, 0x5F, 0xEA, 0x12, 0x9F, 0xD4, }; -static int nouveau_dsm(acpi_handle handle, int func, int arg, int *result) +static int nouveau_dsm(acpi_handle handle, int func, int arg, uint32_t *result) { struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; struct acpi_object_list input; @@ -259,3 +261,37 @@ int nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len) { return nouveau_rom_call(nouveau_dsm_priv.rom_handle, bios, offset, len); } + +int +nouveau_acpi_edid(struct drm_device *dev, struct drm_connector *connector) +{ + struct nouveau_connector *nv_connector = nouveau_connector(connector); + struct acpi_device *acpidev; + acpi_handle handle; + int type, ret; + void *edid; + + switch (connector->connector_type) { + case DRM_MODE_CONNECTOR_LVDS: + case DRM_MODE_CONNECTOR_eDP: + type = ACPI_VIDEO_DISPLAY_LCD; + break; + default: + return -EINVAL; + } + + handle = DEVICE_ACPI_HANDLE(&dev->pdev->dev); + if (!handle) + return -ENODEV; + + ret = acpi_bus_get_device(handle, &acpidev); + if (ret) + return -ENODEV; + + ret = acpi_video_get_edid(acpidev, type, -1, &edid); + if (ret < 0) + return ret; + + nv_connector->edid = edid; + return 0; +} diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index e492919..7369b5e 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -28,6 +28,8 @@ #include "nouveau_hw.h" #include "nouveau_encoder.h" +#include <linux/io-mapping.h> + /* these defines are made up */ #define NV_CIO_CRE_44_HEADA 0x0 #define NV_CIO_CRE_44_HEADB 0x3 @@ -209,20 +211,20 @@ static struct methods shadow_methods[] = { { "PCIROM", load_vbios_pci, true }, { "ACPI", load_vbios_acpi, true }, }; +#define NUM_SHADOW_METHODS ARRAY_SIZE(shadow_methods) static bool NVShadowVBIOS(struct drm_device *dev, uint8_t *data) { - const int nr_methods = ARRAY_SIZE(shadow_methods); struct methods *methods = shadow_methods; int testscore = 3; - int scores[nr_methods], i; + int scores[NUM_SHADOW_METHODS], i; if (nouveau_vbios) { - for (i = 0; i < nr_methods; i++) + for (i = 0; i < NUM_SHADOW_METHODS; i++) if (!strcasecmp(nouveau_vbios, methods[i].desc)) break; - if (i < nr_methods) { + if (i < NUM_SHADOW_METHODS) { NV_INFO(dev, "Attempting to use BIOS image from %s\n", methods[i].desc); @@ -234,7 +236,7 @@ static bool NVShadowVBIOS(struct drm_device *dev, uint8_t *data) NV_ERROR(dev, "VBIOS source \'%s\' invalid\n", nouveau_vbios); } - for (i = 0; i < nr_methods; i++) { + for (i = 0; i < NUM_SHADOW_METHODS; i++) { NV_TRACE(dev, "Attempting to load BIOS image from %s\n", methods[i].desc); data[0] = data[1] = 0; /* avoid reuse of previous image */ @@ -245,7 +247,7 @@ static bool NVShadowVBIOS(struct drm_device *dev, uint8_t *data) } while (--testscore > 0) { - for (i = 0; i < nr_methods; i++) { + for (i = 0; i < NUM_SHADOW_METHODS; i++) { if (scores[i] == testscore) { NV_TRACE(dev, "Using BIOS image from %s\n", methods[i].desc); @@ -920,7 +922,7 @@ init_io_restrict_prog(struct nvbios *bios, uint16_t offset, NV_ERROR(bios->dev, "0x%04X: Config 0x%02X exceeds maximal bound 0x%02X\n", offset, config, count); - return -EINVAL; + return len; } configval = ROM32(bios->data[offset + 11 + config * 4]); @@ -1022,7 +1024,7 @@ init_io_restrict_pll(struct nvbios *bios, uint16_t offset, NV_ERROR(bios->dev, "0x%04X: Config 0x%02X exceeds maximal bound 0x%02X\n", offset, config, count); - return -EINVAL; + return len; } freq = ROM16(bios->data[offset + 12 + config * 2]); @@ -1194,7 +1196,7 @@ init_dp_condition(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) dpe = nouveau_bios_dp_table(dev, dcb, &dummy); if (!dpe) { NV_ERROR(dev, "0x%04X: INIT_3A: no encoder table!!\n", offset); - return -EINVAL; + return 3; } switch (cond) { @@ -1218,12 +1220,16 @@ init_dp_condition(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) int ret; auxch = nouveau_i2c_find(dev, bios->display.output->i2c_index); - if (!auxch) - return -ENODEV; + if (!auxch) { + NV_ERROR(dev, "0x%04X: couldn't get auxch\n", offset); + return 3; + } ret = nouveau_dp_auxch(auxch, 9, 0xd, &cond, 1); - if (ret) - return ret; + if (ret) { + NV_ERROR(dev, "0x%04X: auxch rd fail: %d\n", offset, ret); + return 3; + } if (cond & 1) iexec->execute = false; @@ -1392,7 +1398,7 @@ init_io_restrict_pll2(struct nvbios *bios, uint16_t offset, NV_ERROR(bios->dev, "0x%04X: Config 0x%02X exceeds maximal bound 0x%02X\n", offset, config, count); - return -EINVAL; + return len; } freq = ROM32(bios->data[offset + 11 + config * 4]); @@ -1452,6 +1458,7 @@ init_i2c_byte(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) * "mask n" and OR it with "data n" before writing it back to the device */ + struct drm_device *dev = bios->dev; uint8_t i2c_index = bios->data[offset + 1]; uint8_t i2c_address = bios->data[offset + 2] >> 1; uint8_t count = bios->data[offset + 3]; @@ -1466,9 +1473,11 @@ init_i2c_byte(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) "Count: 0x%02X\n", offset, i2c_index, i2c_address, count); - chan = init_i2c_device_find(bios->dev, i2c_index); - if (!chan) - return -ENODEV; + chan = init_i2c_device_find(dev, i2c_index); + if (!chan) { + NV_ERROR(dev, "0x%04X: i2c bus not found\n", offset); + return len; + } for (i = 0; i < count; i++) { uint8_t reg = bios->data[offset + 4 + i * 3]; @@ -1479,8 +1488,10 @@ init_i2c_byte(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) ret = i2c_smbus_xfer(&chan->adapter, i2c_address, 0, I2C_SMBUS_READ, reg, I2C_SMBUS_BYTE_DATA, &val); - if (ret < 0) - return ret; + if (ret < 0) { + NV_ERROR(dev, "0x%04X: i2c rd fail: %d\n", offset, ret); + return len; + } BIOSLOG(bios, "0x%04X: I2CReg: 0x%02X, Value: 0x%02X, " "Mask: 0x%02X, Data: 0x%02X\n", @@ -1494,8 +1505,10 @@ init_i2c_byte(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) ret = i2c_smbus_xfer(&chan->adapter, i2c_address, 0, I2C_SMBUS_WRITE, reg, I2C_SMBUS_BYTE_DATA, &val); - if (ret < 0) - return ret; + if (ret < 0) { + NV_ERROR(dev, "0x%04X: i2c wr fail: %d\n", offset, ret); + return len; + } } return len; @@ -1520,6 +1533,7 @@ init_zm_i2c_byte(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) * "DCB I2C table entry index", set the register to "data n" */ + struct drm_device *dev = bios->dev; uint8_t i2c_index = bios->data[offset + 1]; uint8_t i2c_address = bios->data[offset + 2] >> 1; uint8_t count = bios->data[offset + 3]; @@ -1534,9 +1548,11 @@ init_zm_i2c_byte(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) "Count: 0x%02X\n", offset, i2c_index, i2c_address, count); - chan = init_i2c_device_find(bios->dev, i2c_index); - if (!chan) - return -ENODEV; + chan = init_i2c_device_find(dev, i2c_index); + if (!chan) { + NV_ERROR(dev, "0x%04X: i2c bus not found\n", offset); + return len; + } for (i = 0; i < count; i++) { uint8_t reg = bios->data[offset + 4 + i * 2]; @@ -1553,8 +1569,10 @@ init_zm_i2c_byte(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) ret = i2c_smbus_xfer(&chan->adapter, i2c_address, 0, I2C_SMBUS_WRITE, reg, I2C_SMBUS_BYTE_DATA, &val); - if (ret < 0) - return ret; + if (ret < 0) { + NV_ERROR(dev, "0x%04X: i2c wr fail: %d\n", offset, ret); + return len; + } } return len; @@ -1577,6 +1595,7 @@ init_zm_i2c(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) * address" on the I2C bus given by "DCB I2C table entry index" */ + struct drm_device *dev = bios->dev; uint8_t i2c_index = bios->data[offset + 1]; uint8_t i2c_address = bios->data[offset + 2] >> 1; uint8_t count = bios->data[offset + 3]; @@ -1584,7 +1603,7 @@ init_zm_i2c(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) struct nouveau_i2c_chan *chan; struct i2c_msg msg; uint8_t data[256]; - int i; + int ret, i; if (!iexec->execute) return len; @@ -1593,9 +1612,11 @@ init_zm_i2c(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) "Count: 0x%02X\n", offset, i2c_index, i2c_address, count); - chan = init_i2c_device_find(bios->dev, i2c_index); - if (!chan) - return -ENODEV; + chan = init_i2c_device_find(dev, i2c_index); + if (!chan) { + NV_ERROR(dev, "0x%04X: i2c bus not found\n", offset); + return len; + } for (i = 0; i < count; i++) { data[i] = bios->data[offset + 4 + i]; @@ -1608,8 +1629,11 @@ init_zm_i2c(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) msg.flags = 0; msg.len = count; msg.buf = data; - if (i2c_transfer(&chan->adapter, &msg, 1) != 1) - return -EIO; + ret = i2c_transfer(&chan->adapter, &msg, 1); + if (ret != 1) { + NV_ERROR(dev, "0x%04X: i2c wr fail: %d\n", offset, ret); + return len; + } } return len; @@ -1633,6 +1657,7 @@ init_tmds(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) * used -- see get_tmds_index_reg() */ + struct drm_device *dev = bios->dev; uint8_t mlv = bios->data[offset + 1]; uint32_t tmdsaddr = bios->data[offset + 2]; uint8_t mask = bios->data[offset + 3]; @@ -1647,8 +1672,10 @@ init_tmds(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) offset, mlv, tmdsaddr, mask, data); reg = get_tmds_index_reg(bios->dev, mlv); - if (!reg) - return -EINVAL; + if (!reg) { + NV_ERROR(dev, "0x%04X: no tmds_index_reg\n", offset); + return 5; + } bios_wr32(bios, reg, tmdsaddr | NV_PRAMDAC_FP_TMDS_CONTROL_WRITE_DISABLE); @@ -1678,6 +1705,7 @@ init_zm_tmds_group(struct nvbios *bios, uint16_t offset, * register is used -- see get_tmds_index_reg() */ + struct drm_device *dev = bios->dev; uint8_t mlv = bios->data[offset + 1]; uint8_t count = bios->data[offset + 2]; int len = 3 + count * 2; @@ -1691,8 +1719,10 @@ init_zm_tmds_group(struct nvbios *bios, uint16_t offset, offset, mlv, count); reg = get_tmds_index_reg(bios->dev, mlv); - if (!reg) - return -EINVAL; + if (!reg) { + NV_ERROR(dev, "0x%04X: no tmds_index_reg\n", offset); + return len; + } for (i = 0; i < count; i++) { uint8_t tmdsaddr = bios->data[offset + 3 + i * 2]; @@ -2039,6 +2069,323 @@ init_zm_index_io(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) return 5; } +static inline void +bios_md32(struct nvbios *bios, uint32_t reg, + uint32_t mask, uint32_t val) +{ + bios_wr32(bios, reg, (bios_rd32(bios, reg) & ~mask) | val); +} + +static uint32_t +peek_fb(struct drm_device *dev, struct io_mapping *fb, + uint32_t off) +{ + uint32_t val = 0; + + if (off < pci_resource_len(dev->pdev, 1)) { + uint32_t __iomem *p = io_mapping_map_atomic_wc(fb, off, KM_USER0); + + val = ioread32(p); + + io_mapping_unmap_atomic(p, KM_USER0); + } + + return val; +} + +static void +poke_fb(struct drm_device *dev, struct io_mapping *fb, + uint32_t off, uint32_t val) +{ + if (off < pci_resource_len(dev->pdev, 1)) { + uint32_t __iomem *p = io_mapping_map_atomic_wc(fb, off, KM_USER0); + + iowrite32(val, p); + wmb(); + + io_mapping_unmap_atomic(p, KM_USER0); + } +} + +static inline bool +read_back_fb(struct drm_device *dev, struct io_mapping *fb, + uint32_t off, uint32_t val) +{ + poke_fb(dev, fb, off, val); + return val == peek_fb(dev, fb, off); +} + +static int +nv04_init_compute_mem(struct nvbios *bios) +{ + struct drm_device *dev = bios->dev; + uint32_t patt = 0xdeadbeef; + struct io_mapping *fb; + int i; + + /* Map the framebuffer aperture */ + fb = io_mapping_create_wc(pci_resource_start(dev->pdev, 1), + pci_resource_len(dev->pdev, 1)); + if (!fb) + return -ENOMEM; + + /* Sequencer and refresh off */ + NVWriteVgaSeq(dev, 0, 1, NVReadVgaSeq(dev, 0, 1) | 0x20); + bios_md32(bios, NV04_PFB_DEBUG_0, 0, NV04_PFB_DEBUG_0_REFRESH_OFF); + + bios_md32(bios, NV04_PFB_BOOT_0, ~0, + NV04_PFB_BOOT_0_RAM_AMOUNT_16MB | + NV04_PFB_BOOT_0_RAM_WIDTH_128 | + NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_16MBIT); + + for (i = 0; i < 4; i++) + poke_fb(dev, fb, 4 * i, patt); + + poke_fb(dev, fb, 0x400000, patt + 1); + + if (peek_fb(dev, fb, 0) == patt + 1) { + bios_md32(bios, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_TYPE, + NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_16MBIT); + bios_md32(bios, NV04_PFB_DEBUG_0, + NV04_PFB_DEBUG_0_REFRESH_OFF, 0); + + for (i = 0; i < 4; i++) + poke_fb(dev, fb, 4 * i, patt); + + if ((peek_fb(dev, fb, 0xc) & 0xffff) != (patt & 0xffff)) + bios_md32(bios, NV04_PFB_BOOT_0, + NV04_PFB_BOOT_0_RAM_WIDTH_128 | + NV04_PFB_BOOT_0_RAM_AMOUNT, + NV04_PFB_BOOT_0_RAM_AMOUNT_8MB); + + } else if ((peek_fb(dev, fb, 0xc) & 0xffff0000) != + (patt & 0xffff0000)) { + bios_md32(bios, NV04_PFB_BOOT_0, + NV04_PFB_BOOT_0_RAM_WIDTH_128 | + NV04_PFB_BOOT_0_RAM_AMOUNT, + NV04_PFB_BOOT_0_RAM_AMOUNT_4MB); + + } else if (peek_fb(dev, fb, 0) == patt) { + if (read_back_fb(dev, fb, 0x800000, patt)) + bios_md32(bios, NV04_PFB_BOOT_0, + NV04_PFB_BOOT_0_RAM_AMOUNT, + NV04_PFB_BOOT_0_RAM_AMOUNT_8MB); + else + bios_md32(bios, NV04_PFB_BOOT_0, + NV04_PFB_BOOT_0_RAM_AMOUNT, + NV04_PFB_BOOT_0_RAM_AMOUNT_4MB); + + bios_md32(bios, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_TYPE, + NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_8MBIT); + + } else if (!read_back_fb(dev, fb, 0x800000, patt)) { + bios_md32(bios, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_AMOUNT, + NV04_PFB_BOOT_0_RAM_AMOUNT_8MB); + + } + + /* Refresh on, sequencer on */ + bios_md32(bios, NV04_PFB_DEBUG_0, NV04_PFB_DEBUG_0_REFRESH_OFF, 0); + NVWriteVgaSeq(dev, 0, 1, NVReadVgaSeq(dev, 0, 1) & ~0x20); + + io_mapping_free(fb); + return 0; +} + +static const uint8_t * +nv05_memory_config(struct nvbios *bios) +{ + /* Defaults for BIOSes lacking a memory config table */ + static const uint8_t default_config_tab[][2] = { + { 0x24, 0x00 }, + { 0x28, 0x00 }, + { 0x24, 0x01 }, + { 0x1f, 0x00 }, + { 0x0f, 0x00 }, + { 0x17, 0x00 }, + { 0x06, 0x00 }, + { 0x00, 0x00 } + }; + int i = (bios_rd32(bios, NV_PEXTDEV_BOOT_0) & + NV_PEXTDEV_BOOT_0_RAMCFG) >> 2; + + if (bios->legacy.mem_init_tbl_ptr) + return &bios->data[bios->legacy.mem_init_tbl_ptr + 2 * i]; + else + return default_config_tab[i]; +} + +static int +nv05_init_compute_mem(struct nvbios *bios) +{ + struct drm_device *dev = bios->dev; + const uint8_t *ramcfg = nv05_memory_config(bios); + uint32_t patt = 0xdeadbeef; + struct io_mapping *fb; + int i, v; + + /* Map the framebuffer aperture */ + fb = io_mapping_create_wc(pci_resource_start(dev->pdev, 1), + pci_resource_len(dev->pdev, 1)); + if (!fb) + return -ENOMEM; + + /* Sequencer off */ + NVWriteVgaSeq(dev, 0, 1, NVReadVgaSeq(dev, 0, 1) | 0x20); + + if (bios_rd32(bios, NV04_PFB_BOOT_0) & NV04_PFB_BOOT_0_UMA_ENABLE) + goto out; + + bios_md32(bios, NV04_PFB_DEBUG_0, NV04_PFB_DEBUG_0_REFRESH_OFF, 0); + + /* If present load the hardcoded scrambling table */ + if (bios->legacy.mem_init_tbl_ptr) { + uint32_t *scramble_tab = (uint32_t *)&bios->data[ + bios->legacy.mem_init_tbl_ptr + 0x10]; + + for (i = 0; i < 8; i++) + bios_wr32(bios, NV04_PFB_SCRAMBLE(i), + ROM32(scramble_tab[i])); + } + + /* Set memory type/width/length defaults depending on the straps */ + bios_md32(bios, NV04_PFB_BOOT_0, 0x3f, ramcfg[0]); + + if (ramcfg[1] & 0x80) + bios_md32(bios, NV04_PFB_CFG0, 0, NV04_PFB_CFG0_SCRAMBLE); + + bios_md32(bios, NV04_PFB_CFG1, 0x700001, (ramcfg[1] & 1) << 20); + bios_md32(bios, NV04_PFB_CFG1, 0, 1); + + /* Probe memory bus width */ + for (i = 0; i < 4; i++) + poke_fb(dev, fb, 4 * i, patt); + + if (peek_fb(dev, fb, 0xc) != patt) + bios_md32(bios, NV04_PFB_BOOT_0, + NV04_PFB_BOOT_0_RAM_WIDTH_128, 0); + + /* Probe memory length */ + v = bios_rd32(bios, NV04_PFB_BOOT_0) & NV04_PFB_BOOT_0_RAM_AMOUNT; + + if (v == NV04_PFB_BOOT_0_RAM_AMOUNT_32MB && + (!read_back_fb(dev, fb, 0x1000000, ++patt) || + !read_back_fb(dev, fb, 0, ++patt))) + bios_md32(bios, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_AMOUNT, + NV04_PFB_BOOT_0_RAM_AMOUNT_16MB); + + if (v == NV04_PFB_BOOT_0_RAM_AMOUNT_16MB && + !read_back_fb(dev, fb, 0x800000, ++patt)) + bios_md32(bios, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_AMOUNT, + NV04_PFB_BOOT_0_RAM_AMOUNT_8MB); + + if (!read_back_fb(dev, fb, 0x400000, ++patt)) + bios_md32(bios, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_AMOUNT, + NV04_PFB_BOOT_0_RAM_AMOUNT_4MB); + +out: + /* Sequencer on */ + NVWriteVgaSeq(dev, 0, 1, NVReadVgaSeq(dev, 0, 1) & ~0x20); + + io_mapping_free(fb); + return 0; +} + +static int +nv10_init_compute_mem(struct nvbios *bios) +{ + struct drm_device *dev = bios->dev; + struct drm_nouveau_private *dev_priv = bios->dev->dev_private; + const int mem_width[] = { 0x10, 0x00, 0x20 }; + const int mem_width_count = (dev_priv->chipset >= 0x17 ? 3 : 2); + uint32_t patt = 0xdeadbeef; + struct io_mapping *fb; + int i, j, k; + + /* Map the framebuffer aperture */ + fb = io_mapping_create_wc(pci_resource_start(dev->pdev, 1), + pci_resource_len(dev->pdev, 1)); + if (!fb) + return -ENOMEM; + + bios_wr32(bios, NV10_PFB_REFCTRL, NV10_PFB_REFCTRL_VALID_1); + + /* Probe memory bus width */ + for (i = 0; i < mem_width_count; i++) { + bios_md32(bios, NV04_PFB_CFG0, 0x30, mem_width[i]); + + for (j = 0; j < 4; j++) { + for (k = 0; k < 4; k++) + poke_fb(dev, fb, 0x1c, 0); + + poke_fb(dev, fb, 0x1c, patt); + poke_fb(dev, fb, 0x3c, 0); + + if (peek_fb(dev, fb, 0x1c) == patt) + goto mem_width_found; + } + } + +mem_width_found: + patt <<= 1; + + /* Probe amount of installed memory */ + for (i = 0; i < 4; i++) { + int off = bios_rd32(bios, NV04_PFB_FIFO_DATA) - 0x100000; + + poke_fb(dev, fb, off, patt); + poke_fb(dev, fb, 0, 0); + + peek_fb(dev, fb, 0); + peek_fb(dev, fb, 0); + peek_fb(dev, fb, 0); + peek_fb(dev, fb, 0); + + if (peek_fb(dev, fb, off) == patt) + goto amount_found; + } + + /* IC missing - disable the upper half memory space. */ + bios_md32(bios, NV04_PFB_CFG0, 0x1000, 0); + +amount_found: + io_mapping_free(fb); + return 0; +} + +static int +nv20_init_compute_mem(struct nvbios *bios) +{ + struct drm_device *dev = bios->dev; + struct drm_nouveau_private *dev_priv = bios->dev->dev_private; + uint32_t mask = (dev_priv->chipset >= 0x25 ? 0x300 : 0x900); + uint32_t amount, off; + struct io_mapping *fb; + + /* Map the framebuffer aperture */ + fb = io_mapping_create_wc(pci_resource_start(dev->pdev, 1), + pci_resource_len(dev->pdev, 1)); + if (!fb) + return -ENOMEM; + + bios_wr32(bios, NV10_PFB_REFCTRL, NV10_PFB_REFCTRL_VALID_1); + + /* Allow full addressing */ + bios_md32(bios, NV04_PFB_CFG0, 0, mask); + + amount = bios_rd32(bios, NV04_PFB_FIFO_DATA); + for (off = amount; off > 0x2000000; off -= 0x2000000) + poke_fb(dev, fb, off - 4, off); + + amount = bios_rd32(bios, NV04_PFB_FIFO_DATA); + if (amount != peek_fb(dev, fb, amount - 4)) + /* IC missing - disable the upper half memory space. */ + bios_md32(bios, NV04_PFB_CFG0, mask, 0); + + io_mapping_free(fb); + return 0; +} + static int init_compute_mem(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) { @@ -2047,64 +2394,57 @@ init_compute_mem(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) * * offset (8 bit): opcode * - * This opcode is meant to set NV_PFB_CFG0 (0x100200) appropriately so - * that the hardware can correctly calculate how much VRAM it has - * (and subsequently report that value in NV_PFB_CSTATUS (0x10020C)) + * This opcode is meant to set the PFB memory config registers + * appropriately so that we can correctly calculate how much VRAM it + * has (on nv10 and better chipsets the amount of installed VRAM is + * subsequently reported in NV_PFB_CSTATUS (0x10020C)). * - * The implementation of this opcode in general consists of two parts: - * 1) determination of the memory bus width - * 2) determination of how many of the card's RAM pads have ICs attached + * The implementation of this opcode in general consists of several + * parts: * - * 1) is done by a cunning combination of writes to offsets 0x1c and - * 0x3c in the framebuffer, and seeing whether the written values are - * read back correctly. This then affects bits 4-7 of NV_PFB_CFG0 + * 1) Determination of memory type and density. Only necessary for + * really old chipsets, the memory type reported by the strap bits + * (0x101000) is assumed to be accurate on nv05 and newer. * - * 2) is done by a cunning combination of writes to an offset slightly - * less than the maximum memory reported by NV_PFB_CSTATUS, then seeing - * if the test pattern can be read back. This then affects bits 12-15 of - * NV_PFB_CFG0 + * 2) Determination of the memory bus width. Usually done by a cunning + * combination of writes to offsets 0x1c and 0x3c in the fb, and + * seeing whether the written values are read back correctly. * - * In this context a "cunning combination" may include multiple reads - * and writes to varying locations, often alternating the test pattern - * and 0, doubtless to make sure buffers are filled, residual charges - * on tracks are removed etc. + * Only necessary on nv0x-nv1x and nv34, on the other cards we can + * trust the straps. * - * Unfortunately, the "cunning combination"s mentioned above, and the - * changes to the bits in NV_PFB_CFG0 differ with nearly every bios - * trace I have. + * 3) Determination of how many of the card's RAM pads have ICs + * attached, usually done by a cunning combination of writes to an + * offset slightly less than the maximum memory reported by + * NV_PFB_CSTATUS, then seeing if the test pattern can be read back. * - * Therefore, we cheat and assume the value of NV_PFB_CFG0 with which - * we started was correct, and use that instead + * This appears to be a NOP on IGPs and NV4x or newer chipsets, both io + * logs of the VBIOS and kmmio traces of the binary driver POSTing the + * card show nothing being done for this opcode. Why is it still listed + * in the table?! */ /* no iexec->execute check by design */ - /* - * This appears to be a NOP on G8x chipsets, both io logs of the VBIOS - * and kmmio traces of the binary driver POSTing the card show nothing - * being done for this opcode. why is it still listed in the table?! - */ - struct drm_nouveau_private *dev_priv = bios->dev->dev_private; + int ret; - if (dev_priv->card_type >= NV_40) - return 1; - - /* - * On every card I've seen, this step gets done for us earlier in - * the init scripts - uint8_t crdata = bios_idxprt_rd(dev, NV_VIO_SRX, 0x01); - bios_idxprt_wr(dev, NV_VIO_SRX, 0x01, crdata | 0x20); - */ - - /* - * This also has probably been done in the scripts, but an mmio trace of - * s3 resume shows nvidia doing it anyway (unlike the NV_VIO_SRX write) - */ - bios_wr32(bios, NV_PFB_REFCTRL, NV_PFB_REFCTRL_VALID_1); + if (dev_priv->chipset >= 0x40 || + dev_priv->chipset == 0x1a || + dev_priv->chipset == 0x1f) + ret = 0; + else if (dev_priv->chipset >= 0x20 && + dev_priv->chipset != 0x34) + ret = nv20_init_compute_mem(bios); + else if (dev_priv->chipset >= 0x10) + ret = nv10_init_compute_mem(bios); + else if (dev_priv->chipset >= 0x5) + ret = nv05_init_compute_mem(bios); + else + ret = nv04_init_compute_mem(bios); - /* write back the saved configuration value */ - bios_wr32(bios, NV_PFB_CFG0, bios->state.saved_nv_pfb_cfg0); + if (ret) + return ret; return 1; } @@ -2131,7 +2471,8 @@ init_reset(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) /* no iexec->execute check by design */ pci_nv_19 = bios_rd32(bios, NV_PBUS_PCI_NV_19); - bios_wr32(bios, NV_PBUS_PCI_NV_19, 0); + bios_wr32(bios, NV_PBUS_PCI_NV_19, pci_nv_19 & ~0xf00); + bios_wr32(bios, reg, value1); udelay(10); @@ -2167,7 +2508,7 @@ init_configure_mem(struct nvbios *bios, uint16_t offset, uint32_t reg, data; if (bios->major_version > 2) - return -ENODEV; + return 0; bios_idxprt_wr(bios, NV_VIO_SRX, NV_VIO_SR_CLOCK_INDEX, bios_idxprt_rd( bios, NV_VIO_SRX, NV_VIO_SR_CLOCK_INDEX) | 0x20); @@ -2180,14 +2521,14 @@ init_configure_mem(struct nvbios *bios, uint16_t offset, reg = ROM32(bios->data[seqtbloffs += 4])) { switch (reg) { - case NV_PFB_PRE: - data = NV_PFB_PRE_CMD_PRECHARGE; + case NV04_PFB_PRE: + data = NV04_PFB_PRE_CMD_PRECHARGE; break; - case NV_PFB_PAD: - data = NV_PFB_PAD_CKE_NORMAL; + case NV04_PFB_PAD: + data = NV04_PFB_PAD_CKE_NORMAL; break; - case NV_PFB_REF: - data = NV_PFB_REF_CMD_REFRESH; + case NV04_PFB_REF: + data = NV04_PFB_REF_CMD_REFRESH; break; default: data = ROM32(bios->data[meminitdata]); @@ -2222,7 +2563,7 @@ init_configure_clk(struct nvbios *bios, uint16_t offset, int clock; if (bios->major_version > 2) - return -ENODEV; + return 0; clock = ROM16(bios->data[meminitoffs + 4]) * 10; setPLL(bios, NV_PRAMDAC_NVPLL_COEFF, clock); @@ -2255,7 +2596,7 @@ init_configure_preinit(struct nvbios *bios, uint16_t offset, uint8_t cr3c = ((straps << 2) & 0xf0) | (straps & (1 << 6)); if (bios->major_version > 2) - return -ENODEV; + return 0; bios_idxprt_wr(bios, NV_CIO_CRX__COLOR, NV_CIO_CRE_SCRATCH4__INDEX, cr3c); @@ -2389,7 +2730,7 @@ init_ram_condition(struct nvbios *bios, uint16_t offset, * offset + 1 (8 bit): mask * offset + 2 (8 bit): cmpval * - * Test if (NV_PFB_BOOT_0 & "mask") equals "cmpval". + * Test if (NV04_PFB_BOOT_0 & "mask") equals "cmpval". * If condition not met skip subsequent opcodes until condition is * inverted (INIT_NOT), or we hit INIT_RESUME */ @@ -2401,7 +2742,7 @@ init_ram_condition(struct nvbios *bios, uint16_t offset, if (!iexec->execute) return 3; - data = bios_rd32(bios, NV_PFB_BOOT_0) & mask; + data = bios_rd32(bios, NV04_PFB_BOOT_0) & mask; BIOSLOG(bios, "0x%04X: Checking if 0x%08X equals 0x%08X\n", offset, data, cmpval); @@ -2795,12 +3136,13 @@ init_gpio(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) */ struct drm_nouveau_private *dev_priv = bios->dev->dev_private; + struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio; const uint32_t nv50_gpio_ctl[2] = { 0xe100, 0xe28c }; int i; if (dev_priv->card_type != NV_50) { NV_ERROR(bios->dev, "INIT_GPIO on unsupported chipset\n"); - return -ENODEV; + return 1; } if (!iexec->execute) @@ -2815,7 +3157,7 @@ init_gpio(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) BIOSLOG(bios, "0x%04X: set gpio 0x%02x, state %d\n", offset, gpio->tag, gpio->state_default); if (bios->execute) - nv50_gpio_set(bios->dev, gpio->tag, gpio->state_default); + pgpio->set(bios->dev, gpio->tag, gpio->state_default); /* The NVIDIA binary driver doesn't appear to actually do * any of this, my VBIOS does however. @@ -2872,10 +3214,7 @@ init_ram_restrict_zm_reg_group(struct nvbios *bios, uint16_t offset, uint8_t index; int i; - - if (!iexec->execute) - return len; - + /* critical! to know the length of the opcode */; if (!blocklen) { NV_ERROR(bios->dev, "0x%04X: Zero block length - has the M table " @@ -2883,6 +3222,9 @@ init_ram_restrict_zm_reg_group(struct nvbios *bios, uint16_t offset, return -EINVAL; } + if (!iexec->execute) + return len; + strap_ramcfg = (bios_rd32(bios, NV_PEXTDEV_BOOT_0) >> 2) & 0xf; index = bios->data[bios->ram_restrict_tbl_ptr + strap_ramcfg]; @@ -3064,14 +3406,14 @@ init_auxch(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) if (!bios->display.output) { NV_ERROR(dev, "INIT_AUXCH: no active output\n"); - return -EINVAL; + return len; } auxch = init_i2c_device_find(dev, bios->display.output->i2c_index); if (!auxch) { NV_ERROR(dev, "INIT_AUXCH: couldn't get auxch %d\n", bios->display.output->i2c_index); - return -ENODEV; + return len; } if (!iexec->execute) @@ -3084,7 +3426,7 @@ init_auxch(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) ret = nouveau_dp_auxch(auxch, 9, addr, &data, 1); if (ret) { NV_ERROR(dev, "INIT_AUXCH: rd auxch fail %d\n", ret); - return ret; + return len; } data &= bios->data[offset + 0]; @@ -3093,7 +3435,7 @@ init_auxch(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) ret = nouveau_dp_auxch(auxch, 8, addr, &data, 1); if (ret) { NV_ERROR(dev, "INIT_AUXCH: wr auxch fail %d\n", ret); - return ret; + return len; } } @@ -3123,14 +3465,14 @@ init_zm_auxch(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) if (!bios->display.output) { NV_ERROR(dev, "INIT_ZM_AUXCH: no active output\n"); - return -EINVAL; + return len; } auxch = init_i2c_device_find(dev, bios->display.output->i2c_index); if (!auxch) { NV_ERROR(dev, "INIT_ZM_AUXCH: couldn't get auxch %d\n", bios->display.output->i2c_index); - return -ENODEV; + return len; } if (!iexec->execute) @@ -3141,7 +3483,7 @@ init_zm_auxch(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) ret = nouveau_dp_auxch(auxch, 8, addr, &bios->data[offset], 1); if (ret) { NV_ERROR(dev, "INIT_ZM_AUXCH: wr auxch fail %d\n", ret); - return ret; + return len; } } @@ -5151,10 +5493,14 @@ static int parse_bmp_structure(struct drm_device *dev, struct nvbios *bios, unsi bios->legacy.i2c_indices.crt = bios->data[legacy_i2c_offset]; bios->legacy.i2c_indices.tv = bios->data[legacy_i2c_offset + 1]; bios->legacy.i2c_indices.panel = bios->data[legacy_i2c_offset + 2]; - bios->dcb.i2c[0].write = bios->data[legacy_i2c_offset + 4]; - bios->dcb.i2c[0].read = bios->data[legacy_i2c_offset + 5]; - bios->dcb.i2c[1].write = bios->data[legacy_i2c_offset + 6]; - bios->dcb.i2c[1].read = bios->data[legacy_i2c_offset + 7]; + if (bios->data[legacy_i2c_offset + 4]) + bios->dcb.i2c[0].write = bios->data[legacy_i2c_offset + 4]; + if (bios->data[legacy_i2c_offset + 5]) + bios->dcb.i2c[0].read = bios->data[legacy_i2c_offset + 5]; + if (bios->data[legacy_i2c_offset + 6]) + bios->dcb.i2c[1].write = bios->data[legacy_i2c_offset + 6]; + if (bios->data[legacy_i2c_offset + 7]) + bios->dcb.i2c[1].read = bios->data[legacy_i2c_offset + 7]; if (bmplength > 74) { bios->fmaxvco = ROM32(bmp[67]); @@ -5589,9 +5935,12 @@ parse_dcb20_entry(struct drm_device *dev, struct dcb_table *dcb, if (conf & 0x4 || conf & 0x8) entry->lvdsconf.use_power_scripts = true; } else { - mask = ~0x5; + mask = ~0x7; + if (conf & 0x2) + entry->lvdsconf.use_acpi_for_edid = true; if (conf & 0x4) entry->lvdsconf.use_power_scripts = true; + entry->lvdsconf.sor.link = (conf & 0x00000030) >> 4; } if (conf & mask) { /* @@ -5706,13 +6055,6 @@ parse_dcb15_entry(struct drm_device *dev, struct dcb_table *dcb, case OUTPUT_TV: entry->tvconf.has_component_output = false; break; - case 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(!). - */ - fabricate_vga_output(dcb, entry->i2c_index, entry->heads); - break; case OUTPUT_LVDS: if ((conn & 0x00003f00) != 0x10) entry->lvdsconf.use_straps_for_mode = true; @@ -5793,6 +6135,31 @@ void merge_like_dcb_entries(struct drm_device *dev, struct dcb_table *dcb) dcb->entries = newentries; } +static bool +apply_dcb_encoder_quirks(struct drm_device *dev, int idx, u32 *conn, u32 *conf) +{ + /* Dell Precision M6300 + * DCB entry 2: 02025312 00000010 + * DCB entry 3: 02026312 00000020 + * + * Identical, except apparently a different connector on a + * different SOR link. Not a clue how we're supposed to know + * which one is in use if it even shares an i2c line... + * + * Ignore the connector on the second SOR link to prevent + * nasty problems until this is sorted (assuming it's not a + * VBIOS bug). + */ + if ((dev->pdev->device == 0x040d) && + (dev->pdev->subsystem_vendor == 0x1028) && + (dev->pdev->subsystem_device == 0x019b)) { + if (*conn == 0x02026312 && *conf == 0x00000020) + return false; + } + + return true; +} + static int parse_dcb_table(struct drm_device *dev, struct nvbios *bios, bool twoHeads) { @@ -5926,6 +6293,9 @@ parse_dcb_table(struct drm_device *dev, struct nvbios *bios, bool twoHeads) if ((connection & 0x0000000f) == 0x0000000f) continue; + if (!apply_dcb_encoder_quirks(dev, i, &connection, &config)) + continue; + NV_TRACEWARN(dev, "Raw DCB entry %d: %08x %08x\n", dcb->entries, connection, config); @@ -6181,9 +6551,8 @@ nouveau_run_vbios_init(struct drm_device *dev) struct nvbios *bios = &dev_priv->vbios; int i, ret = 0; - NVLockVgaCrtcs(dev, false); - if (nv_two_heads(dev)) - NVSetOwner(dev, bios->state.crtchead); + /* Reset the BIOS head to 0. */ + bios->state.crtchead = 0; if (bios->major_version < 5) /* BMP only */ load_nv17_hw_sequencer_ucode(dev, bios); @@ -6216,8 +6585,6 @@ nouveau_run_vbios_init(struct drm_device *dev) } } - NVLockVgaCrtcs(dev, true); - return ret; } @@ -6238,7 +6605,6 @@ static bool nouveau_bios_posted(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; - bool was_locked; unsigned htotal; if (dev_priv->chipset >= NV_50) { @@ -6248,13 +6614,12 @@ nouveau_bios_posted(struct drm_device *dev) return true; } - was_locked = NVLockVgaCrtcs(dev, false); htotal = NVReadVgaCrtc(dev, 0, 0x06); htotal |= (NVReadVgaCrtc(dev, 0, 0x07) & 0x01) << 8; htotal |= (NVReadVgaCrtc(dev, 0, 0x07) & 0x20) << 4; htotal |= (NVReadVgaCrtc(dev, 0, 0x25) & 0x01) << 10; htotal |= (NVReadVgaCrtc(dev, 0, 0x41) & 0x01) << 11; - NVLockVgaCrtcs(dev, was_locked); + return (htotal != 0); } @@ -6263,8 +6628,6 @@ nouveau_bios_init(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; struct nvbios *bios = &dev_priv->vbios; - uint32_t saved_nv_pextdev_boot_0; - bool was_locked; int ret; if (!NVInitVBIOS(dev)) @@ -6284,40 +6647,27 @@ nouveau_bios_init(struct drm_device *dev) if (!bios->major_version) /* we don't run version 0 bios */ return 0; - /* these will need remembering across a suspend */ - saved_nv_pextdev_boot_0 = bios_rd32(bios, NV_PEXTDEV_BOOT_0); - bios->state.saved_nv_pfb_cfg0 = bios_rd32(bios, NV_PFB_CFG0); - /* init script execution disabled */ bios->execute = false; /* ... unless card isn't POSTed already */ if (!nouveau_bios_posted(dev)) { - NV_INFO(dev, "Adaptor not initialised\n"); - if (dev_priv->card_type < NV_40) { - NV_ERROR(dev, "Unable to POST this chipset\n"); - return -ENODEV; - } - - NV_INFO(dev, "Running VBIOS init tables\n"); + NV_INFO(dev, "Adaptor not initialised, " + "running VBIOS init tables.\n"); bios->execute = true; } - bios_wr32(bios, NV_PEXTDEV_BOOT_0, saved_nv_pextdev_boot_0); - ret = nouveau_run_vbios_init(dev); if (ret) return ret; /* feature_byte on BMP is poor, but init always sets CR4B */ - was_locked = NVLockVgaCrtcs(dev, false); if (bios->major_version < 5) bios->is_mobile = NVReadVgaCrtc(dev, 0, NV_CIO_CRE_4B) & 0x40; /* all BIT systems need p_f_m_t for digital_min_front_porch */ if (bios->is_mobile || bios->major_version >= 5) ret = parse_fp_mode_table(dev, bios); - NVLockVgaCrtcs(dev, was_locked); /* allow subsequent scripts to execute */ bios->execute = true; diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.h b/drivers/gpu/drm/nouveau/nouveau_bios.h index adf4ec2..024458a 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.h +++ b/drivers/gpu/drm/nouveau/nouveau_bios.h @@ -81,6 +81,7 @@ struct dcb_connector_table_entry { enum dcb_connector_type type; uint8_t index2; uint8_t gpio_tag; + void *drm; }; struct dcb_connector_table { @@ -117,6 +118,7 @@ struct dcb_entry { struct { struct sor_conf sor; bool use_straps_for_mode; + bool use_acpi_for_edid; bool use_power_scripts; } lvdsconf; struct { @@ -249,8 +251,6 @@ struct nvbios { struct { int crtchead; - /* these need remembering across suspend */ - uint32_t saved_nv_pfb_cfg0; } state; struct { diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index 6f3c195..3ca8343 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -461,9 +461,9 @@ nouveau_bo_move_accel_cleanup(struct nouveau_channel *chan, return ret; ret = ttm_bo_move_accel_cleanup(&nvbo->bo, fence, NULL, - evict, no_wait_reserve, no_wait_gpu, new_mem); - if (nvbo->channel && nvbo->channel != chan) - ret = nouveau_fence_wait(fence, NULL, false, false); + evict || (nvbo->channel && + nvbo->channel != chan), + no_wait_reserve, no_wait_gpu, new_mem); nouveau_fence_unref((void *)&fence); return ret; } @@ -711,8 +711,7 @@ nouveau_bo_move(struct ttm_buffer_object *bo, bool evict, bool intr, return ret; /* Software copy if the card isn't up and running yet. */ - if (dev_priv->init_state != NOUVEAU_CARD_INIT_DONE || - !dev_priv->channel) { + if (!dev_priv->channel) { ret = ttm_bo_move_memcpy(bo, evict, no_wait_reserve, no_wait_gpu, new_mem); goto out; } @@ -783,7 +782,7 @@ nouveau_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem) break; case TTM_PL_VRAM: mem->bus.offset = mem->mm_node->start << PAGE_SHIFT; - mem->bus.base = drm_get_resource_start(dev, 1); + mem->bus.base = pci_resource_start(dev->pdev, 1); mem->bus.is_iomem = true; break; default: diff --git a/drivers/gpu/drm/nouveau/nouveau_calc.c b/drivers/gpu/drm/nouveau/nouveau_calc.c index 88f9bc0..ca85da7 100644 --- a/drivers/gpu/drm/nouveau/nouveau_calc.c +++ b/drivers/gpu/drm/nouveau/nouveau_calc.c @@ -200,7 +200,7 @@ nv04_update_arb(struct drm_device *dev, int VClk, int bpp, struct nv_sim_state sim_data; int MClk = nouveau_hw_get_clock(dev, MPLL); int NVClk = nouveau_hw_get_clock(dev, NVPLL); - uint32_t cfg1 = nvReadFB(dev, NV_PFB_CFG1); + uint32_t cfg1 = nvReadFB(dev, NV04_PFB_CFG1); sim_data.pclk_khz = VClk; sim_data.mclk_khz = MClk; @@ -218,7 +218,7 @@ nv04_update_arb(struct drm_device *dev, int VClk, int bpp, sim_data.mem_latency = 3; sim_data.mem_page_miss = 10; } else { - sim_data.memory_type = nvReadFB(dev, NV_PFB_CFG0) & 0x1; + sim_data.memory_type = nvReadFB(dev, NV04_PFB_CFG0) & 0x1; sim_data.memory_width = (nvReadEXTDEV(dev, NV_PEXTDEV_BOOT_0) & 0x10) ? 128 : 64; sim_data.mem_latency = cfg1 & 0xf; sim_data.mem_page_miss = ((cfg1 >> 4) & 0xf) + ((cfg1 >> 31) & 0x1); diff --git a/drivers/gpu/drm/nouveau/nouveau_channel.c b/drivers/gpu/drm/nouveau/nouveau_channel.c index 1fc57ef..90fdcda 100644 --- a/drivers/gpu/drm/nouveau/nouveau_channel.c +++ b/drivers/gpu/drm/nouveau/nouveau_channel.c @@ -62,7 +62,8 @@ nouveau_channel_pushbuf_ctxdma_init(struct nouveau_channel *chan) * VRAM. */ ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY, - drm_get_resource_start(dev, 1), + pci_resource_start(dev->pdev, + 1), dev_priv->fb_available_size, NV_DMA_ACCESS_RO, NV_DMA_TARGET_PCI, &pushbuf); @@ -257,9 +258,7 @@ nouveau_channel_free(struct nouveau_channel *chan) nouveau_debugfs_channel_fini(chan); /* Give outstanding push buffers a chance to complete */ - spin_lock_irqsave(&chan->fence.lock, flags); nouveau_fence_update(chan); - spin_unlock_irqrestore(&chan->fence.lock, flags); if (chan->fence.sequence != chan->fence.sequence_ack) { struct nouveau_fence *fence = NULL; @@ -368,8 +367,6 @@ nouveau_ioctl_fifo_alloc(struct drm_device *dev, void *data, struct nouveau_channel *chan; int ret; - NOUVEAU_CHECK_INITIALISED_WITH_RETURN; - if (dev_priv->engine.graph.accel_blocked) return -ENODEV; @@ -418,7 +415,6 @@ nouveau_ioctl_fifo_free(struct drm_device *dev, void *data, struct drm_nouveau_channel_free *cfree = data; struct nouveau_channel *chan; - NOUVEAU_CHECK_INITIALISED_WITH_RETURN; NOUVEAU_GET_USER_CHANNEL_WITH_RETURN(cfree->channel, file_priv, chan); nouveau_channel_free(chan); diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index 149ed22..734e926 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -102,63 +102,15 @@ nouveau_connector_destroy(struct drm_connector *drm_connector) kfree(drm_connector); } -static void -nouveau_connector_ddc_prepare(struct drm_connector *connector, int *flags) -{ - struct drm_nouveau_private *dev_priv = connector->dev->dev_private; - - if (dev_priv->card_type >= NV_50) - return; - - *flags = 0; - if (NVLockVgaCrtcs(dev_priv->dev, false)) - *flags |= 1; - if (nv_heads_tied(dev_priv->dev)) - *flags |= 2; - - if (*flags & 2) - NVSetOwner(dev_priv->dev, 0); /* necessary? */ -} - -static void -nouveau_connector_ddc_finish(struct drm_connector *connector, int flags) -{ - struct drm_nouveau_private *dev_priv = connector->dev->dev_private; - - if (dev_priv->card_type >= NV_50) - return; - - if (flags & 2) - NVSetOwner(dev_priv->dev, 4); - if (flags & 1) - NVLockVgaCrtcs(dev_priv->dev, true); -} - static struct nouveau_i2c_chan * nouveau_connector_ddc_detect(struct drm_connector *connector, struct nouveau_encoder **pnv_encoder) { struct drm_device *dev = connector->dev; - uint8_t out_buf[] = { 0x0, 0x0}, buf[2]; - int ret, flags, i; - - struct i2c_msg msgs[] = { - { - .addr = 0x50, - .flags = 0, - .len = 1, - .buf = out_buf, - }, - { - .addr = 0x50, - .flags = I2C_M_RD, - .len = 1, - .buf = buf, - } - }; + int i; for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { - struct nouveau_i2c_chan *i2c = NULL; + struct nouveau_i2c_chan *i2c; struct nouveau_encoder *nv_encoder; struct drm_mode_object *obj; int id; @@ -171,17 +123,9 @@ nouveau_connector_ddc_detect(struct drm_connector *connector, if (!obj) continue; nv_encoder = nouveau_encoder(obj_to_encoder(obj)); + i2c = nouveau_i2c_find(dev, nv_encoder->dcb->i2c_index); - if (nv_encoder->dcb->i2c_index < 0xf) - i2c = nouveau_i2c_find(dev, nv_encoder->dcb->i2c_index); - if (!i2c) - continue; - - nouveau_connector_ddc_prepare(connector, &flags); - ret = i2c_transfer(&i2c->adapter, msgs, 2); - nouveau_connector_ddc_finish(connector, flags); - - if (ret == 2) { + if (i2c && nouveau_probe_i2c_addr(i2c, 0x50)) { *pnv_encoder = nv_encoder; return i2c; } @@ -234,21 +178,7 @@ nouveau_connector_detect(struct drm_connector *connector) struct nouveau_connector *nv_connector = nouveau_connector(connector); struct nouveau_encoder *nv_encoder = NULL; struct nouveau_i2c_chan *i2c; - int type, flags; - - if (nv_connector->dcb->type == DCB_CONNECTOR_LVDS) - nv_encoder = find_encoder_by_type(connector, OUTPUT_LVDS); - if (nv_encoder && nv_connector->native_mode) { - unsigned status = connector_status_connected; - -#if defined(CONFIG_ACPI_BUTTON) || \ - (defined(CONFIG_ACPI_BUTTON_MODULE) && defined(MODULE)) - if (!nouveau_ignorelid && !acpi_lid_open()) - status = connector_status_unknown; -#endif - nouveau_connector_set_encoder(connector, nv_encoder); - return status; - } + int type; /* Cleanup the previous EDID block. */ if (nv_connector->edid) { @@ -259,9 +189,7 @@ nouveau_connector_detect(struct drm_connector *connector) i2c = nouveau_connector_ddc_detect(connector, &nv_encoder); if (i2c) { - nouveau_connector_ddc_prepare(connector, &flags); nv_connector->edid = drm_get_edid(connector, &i2c->adapter); - nouveau_connector_ddc_finish(connector, flags); drm_mode_connector_update_edid_property(connector, nv_connector->edid); if (!nv_connector->edid) { @@ -321,6 +249,85 @@ detect_analog: return connector_status_disconnected; } +static enum drm_connector_status +nouveau_connector_detect_lvds(struct drm_connector *connector) +{ + struct drm_device *dev = connector->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_connector *nv_connector = nouveau_connector(connector); + struct nouveau_encoder *nv_encoder = NULL; + enum drm_connector_status status = connector_status_disconnected; + + /* Cleanup the previous EDID block. */ + if (nv_connector->edid) { + drm_mode_connector_update_edid_property(connector, NULL); + kfree(nv_connector->edid); + nv_connector->edid = NULL; + } + + nv_encoder = find_encoder_by_type(connector, OUTPUT_LVDS); + if (!nv_encoder) + return connector_status_disconnected; + + /* Try retrieving EDID via DDC */ + if (!dev_priv->vbios.fp_no_ddc) { + status = nouveau_connector_detect(connector); + if (status == connector_status_connected) + goto out; + } + + /* On some laptops (Sony, i'm looking at you) there appears to + * be no direct way of accessing the panel's EDID. The only + * option available to us appears to be to ask ACPI for help.. + * + * It's important this check's before trying straps, one of the + * said manufacturer's laptops are configured in such a way + * the nouveau decides an entry in the VBIOS FP mode table is + * valid - it's not (rh#613284) + */ + if (nv_encoder->dcb->lvdsconf.use_acpi_for_edid) { + if (!nouveau_acpi_edid(dev, connector)) { + status = connector_status_connected; + goto out; + } + } + + /* If no EDID found above, and the VBIOS indicates a hardcoded + * modeline is avalilable for the panel, set it as the panel's + * native mode and exit. + */ + if (nouveau_bios_fp_mode(dev, NULL) && (dev_priv->vbios.fp_no_ddc || + nv_encoder->dcb->lvdsconf.use_straps_for_mode)) { + status = connector_status_connected; + goto out; + } + + /* Still nothing, some VBIOS images have a hardcoded EDID block + * stored for the panel stored in them. + */ + if (!dev_priv->vbios.fp_no_ddc) { + struct edid *edid = + (struct edid *)nouveau_bios_embedded_edid(dev); + if (edid) { + nv_connector->edid = kmalloc(EDID_LENGTH, GFP_KERNEL); + *(nv_connector->edid) = *edid; + status = connector_status_connected; + } + } + +out: +#if defined(CONFIG_ACPI_BUTTON) || \ + (defined(CONFIG_ACPI_BUTTON_MODULE) && defined(MODULE)) + if (status == connector_status_connected && + !nouveau_ignorelid && !acpi_lid_open()) + status = connector_status_unknown; +#endif + + drm_mode_connector_update_edid_property(connector, nv_connector->edid); + nouveau_connector_set_encoder(connector, nv_encoder); + return status; +} + static void nouveau_connector_force(struct drm_connector *connector) { @@ -441,7 +448,8 @@ nouveau_connector_native_mode(struct drm_connector *connector) int high_w = 0, high_h = 0, high_v = 0; list_for_each_entry(mode, &nv_connector->base.probed_modes, head) { - if (helper->mode_valid(connector, mode) != MODE_OK) + if (helper->mode_valid(connector, mode) != MODE_OK || + (mode->flags & DRM_MODE_FLAG_INTERLACE)) continue; /* Use preferred mode if there is one.. */ @@ -534,21 +542,27 @@ static int nouveau_connector_get_modes(struct drm_connector *connector) { struct drm_device *dev = connector->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_connector *nv_connector = nouveau_connector(connector); struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder; int ret = 0; - /* If we're not LVDS, destroy the previous native mode, the attached - * monitor could have changed. + /* destroy the native mode, the attached monitor could have changed. */ - if (nv_connector->dcb->type != DCB_CONNECTOR_LVDS && - nv_connector->native_mode) { + if (nv_connector->native_mode) { drm_mode_destroy(dev, nv_connector->native_mode); nv_connector->native_mode = NULL; } if (nv_connector->edid) ret = drm_add_edid_modes(connector, nv_connector->edid); + else + if (nv_encoder->dcb->type == OUTPUT_LVDS && + (nv_encoder->dcb->lvdsconf.use_straps_for_mode || + dev_priv->vbios.fp_no_ddc) && nouveau_bios_fp_mode(dev, NULL)) { + nv_connector->native_mode = drm_mode_create(dev); + nouveau_bios_fp_mode(dev, nv_connector->native_mode); + } /* Find the native mode if this is a digital panel, if we didn't * find any modes through DDC previously add the native mode to @@ -569,7 +583,8 @@ nouveau_connector_get_modes(struct drm_connector *connector) ret = get_slave_funcs(nv_encoder)-> get_modes(to_drm_encoder(nv_encoder), connector); - if (nv_encoder->dcb->type == OUTPUT_LVDS) + if (nv_connector->dcb->type == DCB_CONNECTOR_LVDS || + nv_connector->dcb->type == DCB_CONNECTOR_eDP) ret += nouveau_connector_scaler_modes_add(connector); return ret; @@ -643,6 +658,44 @@ nouveau_connector_best_encoder(struct drm_connector *connector) return NULL; } +void +nouveau_connector_set_polling(struct drm_connector *connector) +{ + struct drm_device *dev = connector->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct drm_crtc *crtc; + bool spare_crtc = false; + + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) + spare_crtc |= !crtc->enabled; + + connector->polled = 0; + + switch (connector->connector_type) { + case DRM_MODE_CONNECTOR_VGA: + case DRM_MODE_CONNECTOR_TV: + if (dev_priv->card_type >= NV_50 || + (nv_gf4_disp_arch(dev) && spare_crtc)) + connector->polled = DRM_CONNECTOR_POLL_CONNECT; + break; + + case DRM_MODE_CONNECTOR_DVII: + case DRM_MODE_CONNECTOR_DVID: + case DRM_MODE_CONNECTOR_HDMIA: + case DRM_MODE_CONNECTOR_DisplayPort: + case DRM_MODE_CONNECTOR_eDP: + if (dev_priv->card_type >= NV_50) + connector->polled = DRM_CONNECTOR_POLL_HPD; + else if (connector->connector_type == DRM_MODE_CONNECTOR_DVID || + spare_crtc) + connector->polled = DRM_CONNECTOR_POLL_CONNECT; + break; + + default: + break; + } +} + static const struct drm_connector_helper_funcs nouveau_connector_helper_funcs = { .get_modes = nouveau_connector_get_modes, @@ -662,148 +715,74 @@ nouveau_connector_funcs = { .force = nouveau_connector_force }; -static int -nouveau_connector_create_lvds(struct drm_device *dev, - struct drm_connector *connector) -{ - struct nouveau_connector *nv_connector = nouveau_connector(connector); - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_i2c_chan *i2c = NULL; - struct nouveau_encoder *nv_encoder; - struct drm_display_mode native, *mode, *temp; - bool dummy, if_is_24bit = false; - int ret, flags; - - nv_encoder = find_encoder_by_type(connector, OUTPUT_LVDS); - if (!nv_encoder) - return -ENODEV; - - ret = nouveau_bios_parse_lvds_table(dev, 0, &dummy, &if_is_24bit); - if (ret) { - NV_ERROR(dev, "Error parsing LVDS table, disabling LVDS\n"); - return ret; - } - nv_connector->use_dithering = !if_is_24bit; - - /* Firstly try getting EDID over DDC, if allowed and I2C channel - * is available. - */ - if (!dev_priv->vbios.fp_no_ddc && nv_encoder->dcb->i2c_index < 0xf) - i2c = nouveau_i2c_find(dev, nv_encoder->dcb->i2c_index); - - if (i2c) { - nouveau_connector_ddc_prepare(connector, &flags); - nv_connector->edid = drm_get_edid(connector, &i2c->adapter); - nouveau_connector_ddc_finish(connector, flags); - } - - /* If no EDID found above, and the VBIOS indicates a hardcoded - * modeline is avalilable for the panel, set it as the panel's - * native mode and exit. - */ - if (!nv_connector->edid && nouveau_bios_fp_mode(dev, &native) && - (nv_encoder->dcb->lvdsconf.use_straps_for_mode || - dev_priv->vbios.fp_no_ddc)) { - nv_connector->native_mode = drm_mode_duplicate(dev, &native); - goto out; - } - - /* Still nothing, some VBIOS images have a hardcoded EDID block - * stored for the panel stored in them. - */ - if (!nv_connector->edid && !nv_connector->native_mode && - !dev_priv->vbios.fp_no_ddc) { - struct edid *edid = - (struct edid *)nouveau_bios_embedded_edid(dev); - if (edid) { - nv_connector->edid = kmalloc(EDID_LENGTH, GFP_KERNEL); - *(nv_connector->edid) = *edid; - } - } - - if (!nv_connector->edid) - goto out; - - /* We didn't find/use a panel mode from the VBIOS, so parse the EDID - * block and look for the preferred mode there. - */ - ret = drm_add_edid_modes(connector, nv_connector->edid); - if (ret == 0) - goto out; - nv_connector->detected_encoder = nv_encoder; - nv_connector->native_mode = nouveau_connector_native_mode(connector); - list_for_each_entry_safe(mode, temp, &connector->probed_modes, head) - drm_mode_remove(connector, mode); - -out: - if (!nv_connector->native_mode) { - NV_ERROR(dev, "LVDS present in DCB table, but couldn't " - "determine its native mode. Disabling.\n"); - return -ENODEV; - } - - drm_mode_connector_update_edid_property(connector, nv_connector->edid); - return 0; -} +static const struct drm_connector_funcs +nouveau_connector_funcs_lvds = { + .dpms = drm_helper_connector_dpms, + .save = NULL, + .restore = NULL, + .detect = nouveau_connector_detect_lvds, + .destroy = nouveau_connector_destroy, + .fill_modes = drm_helper_probe_single_connector_modes, + .set_property = nouveau_connector_set_property, + .force = nouveau_connector_force +}; -int -nouveau_connector_create(struct drm_device *dev, - struct dcb_connector_table_entry *dcb) +struct drm_connector * +nouveau_connector_create(struct drm_device *dev, int index) { + const struct drm_connector_funcs *funcs = &nouveau_connector_funcs; struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_connector *nv_connector = NULL; + struct dcb_connector_table_entry *dcb = NULL; struct drm_connector *connector; - struct drm_encoder *encoder; - int ret, type; + int type, ret = 0; NV_DEBUG_KMS(dev, "\n"); + if (index >= dev_priv->vbios.dcb.connector.entries) + return ERR_PTR(-EINVAL); + + dcb = &dev_priv->vbios.dcb.connector.entry[index]; + if (dcb->drm) + return dcb->drm; + switch (dcb->type) { - case DCB_CONNECTOR_NONE: - return 0; case DCB_CONNECTOR_VGA: - NV_INFO(dev, "Detected a VGA connector\n"); type = DRM_MODE_CONNECTOR_VGA; break; case DCB_CONNECTOR_TV_0: case DCB_CONNECTOR_TV_1: case DCB_CONNECTOR_TV_3: - NV_INFO(dev, "Detected a TV connector\n"); type = DRM_MODE_CONNECTOR_TV; break; case DCB_CONNECTOR_DVI_I: - NV_INFO(dev, "Detected a DVI-I connector\n"); type = DRM_MODE_CONNECTOR_DVII; break; case DCB_CONNECTOR_DVI_D: - NV_INFO(dev, "Detected a DVI-D connector\n"); type = DRM_MODE_CONNECTOR_DVID; break; case DCB_CONNECTOR_HDMI_0: case DCB_CONNECTOR_HDMI_1: - NV_INFO(dev, "Detected a HDMI connector\n"); type = DRM_MODE_CONNECTOR_HDMIA; break; case DCB_CONNECTOR_LVDS: - NV_INFO(dev, "Detected a LVDS connector\n"); type = DRM_MODE_CONNECTOR_LVDS; + funcs = &nouveau_connector_funcs_lvds; break; case DCB_CONNECTOR_DP: - NV_INFO(dev, "Detected a DisplayPort connector\n"); type = DRM_MODE_CONNECTOR_DisplayPort; break; case DCB_CONNECTOR_eDP: - NV_INFO(dev, "Detected an eDP connector\n"); type = DRM_MODE_CONNECTOR_eDP; break; default: NV_ERROR(dev, "unknown connector type: 0x%02x!!\n", dcb->type); - return -EINVAL; + return ERR_PTR(-EINVAL); } nv_connector = kzalloc(sizeof(*nv_connector), GFP_KERNEL); if (!nv_connector) - return -ENOMEM; + return ERR_PTR(-ENOMEM); nv_connector->dcb = dcb; connector = &nv_connector->base; @@ -811,27 +790,21 @@ nouveau_connector_create(struct drm_device *dev, connector->interlace_allowed = false; connector->doublescan_allowed = false; - drm_connector_init(dev, connector, &nouveau_connector_funcs, type); + drm_connector_init(dev, connector, funcs, type); drm_connector_helper_add(connector, &nouveau_connector_helper_funcs); - /* attach encoders */ - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { - struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); - - if (nv_encoder->dcb->connector != dcb->index) - continue; - - if (get_slave_funcs(nv_encoder)) - get_slave_funcs(nv_encoder)->create_resources(encoder, connector); + /* Check if we need dithering enabled */ + if (dcb->type == DCB_CONNECTOR_LVDS) { + bool dummy, is_24bit = false; - drm_mode_connector_attach_encoder(connector, encoder); - } + ret = nouveau_bios_parse_lvds_table(dev, 0, &dummy, &is_24bit); + if (ret) { + NV_ERROR(dev, "Error parsing LVDS table, disabling " + "LVDS\n"); + goto fail; + } - if (!connector->encoder_ids[0]) { - NV_WARN(dev, " no encoders, ignoring\n"); - drm_connector_cleanup(connector); - kfree(connector); - return 0; + nv_connector->use_dithering = !is_24bit; } /* Init DVI-I specific properties */ @@ -841,12 +814,8 @@ nouveau_connector_create(struct drm_device *dev, drm_connector_attach_property(connector, dev->mode_config.dvi_i_select_subconnector_property, 0); } - if (dcb->type != DCB_CONNECTOR_LVDS) - nv_connector->use_dithering = false; - switch (dcb->type) { case DCB_CONNECTOR_VGA: - connector->polled = DRM_CONNECTOR_POLL_CONNECT; if (dev_priv->card_type >= NV_50) { drm_connector_attach_property(connector, dev->mode_config.scaling_mode_property, @@ -858,17 +827,6 @@ nouveau_connector_create(struct drm_device *dev, case DCB_CONNECTOR_TV_3: nv_connector->scaling_mode = DRM_MODE_SCALE_NONE; break; - case DCB_CONNECTOR_DP: - case DCB_CONNECTOR_eDP: - case DCB_CONNECTOR_HDMI_0: - case DCB_CONNECTOR_HDMI_1: - case DCB_CONNECTOR_DVI_I: - case DCB_CONNECTOR_DVI_D: - if (dev_priv->card_type >= NV_50) - connector->polled = DRM_CONNECTOR_POLL_HPD; - else - connector->polled = DRM_CONNECTOR_POLL_CONNECT; - /* fall-through */ default: nv_connector->scaling_mode = DRM_MODE_SCALE_FULLSCREEN; @@ -882,15 +840,15 @@ nouveau_connector_create(struct drm_device *dev, break; } + nouveau_connector_set_polling(connector); + drm_sysfs_connector_add(connector); + dcb->drm = connector; + return dcb->drm; - if (dcb->type == DCB_CONNECTOR_LVDS) { - ret = nouveau_connector_create_lvds(dev, connector); - if (ret) { - connector->funcs->destroy(connector); - return ret; - } - } +fail: + drm_connector_cleanup(connector); + kfree(connector); + return ERR_PTR(ret); - return 0; } diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.h b/drivers/gpu/drm/nouveau/nouveau_connector.h index 4ef38ab..0d2e668 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.h +++ b/drivers/gpu/drm/nouveau/nouveau_connector.h @@ -49,7 +49,10 @@ static inline struct nouveau_connector *nouveau_connector( return container_of(con, struct nouveau_connector, base); } -int nouveau_connector_create(struct drm_device *, - struct dcb_connector_table_entry *); +struct drm_connector * +nouveau_connector_create(struct drm_device *, int index); + +void +nouveau_connector_set_polling(struct drm_connector *); #endif /* __NOUVEAU_CONNECTOR_H__ */ diff --git a/drivers/gpu/drm/nouveau/nouveau_dma.c b/drivers/gpu/drm/nouveau/nouveau_dma.c index 65c441a..2e3c6ca 100644 --- a/drivers/gpu/drm/nouveau/nouveau_dma.c +++ b/drivers/gpu/drm/nouveau/nouveau_dma.c @@ -92,11 +92,9 @@ nouveau_dma_init(struct nouveau_channel *chan) return ret; /* Map M2MF notifier object - fbcon. */ - if (drm_core_check_feature(dev, DRIVER_MODESET)) { - ret = nouveau_bo_map(chan->notifier_bo); - if (ret) - return ret; - } + ret = nouveau_bo_map(chan->notifier_bo); + if (ret) + return ret; /* Insert NOPS for NOUVEAU_DMA_SKIPS */ ret = RING_SPACE(chan, NOUVEAU_DMA_SKIPS); diff --git a/drivers/gpu/drm/nouveau/nouveau_dp.c b/drivers/gpu/drm/nouveau/nouveau_dp.c index deeb21c..33742b1 100644 --- a/drivers/gpu/drm/nouveau/nouveau_dp.c +++ b/drivers/gpu/drm/nouveau/nouveau_dp.c @@ -23,8 +23,10 @@ */ #include "drmP.h" + #include "nouveau_drv.h" #include "nouveau_i2c.h" +#include "nouveau_connector.h" #include "nouveau_encoder.h" static int @@ -270,13 +272,39 @@ bool nouveau_dp_link_train(struct drm_encoder *encoder) { struct drm_device *dev = encoder->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio; struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); - uint8_t config[4]; - uint8_t status[3]; + struct nouveau_connector *nv_connector; + struct bit_displayport_encoder_table *dpe; + int dpe_headerlen; + uint8_t config[4], status[3]; bool cr_done, cr_max_vs, eq_done; int ret = 0, i, tries, voltage; NV_DEBUG_KMS(dev, "link training!!\n"); + + nv_connector = nouveau_encoder_connector_get(nv_encoder); + if (!nv_connector) + return false; + + dpe = nouveau_bios_dp_table(dev, nv_encoder->dcb, &dpe_headerlen); + if (!dpe) { + NV_ERROR(dev, "SOR-%d: no DP encoder table!\n", nv_encoder->or); + return false; + } + + /* disable hotplug detect, this flips around on some panels during + * link training. + */ + pgpio->irq_enable(dev, nv_connector->dcb->gpio_tag, false); + + if (dpe->script0) { + NV_DEBUG_KMS(dev, "SOR-%d: running DP script 0\n", nv_encoder->or); + nouveau_bios_run_init_table(dev, le16_to_cpu(dpe->script0), + nv_encoder->dcb); + } + train: cr_done = eq_done = false; @@ -403,6 +431,15 @@ stop: } } + if (dpe->script1) { + NV_DEBUG_KMS(dev, "SOR-%d: running DP script 1\n", nv_encoder->or); + nouveau_bios_run_init_table(dev, le16_to_cpu(dpe->script1), + nv_encoder->dcb); + } + + /* re-enable hotplug detect */ + pgpio->irq_enable(dev, nv_connector->dcb->gpio_tag, true); + return eq_done; } diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.c b/drivers/gpu/drm/nouveau/nouveau_drv.c index 2737704..1de5eb5 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.c +++ b/drivers/gpu/drm/nouveau/nouveau_drv.c @@ -35,10 +35,6 @@ #include "drm_pciids.h" -MODULE_PARM_DESC(ctxfw, "Use external firmware blob for grctx init (NV40)"); -int nouveau_ctxfw = 0; -module_param_named(ctxfw, nouveau_ctxfw, int, 0400); - MODULE_PARM_DESC(noagp, "Disable AGP"); int nouveau_noagp; module_param_named(noagp, nouveau_noagp, int, 0400); @@ -56,7 +52,7 @@ int nouveau_vram_pushbuf; module_param_named(vram_pushbuf, nouveau_vram_pushbuf, int, 0400); MODULE_PARM_DESC(vram_notify, "Force DMA notifiers to be in VRAM"); -int nouveau_vram_notify = 1; +int nouveau_vram_notify = 0; module_param_named(vram_notify, nouveau_vram_notify, int, 0400); MODULE_PARM_DESC(duallink, "Allow dual-link TMDS (>=GeForce 8)"); @@ -132,7 +128,7 @@ static struct drm_driver driver; static int __devinit nouveau_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { - return drm_get_dev(pdev, ent, &driver); + return drm_get_pci_dev(pdev, ent, &driver); } static void @@ -155,9 +151,6 @@ nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state) struct drm_crtc *crtc; int ret, i; - if (!drm_core_check_feature(dev, DRIVER_MODESET)) - return -ENODEV; - if (pm_state.event == PM_EVENT_PRETHAW) return 0; @@ -257,9 +250,6 @@ nouveau_pci_resume(struct pci_dev *pdev) struct drm_crtc *crtc; int ret, i; - if (!drm_core_check_feature(dev, DRIVER_MODESET)) - return -ENODEV; - nouveau_fbcon_save_disable_accel(dev); NV_INFO(dev, "We're back, enabling device...\n"); @@ -269,6 +259,13 @@ nouveau_pci_resume(struct pci_dev *pdev) return -1; pci_set_master(dev->pdev); + /* Make sure the AGP controller is in a consistent state */ + if (dev_priv->gart_info.type == NOUVEAU_GART_AGP) + nouveau_mem_reset_agp(dev); + + /* Make the CRTCs accessible */ + engine->display.early_init(dev); + NV_INFO(dev, "POSTing device...\n"); ret = nouveau_run_vbios_init(dev); if (ret) @@ -323,7 +320,6 @@ nouveau_pci_resume(struct pci_dev *pdev) list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); - int ret; ret = nouveau_bo_pin(nv_crtc->cursor.nvbo, TTM_PL_FLAG_VRAM); if (!ret) @@ -332,11 +328,7 @@ nouveau_pci_resume(struct pci_dev *pdev) NV_ERROR(dev, "Could not pin/map cursor.\n"); } - if (dev_priv->card_type < NV_50) { - nv04_display_restore(dev); - NVLockVgaCrtcs(dev, false); - } else - nv50_display_init(dev); + engine->display.init(dev); list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); @@ -371,7 +363,8 @@ nouveau_pci_resume(struct pci_dev *pdev) static struct drm_driver driver = { .driver_features = DRIVER_USE_AGP | DRIVER_PCI_DMA | DRIVER_SG | - DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_GEM, + DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_GEM | + DRIVER_MODESET, .load = nouveau_load, .firstopen = nouveau_firstopen, .lastclose = nouveau_lastclose, @@ -438,16 +431,18 @@ static int __init nouveau_init(void) nouveau_modeset = 1; } - if (nouveau_modeset == 1) { - driver.driver_features |= DRIVER_MODESET; - nouveau_register_dsm_handler(); - } + if (!nouveau_modeset) + return 0; + nouveau_register_dsm_handler(); return drm_init(&driver); } static void __exit nouveau_exit(void) { + if (!nouveau_modeset) + return; + drm_exit(&driver); nouveau_unregister_dsm_handler(); } diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index c697191..e15db15 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -123,14 +123,6 @@ nvbo_kmap_obj_iovirtual(struct nouveau_bo *nvbo) return ioptr; } -struct mem_block { - struct mem_block *next; - struct mem_block *prev; - uint64_t start; - uint64_t size; - struct drm_file *file_priv; /* NULL: free, -1: heap, other: real files */ -}; - enum nouveau_flags { NV_NFORCE = 0x10000000, NV_NFORCE2 = 0x20000000 @@ -149,7 +141,7 @@ struct nouveau_gpuobj { struct list_head list; struct nouveau_channel *im_channel; - struct mem_block *im_pramin; + struct drm_mm_node *im_pramin; struct nouveau_bo *im_backing; uint32_t im_backing_start; uint32_t *im_backing_suspend; @@ -196,7 +188,7 @@ struct nouveau_channel { struct list_head pending; uint32_t sequence; uint32_t sequence_ack; - uint32_t last_sequence_irq; + atomic_t last_sequence_irq; } fence; /* DMA push buffer */ @@ -206,7 +198,7 @@ struct nouveau_channel { /* Notifier memory */ struct nouveau_bo *notifier_bo; - struct mem_block *notifier_heap; + struct drm_mm notifier_heap; /* PFIFO context */ struct nouveau_gpuobj_ref *ramfc; @@ -224,7 +216,7 @@ struct nouveau_channel { /* Objects */ struct nouveau_gpuobj_ref *ramin; /* Private instmem */ - struct mem_block *ramin_heap; /* Private PRAMIN heap */ + struct drm_mm ramin_heap; /* Private PRAMIN heap */ struct nouveau_gpuobj_ref *ramht; /* Hash table */ struct list_head ramht_refs; /* Objects referenced by RAMHT */ @@ -277,8 +269,7 @@ struct nouveau_instmem_engine { void (*clear)(struct drm_device *, struct nouveau_gpuobj *); int (*bind)(struct drm_device *, struct nouveau_gpuobj *); int (*unbind)(struct drm_device *, struct nouveau_gpuobj *); - void (*prepare_access)(struct drm_device *, bool write); - void (*finish_access)(struct drm_device *); + void (*flush)(struct drm_device *); }; struct nouveau_mc_engine { @@ -303,10 +294,11 @@ struct nouveau_fb_engine { }; struct nouveau_fifo_engine { - void *priv; - int channels; + struct nouveau_gpuobj_ref *playlist[2]; + int cur_playlist; + int (*init)(struct drm_device *); void (*takedown)(struct drm_device *); @@ -339,10 +331,11 @@ struct nouveau_pgraph_object_class { struct nouveau_pgraph_engine { struct nouveau_pgraph_object_class *grclass; bool accel_blocked; - void *ctxprog; - void *ctxvals; int grctx_size; + /* NV2x/NV3x context table (0x400780) */ + struct nouveau_gpuobj_ref *ctx_table; + int (*init)(struct drm_device *); void (*takedown)(struct drm_device *); @@ -358,6 +351,24 @@ struct nouveau_pgraph_engine { uint32_t size, uint32_t pitch); }; +struct nouveau_display_engine { + int (*early_init)(struct drm_device *); + void (*late_takedown)(struct drm_device *); + int (*create)(struct drm_device *); + int (*init)(struct drm_device *); + void (*destroy)(struct drm_device *); +}; + +struct nouveau_gpio_engine { + int (*init)(struct drm_device *); + void (*takedown)(struct drm_device *); + + int (*get)(struct drm_device *, enum dcb_gpio_tag); + int (*set)(struct drm_device *, enum dcb_gpio_tag, int state); + + void (*irq_enable)(struct drm_device *, enum dcb_gpio_tag, bool on); +}; + struct nouveau_engine { struct nouveau_instmem_engine instmem; struct nouveau_mc_engine mc; @@ -365,6 +376,8 @@ struct nouveau_engine { struct nouveau_fb_engine fb; struct nouveau_pgraph_engine graph; struct nouveau_fifo_engine fifo; + struct nouveau_display_engine display; + struct nouveau_gpio_engine gpio; }; struct nouveau_pll_vals { @@ -500,11 +513,6 @@ enum nouveau_card_type { struct drm_nouveau_private { struct drm_device *dev; - enum { - NOUVEAU_CARD_INIT_DOWN, - NOUVEAU_CARD_INIT_DONE, - NOUVEAU_CARD_INIT_FAILED - } init_state; /* the card type, takes NV_* as values */ enum nouveau_card_type card_type; @@ -525,7 +533,7 @@ struct drm_nouveau_private { struct list_head vbl_waiting; struct { - struct ttm_global_reference mem_global_ref; + struct drm_global_reference mem_global_ref; struct ttm_bo_global_ref bo_global_ref; struct ttm_bo_device bdev; spinlock_t bo_list_lock; @@ -533,8 +541,6 @@ struct drm_nouveau_private { atomic_t validate_sequence; } ttm; - struct fb_info *fbdev_info; - int fifo_alloc_count; struct nouveau_channel *fifos[NOUVEAU_MAX_CHANNEL_NR]; @@ -595,11 +601,7 @@ struct drm_nouveau_private { struct nouveau_gpuobj *vm_vram_pt[NV50_VM_VRAM_NR]; int vm_vram_pt_nr; - struct mem_block *ramin_heap; - - /* context table pointed to be NV_PGRAPH_CHANNEL_CTX_TABLE (0x400780) */ - uint32_t ctx_table_size; - struct nouveau_gpuobj_ref *ctx_table; + struct drm_mm ramin_heap; struct list_head gpuobj_list; @@ -618,6 +620,11 @@ struct drm_nouveau_private { struct backlight_device *backlight; struct nouveau_channel *evo; + struct { + struct dcb_entry *dcb; + u16 script; + u32 pclk; + } evo_irq; struct { struct dentry *channel_root; @@ -652,14 +659,6 @@ nouveau_bo_ref(struct nouveau_bo *ref, struct nouveau_bo **pnvbo) return 0; } -#define NOUVEAU_CHECK_INITIALISED_WITH_RETURN do { \ - struct drm_nouveau_private *nv = dev->dev_private; \ - if (nv->init_state != NOUVEAU_CARD_INIT_DONE) { \ - NV_ERROR(dev, "called without init\n"); \ - return -EINVAL; \ - } \ -} while (0) - #define NOUVEAU_GET_USER_CHANNEL_WITH_RETURN(id, cl, ch) do { \ struct drm_nouveau_private *nv = dev->dev_private; \ if (!nouveau_channel_owner(dev, (cl), (id))) { \ @@ -682,7 +681,6 @@ extern int nouveau_tv_disable; extern char *nouveau_tv_norm; extern int nouveau_reg_debug; extern char *nouveau_vbios; -extern int nouveau_ctxfw; extern int nouveau_ignorelid; extern int nouveau_nofbaccel; extern int nouveau_noaccel; @@ -707,17 +705,10 @@ extern bool nouveau_wait_for_idle(struct drm_device *); extern int nouveau_card_init(struct drm_device *); /* nouveau_mem.c */ -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 *, int tail); -extern void nouveau_mem_takedown(struct mem_block **heap); -extern void nouveau_mem_free_block(struct mem_block *); extern int nouveau_mem_detect(struct drm_device *dev); -extern void nouveau_mem_release(struct drm_file *, struct mem_block *heap); extern int nouveau_mem_init(struct drm_device *); extern int nouveau_mem_init_agp(struct drm_device *); +extern int nouveau_mem_reset_agp(struct drm_device *); extern void nouveau_mem_close(struct drm_device *); extern struct nouveau_tile_reg *nv10_mem_set_tiling(struct drm_device *dev, uint32_t addr, @@ -857,11 +848,13 @@ void nouveau_register_dsm_handler(void); void nouveau_unregister_dsm_handler(void); int nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len); bool nouveau_acpi_rom_supported(struct pci_dev *pdev); +int nouveau_acpi_edid(struct drm_device *, struct drm_connector *); #else static inline void nouveau_register_dsm_handler(void) {} static inline void nouveau_unregister_dsm_handler(void) {} static inline bool nouveau_acpi_rom_supported(struct pci_dev *pdev) { return false; } static inline int nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len) { return -EINVAL; } +static inline int nouveau_acpi_edid(struct drm_device *dev, struct drm_connector *connector) { return -EINVAL; } #endif /* nouveau_backlight.c */ @@ -924,6 +917,10 @@ extern void nv10_fb_takedown(struct drm_device *); extern void nv10_fb_set_region_tiling(struct drm_device *, int, uint32_t, uint32_t, uint32_t); +/* nv30_fb.c */ +extern int nv30_fb_init(struct drm_device *); +extern void nv30_fb_takedown(struct drm_device *); + /* nv40_fb.c */ extern int nv40_fb_init(struct drm_device *); extern void nv40_fb_takedown(struct drm_device *); @@ -1035,12 +1032,6 @@ extern int nv50_graph_unload_context(struct drm_device *); extern void nv50_graph_context_switch(struct drm_device *); extern int nv50_grctx_init(struct nouveau_grctx *); -/* nouveau_grctx.c */ -extern int nouveau_grctx_prog_load(struct drm_device *); -extern void nouveau_grctx_vals_load(struct drm_device *, - struct nouveau_gpuobj *); -extern void nouveau_grctx_fini(struct drm_device *); - /* nv04_instmem.c */ extern int nv04_instmem_init(struct drm_device *); extern void nv04_instmem_takedown(struct drm_device *); @@ -1051,8 +1042,7 @@ extern int nv04_instmem_populate(struct drm_device *, struct nouveau_gpuobj *, extern void nv04_instmem_clear(struct drm_device *, struct nouveau_gpuobj *); extern int nv04_instmem_bind(struct drm_device *, struct nouveau_gpuobj *); extern int nv04_instmem_unbind(struct drm_device *, struct nouveau_gpuobj *); -extern void nv04_instmem_prepare_access(struct drm_device *, bool write); -extern void nv04_instmem_finish_access(struct drm_device *); +extern void nv04_instmem_flush(struct drm_device *); /* nv50_instmem.c */ extern int nv50_instmem_init(struct drm_device *); @@ -1064,8 +1054,9 @@ extern int nv50_instmem_populate(struct drm_device *, struct nouveau_gpuobj *, extern void nv50_instmem_clear(struct drm_device *, struct nouveau_gpuobj *); extern int nv50_instmem_bind(struct drm_device *, struct nouveau_gpuobj *); extern int nv50_instmem_unbind(struct drm_device *, struct nouveau_gpuobj *); -extern void nv50_instmem_prepare_access(struct drm_device *, bool write); -extern void nv50_instmem_finish_access(struct drm_device *); +extern void nv50_instmem_flush(struct drm_device *); +extern void nv84_instmem_flush(struct drm_device *); +extern void nv50_vm_flush(struct drm_device *, int engine); /* nv04_mc.c */ extern int nv04_mc_init(struct drm_device *); @@ -1088,13 +1079,14 @@ extern long nouveau_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg); /* nv04_dac.c */ -extern int nv04_dac_create(struct drm_device *dev, struct dcb_entry *entry); +extern int nv04_dac_create(struct drm_connector *, struct dcb_entry *); extern uint32_t nv17_dac_sample_load(struct drm_encoder *encoder); extern int nv04_dac_output_offset(struct drm_encoder *encoder); extern void nv04_dac_update_dacclk(struct drm_encoder *encoder, bool enable); +extern bool nv04_dac_in_use(struct drm_encoder *encoder); /* nv04_dfp.c */ -extern int nv04_dfp_create(struct drm_device *dev, struct dcb_entry *entry); +extern int nv04_dfp_create(struct drm_connector *, struct dcb_entry *); extern int nv04_dfp_get_bound_head(struct drm_device *dev, struct dcb_entry *dcbent); extern void nv04_dfp_bind_head(struct drm_device *dev, struct dcb_entry *dcbent, int head, bool dl); @@ -1103,15 +1095,17 @@ extern void nv04_dfp_update_fp_control(struct drm_encoder *encoder, int mode); /* nv04_tv.c */ extern int nv04_tv_identify(struct drm_device *dev, int i2c_index); -extern int nv04_tv_create(struct drm_device *dev, struct dcb_entry *entry); +extern int nv04_tv_create(struct drm_connector *, struct dcb_entry *); /* nv17_tv.c */ -extern int nv17_tv_create(struct drm_device *dev, struct dcb_entry *entry); +extern int nv17_tv_create(struct drm_connector *, struct dcb_entry *); /* nv04_display.c */ +extern int nv04_display_early_init(struct drm_device *); +extern void nv04_display_late_takedown(struct drm_device *); extern int nv04_display_create(struct drm_device *); +extern int nv04_display_init(struct drm_device *); extern void nv04_display_destroy(struct drm_device *); -extern void nv04_display_restore(struct drm_device *); /* nv04_crtc.c */ extern int nv04_crtc_create(struct drm_device *, int index); @@ -1147,7 +1141,6 @@ extern int nouveau_fence_wait(void *obj, void *arg, bool lazy, bool intr); extern int nouveau_fence_flush(void *obj, void *arg); extern void nouveau_fence_unref(void **obj); extern void *nouveau_fence_ref(void *obj); -extern void nouveau_fence_handler(struct drm_device *dev, int channel); /* nouveau_gem.c */ extern int nouveau_gem_new(struct drm_device *, struct nouveau_channel *, @@ -1167,13 +1160,15 @@ extern int nouveau_gem_ioctl_cpu_fini(struct drm_device *, void *, extern int nouveau_gem_ioctl_info(struct drm_device *, void *, struct drm_file *); -/* nv17_gpio.c */ -int nv17_gpio_get(struct drm_device *dev, enum dcb_gpio_tag tag); -int nv17_gpio_set(struct drm_device *dev, enum dcb_gpio_tag tag, int state); +/* nv10_gpio.c */ +int nv10_gpio_get(struct drm_device *dev, enum dcb_gpio_tag tag); +int nv10_gpio_set(struct drm_device *dev, enum dcb_gpio_tag tag, int state); /* nv50_gpio.c */ +int nv50_gpio_init(struct drm_device *dev); int nv50_gpio_get(struct drm_device *dev, enum dcb_gpio_tag tag); int nv50_gpio_set(struct drm_device *dev, enum dcb_gpio_tag tag, int state); +void nv50_gpio_irq_enable(struct drm_device *, enum dcb_gpio_tag, bool on); /* nv50_calc. */ int nv50_calc_pll(struct drm_device *, struct pll_lims *, int clk, @@ -1220,6 +1215,14 @@ static inline void nv_wr32(struct drm_device *dev, unsigned reg, u32 val) iowrite32_native(val, dev_priv->mmio + reg); } +static inline void nv_mask(struct drm_device *dev, u32 reg, u32 mask, u32 val) +{ + u32 tmp = nv_rd32(dev, reg); + tmp &= ~mask; + tmp |= val; + nv_wr32(dev, reg, tmp); +} + static inline u8 nv_rd08(struct drm_device *dev, unsigned reg) { struct drm_nouveau_private *dev_priv = dev->dev_private; diff --git a/drivers/gpu/drm/nouveau/nouveau_encoder.h b/drivers/gpu/drm/nouveau/nouveau_encoder.h index e1df820..a1a0d48 100644 --- a/drivers/gpu/drm/nouveau/nouveau_encoder.h +++ b/drivers/gpu/drm/nouveau/nouveau_encoder.h @@ -38,13 +38,15 @@ struct nouveau_encoder { struct dcb_entry *dcb; int or; + /* different to drm_encoder.crtc, this reflects what's + * actually programmed on the hw, not the proposed crtc */ + struct drm_crtc *crtc; + struct drm_display_mode mode; int last_dpms; struct nv04_output_reg restore; - void (*disconnect)(struct nouveau_encoder *encoder); - union { struct { int mc_unknown; @@ -71,8 +73,8 @@ static inline struct drm_encoder *to_drm_encoder(struct nouveau_encoder *enc) struct nouveau_connector * nouveau_encoder_connector_get(struct nouveau_encoder *encoder); -int nv50_sor_create(struct drm_device *dev, struct dcb_entry *entry); -int nv50_dac_create(struct drm_device *dev, struct dcb_entry *entry); +int nv50_sor_create(struct drm_connector *, struct dcb_entry *); +int nv50_dac_create(struct drm_connector *, struct dcb_entry *); struct bit_displayport_encoder_table { uint32_t match; diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c index 257ea13..2fb2444 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c +++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c @@ -333,7 +333,7 @@ nouveau_fbcon_output_poll_changed(struct drm_device *dev) drm_fb_helper_hotplug_event(&dev_priv->nfbdev->helper); } -int +static int nouveau_fbcon_destroy(struct drm_device *dev, struct nouveau_fbdev *nfbdev) { struct nouveau_framebuffer *nouveau_fb = &nfbdev->nouveau_fb; diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c index faddf53..6b208ff 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fence.c +++ b/drivers/gpu/drm/nouveau/nouveau_fence.c @@ -67,12 +67,13 @@ nouveau_fence_update(struct nouveau_channel *chan) if (USE_REFCNT) sequence = nvchan_rd32(chan, 0x48); else - sequence = chan->fence.last_sequence_irq; + sequence = atomic_read(&chan->fence.last_sequence_irq); if (chan->fence.sequence_ack == sequence) return; chan->fence.sequence_ack = sequence; + spin_lock(&chan->fence.lock); list_for_each_safe(entry, tmp, &chan->fence.pending) { fence = list_entry(entry, struct nouveau_fence, entry); @@ -84,6 +85,7 @@ nouveau_fence_update(struct nouveau_channel *chan) if (sequence == chan->fence.sequence_ack) break; } + spin_unlock(&chan->fence.lock); } int @@ -119,7 +121,6 @@ nouveau_fence_emit(struct nouveau_fence *fence) { struct drm_nouveau_private *dev_priv = fence->channel->dev->dev_private; struct nouveau_channel *chan = fence->channel; - unsigned long flags; int ret; ret = RING_SPACE(chan, 2); @@ -127,9 +128,7 @@ nouveau_fence_emit(struct nouveau_fence *fence) return ret; if (unlikely(chan->fence.sequence == chan->fence.sequence_ack - 1)) { - spin_lock_irqsave(&chan->fence.lock, flags); nouveau_fence_update(chan); - spin_unlock_irqrestore(&chan->fence.lock, flags); BUG_ON(chan->fence.sequence == chan->fence.sequence_ack - 1); @@ -138,9 +137,9 @@ nouveau_fence_emit(struct nouveau_fence *fence) fence->sequence = ++chan->fence.sequence; kref_get(&fence->refcount); - spin_lock_irqsave(&chan->fence.lock, flags); + spin_lock(&chan->fence.lock); list_add_tail(&fence->entry, &chan->fence.pending); - spin_unlock_irqrestore(&chan->fence.lock, flags); + spin_unlock(&chan->fence.lock); BEGIN_RING(chan, NvSubSw, USE_REFCNT ? 0x0050 : 0x0150, 1); OUT_RING(chan, fence->sequence); @@ -173,14 +172,11 @@ nouveau_fence_signalled(void *sync_obj, void *sync_arg) { struct nouveau_fence *fence = nouveau_fence(sync_obj); struct nouveau_channel *chan = fence->channel; - unsigned long flags; if (fence->signalled) return true; - spin_lock_irqsave(&chan->fence.lock, flags); nouveau_fence_update(chan); - spin_unlock_irqrestore(&chan->fence.lock, flags); return fence->signalled; } @@ -190,8 +186,6 @@ nouveau_fence_wait(void *sync_obj, void *sync_arg, bool lazy, bool intr) unsigned long timeout = jiffies + (3 * DRM_HZ); int ret = 0; - __set_current_state(intr ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE); - while (1) { if (nouveau_fence_signalled(sync_obj, sync_arg)) break; @@ -201,6 +195,8 @@ nouveau_fence_wait(void *sync_obj, void *sync_arg, bool lazy, bool intr) break; } + __set_current_state(intr ? TASK_INTERRUPTIBLE + : TASK_UNINTERRUPTIBLE); if (lazy) schedule_timeout(1); @@ -221,27 +217,12 @@ nouveau_fence_flush(void *sync_obj, void *sync_arg) return 0; } -void -nouveau_fence_handler(struct drm_device *dev, int channel) -{ - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_channel *chan = NULL; - - if (channel >= 0 && channel < dev_priv->engine.fifo.channels) - chan = dev_priv->fifos[channel]; - - if (chan) { - spin_lock_irq(&chan->fence.lock); - nouveau_fence_update(chan); - spin_unlock_irq(&chan->fence.lock); - } -} - int nouveau_fence_init(struct nouveau_channel *chan) { INIT_LIST_HEAD(&chan->fence.pending); spin_lock_init(&chan->fence.lock); + atomic_set(&chan->fence.last_sequence_irq, 0); return 0; } diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c index 69c76cf..547f2c2 100644 --- a/drivers/gpu/drm/nouveau/nouveau_gem.c +++ b/drivers/gpu/drm/nouveau/nouveau_gem.c @@ -137,8 +137,6 @@ nouveau_gem_ioctl_new(struct drm_device *dev, void *data, uint32_t flags = 0; int ret = 0; - NOUVEAU_CHECK_INITIALISED_WITH_RETURN; - if (unlikely(dev_priv->ttm.bdev.dev_mapping == NULL)) dev_priv->ttm.bdev.dev_mapping = dev_priv->dev->dev_mapping; @@ -577,10 +575,9 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data, struct drm_nouveau_gem_pushbuf_bo *bo; struct nouveau_channel *chan; struct validate_op op; - struct nouveau_fence *fence = 0; + struct nouveau_fence *fence = NULL; int i, j, ret = 0, do_reloc = 0; - NOUVEAU_CHECK_INITIALISED_WITH_RETURN; NOUVEAU_GET_USER_CHANNEL_WITH_RETURN(req->channel, file_priv, chan); req->vram_available = dev_priv->fb_aper_free; @@ -760,8 +757,6 @@ nouveau_gem_ioctl_cpu_prep(struct drm_device *dev, void *data, bool no_wait = !!(req->flags & NOUVEAU_GEM_CPU_PREP_NOWAIT); int ret = -EINVAL; - NOUVEAU_CHECK_INITIALISED_WITH_RETURN; - gem = drm_gem_object_lookup(dev, file_priv, req->handle); if (!gem) return ret; @@ -800,8 +795,6 @@ nouveau_gem_ioctl_cpu_fini(struct drm_device *dev, void *data, struct nouveau_bo *nvbo; int ret = -EINVAL; - NOUVEAU_CHECK_INITIALISED_WITH_RETURN; - gem = drm_gem_object_lookup(dev, file_priv, req->handle); if (!gem) return ret; @@ -827,8 +820,6 @@ nouveau_gem_ioctl_info(struct drm_device *dev, void *data, struct drm_gem_object *gem; int ret; - NOUVEAU_CHECK_INITIALISED_WITH_RETURN; - gem = drm_gem_object_lookup(dev, file_priv, req->handle); if (!gem) return -EINVAL; diff --git a/drivers/gpu/drm/nouveau/nouveau_grctx.c b/drivers/gpu/drm/nouveau/nouveau_grctx.c deleted file mode 100644 index f731c5f..0000000 --- a/drivers/gpu/drm/nouveau/nouveau_grctx.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Copyright 2009 Red Hat Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: Ben Skeggs - */ - -#include <linux/firmware.h> -#include <linux/slab.h> - -#include "drmP.h" -#include "nouveau_drv.h" - -struct nouveau_ctxprog { - uint32_t signature; - uint8_t version; - uint16_t length; - uint32_t data[]; -} __attribute__ ((packed)); - -struct nouveau_ctxvals { - uint32_t signature; - uint8_t version; - uint32_t length; - struct { - uint32_t offset; - uint32_t value; - } data[]; -} __attribute__ ((packed)); - -int -nouveau_grctx_prog_load(struct drm_device *dev) -{ - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; - const int chipset = dev_priv->chipset; - const struct firmware *fw; - const struct nouveau_ctxprog *cp; - const struct nouveau_ctxvals *cv; - char name[32]; - int ret, i; - - if (pgraph->accel_blocked) - return -ENODEV; - - if (!pgraph->ctxprog) { - sprintf(name, "nouveau/nv%02x.ctxprog", chipset); - ret = request_firmware(&fw, name, &dev->pdev->dev); - if (ret) { - NV_ERROR(dev, "No ctxprog for NV%02x\n", chipset); - return ret; - } - - pgraph->ctxprog = kmemdup(fw->data, fw->size, GFP_KERNEL); - if (!pgraph->ctxprog) { - NV_ERROR(dev, "OOM copying ctxprog\n"); - release_firmware(fw); - return -ENOMEM; - } - - cp = pgraph->ctxprog; - if (le32_to_cpu(cp->signature) != 0x5043564e || - cp->version != 0 || - le16_to_cpu(cp->length) != ((fw->size - 7) / 4)) { - NV_ERROR(dev, "ctxprog invalid\n"); - release_firmware(fw); - nouveau_grctx_fini(dev); - return -EINVAL; - } - release_firmware(fw); - } - - if (!pgraph->ctxvals) { - sprintf(name, "nouveau/nv%02x.ctxvals", chipset); - ret = request_firmware(&fw, name, &dev->pdev->dev); - if (ret) { - NV_ERROR(dev, "No ctxvals for NV%02x\n", chipset); - nouveau_grctx_fini(dev); - return ret; - } - - pgraph->ctxvals = kmemdup(fw->data, fw->size, GFP_KERNEL); - if (!pgraph->ctxvals) { - NV_ERROR(dev, "OOM copying ctxvals\n"); - release_firmware(fw); - nouveau_grctx_fini(dev); - return -ENOMEM; - } - - cv = (void *)pgraph->ctxvals; - if (le32_to_cpu(cv->signature) != 0x5643564e || - cv->version != 0 || - le32_to_cpu(cv->length) != ((fw->size - 9) / 8)) { - NV_ERROR(dev, "ctxvals invalid\n"); - release_firmware(fw); - nouveau_grctx_fini(dev); - return -EINVAL; - } - release_firmware(fw); - } - - cp = pgraph->ctxprog; - - nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_INDEX, 0); - for (i = 0; i < le16_to_cpu(cp->length); i++) - nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_DATA, - le32_to_cpu(cp->data[i])); - - return 0; -} - -void -nouveau_grctx_fini(struct drm_device *dev) -{ - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; - - if (pgraph->ctxprog) { - kfree(pgraph->ctxprog); - pgraph->ctxprog = NULL; - } - - if (pgraph->ctxvals) { - kfree(pgraph->ctxprog); - pgraph->ctxvals = NULL; - } -} - -void -nouveau_grctx_vals_load(struct drm_device *dev, struct nouveau_gpuobj *ctx) -{ - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; - struct nouveau_ctxvals *cv = pgraph->ctxvals; - int i; - - if (!cv) - return; - - for (i = 0; i < le32_to_cpu(cv->length); i++) - nv_wo32(dev, ctx, le32_to_cpu(cv->data[i].offset), - le32_to_cpu(cv->data[i].value)); -} diff --git a/drivers/gpu/drm/nouveau/nouveau_i2c.c b/drivers/gpu/drm/nouveau/nouveau_i2c.c index 316a3c7..cb0cb34 100644 --- a/drivers/gpu/drm/nouveau/nouveau_i2c.c +++ b/drivers/gpu/drm/nouveau/nouveau_i2c.c @@ -278,3 +278,45 @@ nouveau_i2c_find(struct drm_device *dev, int index) return i2c->chan; } +bool +nouveau_probe_i2c_addr(struct nouveau_i2c_chan *i2c, int addr) +{ + uint8_t buf[] = { 0 }; + struct i2c_msg msgs[] = { + { + .addr = addr, + .flags = 0, + .len = 1, + .buf = buf, + }, + { + .addr = addr, + .flags = I2C_M_RD, + .len = 1, + .buf = buf, + } + }; + + return i2c_transfer(&i2c->adapter, msgs, 2) == 2; +} + +int +nouveau_i2c_identify(struct drm_device *dev, const char *what, + struct i2c_board_info *info, int index) +{ + struct nouveau_i2c_chan *i2c = nouveau_i2c_find(dev, index); + int i; + + NV_DEBUG(dev, "Probing %ss on I2C bus: %d\n", what, index); + + for (i = 0; info[i].addr; i++) { + if (nouveau_probe_i2c_addr(i2c, info[i].addr)) { + NV_INFO(dev, "Detected %s: %s\n", what, info[i].type); + return i; + } + } + + NV_DEBUG(dev, "No devices found.\n"); + + return -ENODEV; +} diff --git a/drivers/gpu/drm/nouveau/nouveau_i2c.h b/drivers/gpu/drm/nouveau/nouveau_i2c.h index c8eaf7a..6dd2f87 100644 --- a/drivers/gpu/drm/nouveau/nouveau_i2c.h +++ b/drivers/gpu/drm/nouveau/nouveau_i2c.h @@ -45,6 +45,9 @@ struct nouveau_i2c_chan { int nouveau_i2c_init(struct drm_device *, struct dcb_i2c_entry *, int index); void nouveau_i2c_fini(struct drm_device *, struct dcb_i2c_entry *); struct nouveau_i2c_chan *nouveau_i2c_find(struct drm_device *, int index); +bool nouveau_probe_i2c_addr(struct nouveau_i2c_chan *i2c, int addr); +int nouveau_i2c_identify(struct drm_device *dev, const char *what, + struct i2c_board_info *info, int index); int nouveau_dp_i2c_aux_ch(struct i2c_adapter *, int mode, uint8_t write_byte, uint8_t *read_byte); diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c index c1fd42b..a9f36ab 100644 --- a/drivers/gpu/drm/nouveau/nouveau_mem.c +++ b/drivers/gpu/drm/nouveau/nouveau_mem.c @@ -35,162 +35,6 @@ #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) -{ - /* Maybe cut off the start of an existing block */ - if (start > p->start) { - struct mem_block *newblock = - kmalloc(sizeof(*newblock), GFP_KERNEL); - if (!newblock) - goto out; - newblock->start = start; - newblock->size = p->size - (start - p->start); - newblock->file_priv = NULL; - newblock->next = p->next; - newblock->prev = p; - p->next->prev = newblock; - p->next = newblock; - p->size -= newblock->size; - p = newblock; - } - - /* Maybe cut off the end of an existing block */ - if (size < p->size) { - struct mem_block *newblock = - kmalloc(sizeof(*newblock), GFP_KERNEL); - if (!newblock) - goto out; - newblock->start = start + size; - newblock->size = p->size - size; - newblock->file_priv = NULL; - newblock->next = p->next; - newblock->prev = p; - p->next->prev = newblock; - p->next = newblock; - p->size = size; - } - -out: - /* Our block is in the middle */ - p->file_priv = file_priv; - return p; -} - -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; - - if (!heap) - return NULL; - - if (tail) { - list_for_each_prev(p, heap) { - uint64_t start = ((p->start + p->size) - size) & ~mask; - - if (p->file_priv == NULL && 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 == NULL && - start + size <= p->start + p->size) - return split_block(p, start, size, file_priv); - } - } - - return NULL; -} - -void nouveau_mem_free_block(struct mem_block *p) -{ - p->file_priv = NULL; - - /* Assumes a single contiguous range. Needs a special file_priv in - * 'heap' to stop it being subsumed. - */ - if (p->next->file_priv == NULL) { - struct mem_block *q = p->next; - p->size += q->size; - p->next = q->next; - p->next->prev = p; - kfree(q); - } - - if (p->prev->file_priv == NULL) { - struct mem_block *q = p->prev; - q->size += p->size; - q->next = p->next; - q->next->prev = q; - kfree(p); - } -} - -/* Initialize. How to check for an uninitialized heap? - */ -int nouveau_mem_init_heap(struct mem_block **heap, uint64_t start, - uint64_t size) -{ - struct mem_block *blocks = kmalloc(sizeof(*blocks), GFP_KERNEL); - - if (!blocks) - return -ENOMEM; - - *heap = kmalloc(sizeof(**heap), GFP_KERNEL); - if (!*heap) { - kfree(blocks); - return -ENOMEM; - } - - blocks->start = start; - blocks->size = size; - blocks->file_priv = NULL; - blocks->next = blocks->prev = *heap; - - memset(*heap, 0, sizeof(**heap)); - (*heap)->file_priv = (struct drm_file *) -1; - (*heap)->next = (*heap)->prev = blocks; - return 0; -} - -/* - * Free all blocks associated with the releasing file_priv - */ -void nouveau_mem_release(struct drm_file *file_priv, struct mem_block *heap) -{ - struct mem_block *p; - - if (!heap || !heap->next) - return; - - list_for_each(p, heap) { - if (p->file_priv == file_priv) - p->file_priv = NULL; - } - - /* Assumes a single contiguous range. Needs a special file_priv in - * 'heap' to stop it being subsumed. - */ - list_for_each(p, heap) { - while ((p->file_priv == NULL) && - (p->next->file_priv == NULL) && - (p->next != heap)) { - struct mem_block *q = p->next; - p->size += q->size; - p->next = q->next; - p->next->prev = p; - kfree(q); - } - } -} - /* * NV10-NV40 tiling helpers */ @@ -299,7 +143,6 @@ nv50_mem_vm_bind_linear(struct drm_device *dev, uint64_t virt, uint32_t size, phys |= 0x30; } - dev_priv->engine.instmem.prepare_access(dev, true); while (size) { unsigned offset_h = upper_32_bits(phys); unsigned offset_l = lower_32_bits(phys); @@ -331,36 +174,12 @@ nv50_mem_vm_bind_linear(struct drm_device *dev, uint64_t virt, uint32_t size, } } } - dev_priv->engine.instmem.finish_access(dev); - - nv_wr32(dev, 0x100c80, 0x00050001); - if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) { - NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n"); - NV_ERROR(dev, "0x100c80 = 0x%08x\n", nv_rd32(dev, 0x100c80)); - return -EBUSY; - } - - nv_wr32(dev, 0x100c80, 0x00000001); - if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) { - NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n"); - NV_ERROR(dev, "0x100c80 = 0x%08x\n", nv_rd32(dev, 0x100c80)); - return -EBUSY; - } - - nv_wr32(dev, 0x100c80, 0x00040001); - if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) { - NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n"); - NV_ERROR(dev, "0x100c80 = 0x%08x\n", nv_rd32(dev, 0x100c80)); - return -EBUSY; - } - - nv_wr32(dev, 0x100c80, 0x00060001); - if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) { - NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n"); - NV_ERROR(dev, "0x100c80 = 0x%08x\n", nv_rd32(dev, 0x100c80)); - return -EBUSY; - } + dev_priv->engine.instmem.flush(dev); + nv50_vm_flush(dev, 5); + nv50_vm_flush(dev, 0); + nv50_vm_flush(dev, 4); + nv50_vm_flush(dev, 6); return 0; } @@ -374,7 +193,6 @@ nv50_mem_vm_unbind(struct drm_device *dev, uint64_t virt, uint32_t size) virt -= dev_priv->vm_vram_base; pages = (size >> 16) << 1; - dev_priv->engine.instmem.prepare_access(dev, true); while (pages) { pgt = dev_priv->vm_vram_pt[virt >> 29]; pte = (virt & 0x1ffe0000ULL) >> 15; @@ -388,57 +206,19 @@ nv50_mem_vm_unbind(struct drm_device *dev, uint64_t virt, uint32_t size) while (pte < end) nv_wo32(dev, pgt, pte++, 0); } - dev_priv->engine.instmem.finish_access(dev); - - nv_wr32(dev, 0x100c80, 0x00050001); - if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) { - NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n"); - NV_ERROR(dev, "0x100c80 = 0x%08x\n", nv_rd32(dev, 0x100c80)); - return; - } - - nv_wr32(dev, 0x100c80, 0x00000001); - if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) { - NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n"); - NV_ERROR(dev, "0x100c80 = 0x%08x\n", nv_rd32(dev, 0x100c80)); - return; - } - - nv_wr32(dev, 0x100c80, 0x00040001); - if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) { - NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n"); - NV_ERROR(dev, "0x100c80 = 0x%08x\n", nv_rd32(dev, 0x100c80)); - return; - } + dev_priv->engine.instmem.flush(dev); - nv_wr32(dev, 0x100c80, 0x00060001); - if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) { - NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n"); - NV_ERROR(dev, "0x100c80 = 0x%08x\n", nv_rd32(dev, 0x100c80)); - } + nv50_vm_flush(dev, 5); + nv50_vm_flush(dev, 0); + nv50_vm_flush(dev, 4); + nv50_vm_flush(dev, 6); } /* * Cleanup everything */ -void nouveau_mem_takedown(struct mem_block **heap) -{ - struct mem_block *p; - - if (!*heap) - return; - - for (p = (*heap)->next; p != *heap;) { - struct mem_block *q = p; - p = p->next; - kfree(q); - } - - kfree(*heap); - *heap = NULL; -} - -void nouveau_mem_close(struct drm_device *dev) +void +nouveau_mem_close(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; @@ -449,8 +229,7 @@ void nouveau_mem_close(struct drm_device *dev) nouveau_ttm_global_release(dev_priv); - if (drm_core_has_AGP(dev) && dev->agp && - drm_core_check_feature(dev, DRIVER_MODESET)) { + if (drm_core_has_AGP(dev) && dev->agp) { struct drm_agp_mem *entry, *tempe; /* Remove AGP resources, but leave dev->agp @@ -471,28 +250,29 @@ void nouveau_mem_close(struct drm_device *dev) } if (dev_priv->fb_mtrr) { - drm_mtrr_del(dev_priv->fb_mtrr, drm_get_resource_start(dev, 1), - drm_get_resource_len(dev, 1), DRM_MTRR_WC); - dev_priv->fb_mtrr = 0; + drm_mtrr_del(dev_priv->fb_mtrr, + pci_resource_start(dev->pdev, 1), + pci_resource_len(dev->pdev, 1), DRM_MTRR_WC); + dev_priv->fb_mtrr = -1; } } static uint32_t nouveau_mem_detect_nv04(struct drm_device *dev) { - uint32_t boot0 = nv_rd32(dev, NV03_BOOT_0); + uint32_t boot0 = nv_rd32(dev, NV04_PFB_BOOT_0); if (boot0 & 0x00000100) return (((boot0 >> 12) & 0xf) * 2 + 2) * 1024 * 1024; - switch (boot0 & NV03_BOOT_0_RAM_AMOUNT) { - case NV04_BOOT_0_RAM_AMOUNT_32MB: + switch (boot0 & NV04_PFB_BOOT_0_RAM_AMOUNT) { + case NV04_PFB_BOOT_0_RAM_AMOUNT_32MB: return 32 * 1024 * 1024; - case NV04_BOOT_0_RAM_AMOUNT_16MB: + case NV04_PFB_BOOT_0_RAM_AMOUNT_16MB: return 16 * 1024 * 1024; - case NV04_BOOT_0_RAM_AMOUNT_8MB: + case NV04_PFB_BOOT_0_RAM_AMOUNT_8MB: return 8 * 1024 * 1024; - case NV04_BOOT_0_RAM_AMOUNT_4MB: + case NV04_PFB_BOOT_0_RAM_AMOUNT_4MB: return 4 * 1024 * 1024; } @@ -536,12 +316,18 @@ nouveau_mem_detect(struct drm_device *dev) } else if (dev_priv->flags & (NV_NFORCE | NV_NFORCE2)) { dev_priv->vram_size = nouveau_mem_detect_nforce(dev); + } else + if (dev_priv->card_type < NV_50) { + dev_priv->vram_size = nv_rd32(dev, NV04_PFB_FIFO_DATA); + dev_priv->vram_size &= NV10_PFB_FIFO_DATA_RAM_AMOUNT_MB_MASK; } else { - dev_priv->vram_size = nv_rd32(dev, NV04_FIFO_DATA); - dev_priv->vram_size &= NV10_FIFO_DATA_RAM_AMOUNT_MB_MASK; - if (dev_priv->chipset == 0xaa || dev_priv->chipset == 0xac) + dev_priv->vram_size = nv_rd32(dev, NV04_PFB_FIFO_DATA); + dev_priv->vram_size |= (dev_priv->vram_size & 0xff) << 32; + dev_priv->vram_size &= 0xffffffff00ll; + if (dev_priv->chipset == 0xaa || dev_priv->chipset == 0xac) { dev_priv->vram_sys_base = nv_rd32(dev, 0x100e10); dev_priv->vram_sys_base <<= 12; + } } NV_INFO(dev, "Detected %dMiB VRAM\n", (int)(dev_priv->vram_size >> 20)); @@ -555,18 +341,36 @@ nouveau_mem_detect(struct drm_device *dev) return -ENOMEM; } -#if __OS_HAS_AGP -static void nouveau_mem_reset_agp(struct drm_device *dev) +int +nouveau_mem_reset_agp(struct drm_device *dev) { - uint32_t saved_pci_nv_1, saved_pci_nv_19, pmc_enable; +#if __OS_HAS_AGP + uint32_t saved_pci_nv_1, pmc_enable; + int ret; + + /* First of all, disable fast writes, otherwise if it's + * already enabled in the AGP bridge and we disable the card's + * AGP controller we might be locking ourselves out of it. */ + if (dev->agp->acquired) { + struct drm_agp_info info; + struct drm_agp_mode mode; + + ret = drm_agp_info(dev, &info); + if (ret) + return ret; + + mode.mode = info.mode & ~0x10; + ret = drm_agp_enable(dev, mode); + if (ret) + return ret; + } saved_pci_nv_1 = nv_rd32(dev, NV04_PBUS_PCI_NV_1); - saved_pci_nv_19 = nv_rd32(dev, NV04_PBUS_PCI_NV_19); /* clear busmaster bit */ nv_wr32(dev, NV04_PBUS_PCI_NV_1, saved_pci_nv_1 & ~0x4); - /* clear SBA and AGP bits */ - nv_wr32(dev, NV04_PBUS_PCI_NV_19, saved_pci_nv_19 & 0xfffff0ff); + /* disable AGP */ + nv_wr32(dev, NV04_PBUS_PCI_NV_19, 0); /* power cycle pgraph, if enabled */ pmc_enable = nv_rd32(dev, NV03_PMC_ENABLE); @@ -578,11 +382,12 @@ static void nouveau_mem_reset_agp(struct drm_device *dev) } /* and restore (gives effect of resetting AGP) */ - nv_wr32(dev, NV04_PBUS_PCI_NV_19, saved_pci_nv_19); nv_wr32(dev, NV04_PBUS_PCI_NV_1, saved_pci_nv_1); -} #endif + return 0; +} + int nouveau_mem_init_agp(struct drm_device *dev) { @@ -592,11 +397,6 @@ nouveau_mem_init_agp(struct drm_device *dev) struct drm_agp_mode mode; int ret; - if (nouveau_noagp) - return 0; - - nouveau_mem_reset_agp(dev); - if (!dev->agp->acquired) { ret = drm_agp_acquire(dev); if (ret) { @@ -633,7 +433,7 @@ nouveau_mem_init(struct drm_device *dev) struct ttm_bo_device *bdev = &dev_priv->ttm.bdev; int ret, dma_bits = 32; - dev_priv->fb_phys = drm_get_resource_start(dev, 1); + dev_priv->fb_phys = pci_resource_start(dev->pdev, 1); dev_priv->gart_info.type = NOUVEAU_GART_NONE; if (dev_priv->card_type >= NV_50 && @@ -665,8 +465,9 @@ nouveau_mem_init(struct drm_device *dev) dev_priv->fb_available_size = dev_priv->vram_size; dev_priv->fb_mappable_pages = dev_priv->fb_available_size; - if (dev_priv->fb_mappable_pages > drm_get_resource_len(dev, 1)) - dev_priv->fb_mappable_pages = drm_get_resource_len(dev, 1); + if (dev_priv->fb_mappable_pages > pci_resource_len(dev->pdev, 1)) + dev_priv->fb_mappable_pages = + pci_resource_len(dev->pdev, 1); dev_priv->fb_mappable_pages >>= PAGE_SHIFT; /* remove reserved space at end of vram from available amount */ @@ -692,7 +493,8 @@ nouveau_mem_init(struct drm_device *dev) /* GART */ #if !defined(__powerpc__) && !defined(__ia64__) - if (drm_device_is_agp(dev) && dev->agp) { + if (drm_device_is_agp(dev) && dev->agp && !nouveau_noagp) { + nouveau_mem_reset_agp(dev); ret = nouveau_mem_init_agp(dev); if (ret) NV_ERROR(dev, "Error initialising AGP: %d\n", ret); @@ -718,8 +520,8 @@ nouveau_mem_init(struct drm_device *dev) return ret; } - dev_priv->fb_mtrr = drm_mtrr_add(drm_get_resource_start(dev, 1), - drm_get_resource_len(dev, 1), + dev_priv->fb_mtrr = drm_mtrr_add(pci_resource_start(dev->pdev, 1), + pci_resource_len(dev->pdev, 1), DRM_MTRR_WC); return 0; diff --git a/drivers/gpu/drm/nouveau/nouveau_notifier.c b/drivers/gpu/drm/nouveau/nouveau_notifier.c index 9537f3e..3ec181f 100644 --- a/drivers/gpu/drm/nouveau/nouveau_notifier.c +++ b/drivers/gpu/drm/nouveau/nouveau_notifier.c @@ -55,7 +55,7 @@ nouveau_notifier_init_channel(struct nouveau_channel *chan) if (ret) goto out_err; - ret = nouveau_mem_init_heap(&chan->notifier_heap, 0, ntfy->bo.mem.size); + ret = drm_mm_init(&chan->notifier_heap, 0, ntfy->bo.mem.size); if (ret) goto out_err; @@ -80,7 +80,7 @@ nouveau_notifier_takedown_channel(struct nouveau_channel *chan) nouveau_bo_unpin(chan->notifier_bo); mutex_unlock(&dev->struct_mutex); drm_gem_object_unreference_unlocked(chan->notifier_bo->gem); - nouveau_mem_takedown(&chan->notifier_heap); + drm_mm_takedown(&chan->notifier_heap); } static void @@ -90,7 +90,7 @@ nouveau_notifier_gpuobj_dtor(struct drm_device *dev, NV_DEBUG(dev, "\n"); if (gpuobj->priv) - nouveau_mem_free_block(gpuobj->priv); + drm_mm_put_block(gpuobj->priv); } int @@ -100,18 +100,13 @@ nouveau_notifier_alloc(struct nouveau_channel *chan, uint32_t handle, struct drm_device *dev = chan->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_gpuobj *nobj = NULL; - struct mem_block *mem; + struct drm_mm_node *mem; uint32_t offset; int target, ret; - if (!chan->notifier_heap) { - NV_ERROR(dev, "Channel %d doesn't have a notifier heap!\n", - chan->id); - return -EINVAL; - } - - mem = nouveau_mem_alloc_block(chan->notifier_heap, size, 0, - (struct drm_file *)-2, 0); + mem = drm_mm_search_free(&chan->notifier_heap, size, 0, 0); + if (mem) + mem = drm_mm_get_block(mem, size, 0); if (!mem) { NV_ERROR(dev, "Channel %d notifier block full\n", chan->id); return -ENOMEM; @@ -144,17 +139,17 @@ nouveau_notifier_alloc(struct nouveau_channel *chan, uint32_t handle, mem->size, NV_DMA_ACCESS_RW, target, &nobj); if (ret) { - nouveau_mem_free_block(mem); + drm_mm_put_block(mem); NV_ERROR(dev, "Error creating notifier ctxdma: %d\n", ret); return ret; } - nobj->dtor = nouveau_notifier_gpuobj_dtor; - nobj->priv = mem; + nobj->dtor = nouveau_notifier_gpuobj_dtor; + nobj->priv = mem; ret = nouveau_gpuobj_ref_add(dev, chan, handle, nobj, NULL); if (ret) { nouveau_gpuobj_del(dev, &nobj); - nouveau_mem_free_block(mem); + drm_mm_put_block(mem); NV_ERROR(dev, "Error referencing notifier ctxdma: %d\n", ret); return ret; } @@ -170,7 +165,7 @@ nouveau_notifier_offset(struct nouveau_gpuobj *nobj, uint32_t *poffset) return -EINVAL; if (poffset) { - struct mem_block *mem = nobj->priv; + struct drm_mm_node *mem = nobj->priv; if (*poffset >= mem->size) return false; @@ -189,7 +184,6 @@ nouveau_ioctl_notifier_alloc(struct drm_device *dev, void *data, struct nouveau_channel *chan; int ret; - NOUVEAU_CHECK_INITIALISED_WITH_RETURN; NOUVEAU_GET_USER_CHANNEL_WITH_RETURN(na->channel, file_priv, chan); ret = nouveau_notifier_alloc(chan, na->handle, na->size, &na->offset); diff --git a/drivers/gpu/drm/nouveau/nouveau_object.c b/drivers/gpu/drm/nouveau/nouveau_object.c index e7c100b..b6bcb25 100644 --- a/drivers/gpu/drm/nouveau/nouveau_object.c +++ b/drivers/gpu/drm/nouveau/nouveau_object.c @@ -132,7 +132,6 @@ nouveau_ramht_insert(struct drm_device *dev, struct nouveau_gpuobj_ref *ref) } } - instmem->prepare_access(dev, true); co = ho = nouveau_ramht_hash_handle(dev, chan->id, ref->handle); do { if (!nouveau_ramht_entry_valid(dev, ramht, co)) { @@ -143,7 +142,7 @@ nouveau_ramht_insert(struct drm_device *dev, struct nouveau_gpuobj_ref *ref) nv_wo32(dev, ramht, (co + 4)/4, ctx); list_add_tail(&ref->list, &chan->ramht_refs); - instmem->finish_access(dev); + instmem->flush(dev); return 0; } NV_DEBUG(dev, "collision ch%d 0x%08x: h=0x%08x\n", @@ -153,7 +152,6 @@ nouveau_ramht_insert(struct drm_device *dev, struct nouveau_gpuobj_ref *ref) if (co >= dev_priv->ramht_size) co = 0; } while (co != ho); - instmem->finish_access(dev); NV_ERROR(dev, "RAMHT space exhausted. ch=%d\n", chan->id); return -ENOMEM; @@ -173,7 +171,6 @@ nouveau_ramht_remove(struct drm_device *dev, struct nouveau_gpuobj_ref *ref) return; } - instmem->prepare_access(dev, true); co = ho = nouveau_ramht_hash_handle(dev, chan->id, ref->handle); do { if (nouveau_ramht_entry_valid(dev, ramht, co) && @@ -186,7 +183,7 @@ nouveau_ramht_remove(struct drm_device *dev, struct nouveau_gpuobj_ref *ref) nv_wo32(dev, ramht, (co + 4)/4, 0x00000000); list_del(&ref->list); - instmem->finish_access(dev); + instmem->flush(dev); return; } @@ -195,7 +192,6 @@ nouveau_ramht_remove(struct drm_device *dev, struct nouveau_gpuobj_ref *ref) co = 0; } while (co != ho); list_del(&ref->list); - instmem->finish_access(dev); NV_ERROR(dev, "RAMHT entry not found. ch=%d, handle=0x%08x\n", chan->id, ref->handle); @@ -209,7 +205,7 @@ nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan, struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_engine *engine = &dev_priv->engine; struct nouveau_gpuobj *gpuobj; - struct mem_block *pramin = NULL; + struct drm_mm *pramin = NULL; int ret; NV_DEBUG(dev, "ch%d size=%u align=%d flags=0x%08x\n", @@ -233,25 +229,12 @@ nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan, * available. */ if (chan) { - if (chan->ramin_heap) { - NV_DEBUG(dev, "private heap\n"); - pramin = chan->ramin_heap; - } else - if (dev_priv->card_type < NV_50) { - NV_DEBUG(dev, "global heap fallback\n"); - pramin = dev_priv->ramin_heap; - } + NV_DEBUG(dev, "channel heap\n"); + pramin = &chan->ramin_heap; } else { NV_DEBUG(dev, "global heap\n"); - pramin = dev_priv->ramin_heap; - } - - if (!pramin) { - NV_ERROR(dev, "No PRAMIN heap!\n"); - return -EINVAL; - } + pramin = &dev_priv->ramin_heap; - if (!chan) { ret = engine->instmem.populate(dev, gpuobj, &size); if (ret) { nouveau_gpuobj_del(dev, &gpuobj); @@ -260,9 +243,10 @@ 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, 0); + gpuobj->im_pramin = drm_mm_search_free(pramin, size, align, 0); + if (gpuobj->im_pramin) + gpuobj->im_pramin = drm_mm_get_block(gpuobj->im_pramin, size, align); + if (!gpuobj->im_pramin) { nouveau_gpuobj_del(dev, &gpuobj); return -ENOMEM; @@ -279,10 +263,9 @@ nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan, if (gpuobj->flags & NVOBJ_FLAG_ZERO_ALLOC) { int i; - engine->instmem.prepare_access(dev, true); for (i = 0; i < gpuobj->im_pramin->size; i += 4) nv_wo32(dev, gpuobj, i/4, 0); - engine->instmem.finish_access(dev); + engine->instmem.flush(dev); } *gpuobj_ret = gpuobj; @@ -370,10 +353,9 @@ nouveau_gpuobj_del(struct drm_device *dev, struct nouveau_gpuobj **pgpuobj) } if (gpuobj->im_pramin && (gpuobj->flags & NVOBJ_FLAG_ZERO_FREE)) { - engine->instmem.prepare_access(dev, true); for (i = 0; i < gpuobj->im_pramin->size; i += 4) nv_wo32(dev, gpuobj, i/4, 0); - engine->instmem.finish_access(dev); + engine->instmem.flush(dev); } if (gpuobj->dtor) @@ -386,7 +368,7 @@ nouveau_gpuobj_del(struct drm_device *dev, struct nouveau_gpuobj **pgpuobj) if (gpuobj->flags & NVOBJ_FLAG_FAKE) kfree(gpuobj->im_pramin); else - nouveau_mem_free_block(gpuobj->im_pramin); + drm_mm_put_block(gpuobj->im_pramin); } list_del(&gpuobj->list); @@ -589,7 +571,7 @@ nouveau_gpuobj_new_fake(struct drm_device *dev, uint32_t p_offset, list_add_tail(&gpuobj->list, &dev_priv->gpuobj_list); if (p_offset != ~0) { - gpuobj->im_pramin = kzalloc(sizeof(struct mem_block), + gpuobj->im_pramin = kzalloc(sizeof(struct drm_mm_node), GFP_KERNEL); if (!gpuobj->im_pramin) { nouveau_gpuobj_del(dev, &gpuobj); @@ -605,10 +587,9 @@ nouveau_gpuobj_new_fake(struct drm_device *dev, uint32_t p_offset, } if (gpuobj->flags & NVOBJ_FLAG_ZERO_ALLOC) { - dev_priv->engine.instmem.prepare_access(dev, true); for (i = 0; i < gpuobj->im_pramin->size; i += 4) nv_wo32(dev, gpuobj, i/4, 0); - dev_priv->engine.instmem.finish_access(dev); + dev_priv->engine.instmem.flush(dev); } if (pref) { @@ -696,8 +677,6 @@ nouveau_gpuobj_dma_new(struct nouveau_channel *chan, int class, return ret; } - instmem->prepare_access(dev, true); - if (dev_priv->card_type < NV_50) { uint32_t frame, adjust, pte_flags = 0; @@ -734,7 +713,7 @@ nouveau_gpuobj_dma_new(struct nouveau_channel *chan, int class, nv_wo32(dev, *gpuobj, 5, flags5); } - instmem->finish_access(dev); + instmem->flush(dev); (*gpuobj)->engine = NVOBJ_ENGINE_SW; (*gpuobj)->class = class; @@ -849,7 +828,6 @@ nouveau_gpuobj_gr_new(struct nouveau_channel *chan, int class, return ret; } - dev_priv->engine.instmem.prepare_access(dev, true); if (dev_priv->card_type >= NV_50) { nv_wo32(dev, *gpuobj, 0, class); nv_wo32(dev, *gpuobj, 5, 0x00010000); @@ -874,7 +852,7 @@ nouveau_gpuobj_gr_new(struct nouveau_channel *chan, int class, } } } - dev_priv->engine.instmem.finish_access(dev); + dev_priv->engine.instmem.flush(dev); (*gpuobj)->engine = NVOBJ_ENGINE_GR; (*gpuobj)->class = class; @@ -920,6 +898,7 @@ nouveau_gpuobj_channel_init_pramin(struct nouveau_channel *chan) base = 0; /* PGRAPH context */ + size += dev_priv->engine.graph.grctx_size; if (dev_priv->card_type == NV_50) { /* Various fixed table thingos */ @@ -930,12 +909,8 @@ nouveau_gpuobj_channel_init_pramin(struct nouveau_channel *chan) size += 0x8000; /* RAMFC */ size += 0x1000; - /* PGRAPH context */ - size += 0x70000; } - NV_DEBUG(dev, "ch%d PRAMIN size: 0x%08x bytes, base alloc=0x%08x\n", - chan->id, size, base); ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0, size, 0x1000, 0, &chan->ramin); if (ret) { @@ -944,8 +919,7 @@ nouveau_gpuobj_channel_init_pramin(struct nouveau_channel *chan) } pramin = chan->ramin->gpuobj; - ret = nouveau_mem_init_heap(&chan->ramin_heap, - pramin->im_pramin->start + base, size); + ret = drm_mm_init(&chan->ramin_heap, pramin->im_pramin->start + base, size); if (ret) { NV_ERROR(dev, "Error creating PRAMIN heap: %d\n", ret); nouveau_gpuobj_ref_del(dev, &chan->ramin); @@ -969,15 +943,11 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan, NV_DEBUG(dev, "ch%d vram=0x%08x tt=0x%08x\n", chan->id, vram_h, tt_h); - /* Reserve a block of PRAMIN for the channel - *XXX: maybe on <NV50 too at some point - */ - if (0 || dev_priv->card_type == NV_50) { - ret = nouveau_gpuobj_channel_init_pramin(chan); - if (ret) { - NV_ERROR(dev, "init pramin\n"); - return ret; - } + /* Allocate a chunk of memory for per-channel object storage */ + ret = nouveau_gpuobj_channel_init_pramin(chan); + if (ret) { + NV_ERROR(dev, "init pramin\n"); + return ret; } /* NV50 VM @@ -988,17 +958,13 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan, if (dev_priv->card_type >= NV_50) { uint32_t vm_offset, pde; - instmem->prepare_access(dev, true); - vm_offset = (dev_priv->chipset & 0xf0) == 0x50 ? 0x1400 : 0x200; vm_offset += chan->ramin->gpuobj->im_pramin->start; ret = nouveau_gpuobj_new_fake(dev, vm_offset, ~0, 0x4000, 0, &chan->vm_pd, NULL); - if (ret) { - instmem->finish_access(dev); + if (ret) return ret; - } for (i = 0; i < 0x4000; i += 8) { nv_wo32(dev, chan->vm_pd, (i+0)/4, 0x00000000); nv_wo32(dev, chan->vm_pd, (i+4)/4, 0xdeadcafe); @@ -1008,10 +974,8 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan, ret = nouveau_gpuobj_ref_add(dev, NULL, 0, dev_priv->gart_info.sg_ctxdma, &chan->vm_gart_pt); - if (ret) { - instmem->finish_access(dev); + if (ret) return ret; - } nv_wo32(dev, chan->vm_pd, pde++, chan->vm_gart_pt->instance | 0x03); nv_wo32(dev, chan->vm_pd, pde++, 0x00000000); @@ -1021,17 +985,15 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan, ret = nouveau_gpuobj_ref_add(dev, NULL, 0, dev_priv->vm_vram_pt[i], &chan->vm_vram_pt[i]); - if (ret) { - instmem->finish_access(dev); + if (ret) return ret; - } nv_wo32(dev, chan->vm_pd, pde++, chan->vm_vram_pt[i]->instance | 0x61); nv_wo32(dev, chan->vm_pd, pde++, 0x00000000); } - instmem->finish_access(dev); + instmem->flush(dev); } /* RAMHT */ @@ -1130,8 +1092,8 @@ nouveau_gpuobj_channel_takedown(struct nouveau_channel *chan) for (i = 0; i < dev_priv->vm_vram_pt_nr; i++) nouveau_gpuobj_ref_del(dev, &chan->vm_vram_pt[i]); - if (chan->ramin_heap) - nouveau_mem_takedown(&chan->ramin_heap); + if (chan->ramin_heap.free_stack.next) + drm_mm_takedown(&chan->ramin_heap); if (chan->ramin) nouveau_gpuobj_ref_del(dev, &chan->ramin); @@ -1164,10 +1126,8 @@ nouveau_gpuobj_suspend(struct drm_device *dev) return -ENOMEM; } - dev_priv->engine.instmem.prepare_access(dev, false); for (i = 0; i < gpuobj->im_pramin->size / 4; i++) gpuobj->im_backing_suspend[i] = nv_ro32(dev, gpuobj, i); - dev_priv->engine.instmem.finish_access(dev); } return 0; @@ -1212,10 +1172,9 @@ nouveau_gpuobj_resume(struct drm_device *dev) if (!gpuobj->im_backing_suspend) continue; - dev_priv->engine.instmem.prepare_access(dev, true); for (i = 0; i < gpuobj->im_pramin->size / 4; i++) nv_wo32(dev, gpuobj, i, gpuobj->im_backing_suspend[i]); - dev_priv->engine.instmem.finish_access(dev); + dev_priv->engine.instmem.flush(dev); } nouveau_gpuobj_suspend_cleanup(dev); @@ -1232,7 +1191,6 @@ int nouveau_ioctl_grobj_alloc(struct drm_device *dev, void *data, struct nouveau_channel *chan; int ret; - NOUVEAU_CHECK_INITIALISED_WITH_RETURN; NOUVEAU_GET_USER_CHANNEL_WITH_RETURN(init->channel, file_priv, chan); if (init->handle == ~0) @@ -1283,7 +1241,6 @@ int nouveau_ioctl_gpuobj_free(struct drm_device *dev, void *data, struct nouveau_channel *chan; int ret; - NOUVEAU_CHECK_INITIALISED_WITH_RETURN; NOUVEAU_GET_USER_CHANNEL_WITH_RETURN(objfree->channel, file_priv, chan); ret = nouveau_gpuobj_ref_find(chan, objfree->handle, &ref); diff --git a/drivers/gpu/drm/nouveau/nouveau_reg.h b/drivers/gpu/drm/nouveau/nouveau_reg.h index 6ca80a3..9c1056c 100644 --- a/drivers/gpu/drm/nouveau/nouveau_reg.h +++ b/drivers/gpu/drm/nouveau/nouveau_reg.h @@ -1,19 +1,64 @@ +#define NV04_PFB_BOOT_0 0x00100000 +# define NV04_PFB_BOOT_0_RAM_AMOUNT 0x00000003 +# define NV04_PFB_BOOT_0_RAM_AMOUNT_32MB 0x00000000 +# define NV04_PFB_BOOT_0_RAM_AMOUNT_4MB 0x00000001 +# define NV04_PFB_BOOT_0_RAM_AMOUNT_8MB 0x00000002 +# define NV04_PFB_BOOT_0_RAM_AMOUNT_16MB 0x00000003 +# define NV04_PFB_BOOT_0_RAM_WIDTH_128 0x00000004 +# define NV04_PFB_BOOT_0_RAM_TYPE 0x00000028 +# define NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_8MBIT 0x00000000 +# define NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_16MBIT 0x00000008 +# define NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_16MBIT_4BANK 0x00000010 +# define NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_16MBIT 0x00000018 +# define NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_64MBIT 0x00000020 +# define NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_64MBITX16 0x00000028 +# define NV04_PFB_BOOT_0_UMA_ENABLE 0x00000100 +# define NV04_PFB_BOOT_0_UMA_SIZE 0x0000f000 +#define NV04_PFB_DEBUG_0 0x00100080 +# define NV04_PFB_DEBUG_0_PAGE_MODE 0x00000001 +# define NV04_PFB_DEBUG_0_REFRESH_OFF 0x00000010 +# define NV04_PFB_DEBUG_0_REFRESH_COUNTX64 0x00003f00 +# define NV04_PFB_DEBUG_0_REFRESH_SLOW_CLK 0x00004000 +# define NV04_PFB_DEBUG_0_SAFE_MODE 0x00008000 +# define NV04_PFB_DEBUG_0_ALOM_ENABLE 0x00010000 +# define NV04_PFB_DEBUG_0_CASOE 0x00100000 +# define NV04_PFB_DEBUG_0_CKE_INVERT 0x10000000 +# define NV04_PFB_DEBUG_0_REFINC 0x20000000 +# define NV04_PFB_DEBUG_0_SAVE_POWER_OFF 0x40000000 +#define NV04_PFB_CFG0 0x00100200 +# define NV04_PFB_CFG0_SCRAMBLE 0x20000000 +#define NV04_PFB_CFG1 0x00100204 +#define NV04_PFB_FIFO_DATA 0x0010020c +# define NV10_PFB_FIFO_DATA_RAM_AMOUNT_MB_MASK 0xfff00000 +# define NV10_PFB_FIFO_DATA_RAM_AMOUNT_MB_SHIFT 20 +#define NV10_PFB_REFCTRL 0x00100210 +# define NV10_PFB_REFCTRL_VALID_1 (1 << 31) +#define NV04_PFB_PAD 0x0010021c +# define NV04_PFB_PAD_CKE_NORMAL (1 << 0) +#define NV10_PFB_TILE(i) (0x00100240 + (i*16)) +#define NV10_PFB_TILE__SIZE 8 +#define NV10_PFB_TLIMIT(i) (0x00100244 + (i*16)) +#define NV10_PFB_TSIZE(i) (0x00100248 + (i*16)) +#define NV10_PFB_TSTATUS(i) (0x0010024c + (i*16)) +#define NV04_PFB_REF 0x001002d0 +# define NV04_PFB_REF_CMD_REFRESH (1 << 0) +#define NV04_PFB_PRE 0x001002d4 +# define NV04_PFB_PRE_CMD_PRECHARGE (1 << 0) +#define NV10_PFB_CLOSE_PAGE2 0x0010033c +#define NV04_PFB_SCRAMBLE(i) (0x00100400 + 4 * (i)) +#define NV40_PFB_TILE(i) (0x00100600 + (i*16)) +#define NV40_PFB_TILE__SIZE_0 12 +#define NV40_PFB_TILE__SIZE_1 15 +#define NV40_PFB_TLIMIT(i) (0x00100604 + (i*16)) +#define NV40_PFB_TSIZE(i) (0x00100608 + (i*16)) +#define NV40_PFB_TSTATUS(i) (0x0010060c + (i*16)) +#define NV40_PFB_UNK_800 0x00100800 -#define NV03_BOOT_0 0x00100000 -# define NV03_BOOT_0_RAM_AMOUNT 0x00000003 -# define NV03_BOOT_0_RAM_AMOUNT_8MB 0x00000000 -# define NV03_BOOT_0_RAM_AMOUNT_2MB 0x00000001 -# define NV03_BOOT_0_RAM_AMOUNT_4MB 0x00000002 -# define NV03_BOOT_0_RAM_AMOUNT_8MB_SDRAM 0x00000003 -# define NV04_BOOT_0_RAM_AMOUNT_32MB 0x00000000 -# define NV04_BOOT_0_RAM_AMOUNT_4MB 0x00000001 -# define NV04_BOOT_0_RAM_AMOUNT_8MB 0x00000002 -# define NV04_BOOT_0_RAM_AMOUNT_16MB 0x00000003 - -#define NV04_FIFO_DATA 0x0010020c -# define NV10_FIFO_DATA_RAM_AMOUNT_MB_MASK 0xfff00000 -# define NV10_FIFO_DATA_RAM_AMOUNT_MB_SHIFT 20 +#define NV_PEXTDEV_BOOT_0 0x00101000 +#define NV_PEXTDEV_BOOT_0_RAMCFG 0x0000003c +# define NV_PEXTDEV_BOOT_0_STRAP_FP_IFACE_12BIT (8 << 12) +#define NV_PEXTDEV_BOOT_3 0x0010100c #define NV_RAMIN 0x00700000 @@ -131,23 +176,6 @@ #define NV04_PTIMER_TIME_1 0x00009410 #define NV04_PTIMER_ALARM_0 0x00009420 -#define NV04_PFB_CFG0 0x00100200 -#define NV04_PFB_CFG1 0x00100204 -#define NV40_PFB_020C 0x0010020C -#define NV10_PFB_TILE(i) (0x00100240 + (i*16)) -#define NV10_PFB_TILE__SIZE 8 -#define NV10_PFB_TLIMIT(i) (0x00100244 + (i*16)) -#define NV10_PFB_TSIZE(i) (0x00100248 + (i*16)) -#define NV10_PFB_TSTATUS(i) (0x0010024C + (i*16)) -#define NV10_PFB_CLOSE_PAGE2 0x0010033C -#define NV40_PFB_TILE(i) (0x00100600 + (i*16)) -#define NV40_PFB_TILE__SIZE_0 12 -#define NV40_PFB_TILE__SIZE_1 15 -#define NV40_PFB_TLIMIT(i) (0x00100604 + (i*16)) -#define NV40_PFB_TSIZE(i) (0x00100608 + (i*16)) -#define NV40_PFB_TSTATUS(i) (0x0010060C + (i*16)) -#define NV40_PFB_UNK_800 0x00100800 - #define NV04_PGRAPH_DEBUG_0 0x00400080 #define NV04_PGRAPH_DEBUG_1 0x00400084 #define NV04_PGRAPH_DEBUG_2 0x00400088 @@ -814,6 +842,7 @@ #define NV50_PDISPLAY_SOR_BACKLIGHT_ENABLE 0x80000000 #define NV50_PDISPLAY_SOR_BACKLIGHT_LEVEL 0x00000fff #define NV50_SOR_DP_CTRL(i,l) (0x0061c10c + (i) * 0x800 + (l) * 0x80) +#define NV50_SOR_DP_CTRL_ENABLED 0x00000001 #define NV50_SOR_DP_CTRL_ENHANCED_FRAME_ENABLED 0x00004000 #define NV50_SOR_DP_CTRL_LANE_MASK 0x001f0000 #define NV50_SOR_DP_CTRL_LANE_0_ENABLED 0x00010000 diff --git a/drivers/gpu/drm/nouveau/nouveau_sgdma.c b/drivers/gpu/drm/nouveau/nouveau_sgdma.c index 1d6ee8b..491767f 100644 --- a/drivers/gpu/drm/nouveau/nouveau_sgdma.c +++ b/drivers/gpu/drm/nouveau/nouveau_sgdma.c @@ -97,7 +97,6 @@ nouveau_sgdma_bind(struct ttm_backend *be, struct ttm_mem_reg *mem) NV_DEBUG(dev, "pg=0x%lx\n", mem->mm_node->start); - dev_priv->engine.instmem.prepare_access(nvbe->dev, true); pte = nouveau_sgdma_pte(nvbe->dev, mem->mm_node->start << PAGE_SHIFT); nvbe->pte_start = pte; for (i = 0; i < nvbe->nr_pages; i++) { @@ -116,24 +115,11 @@ nouveau_sgdma_bind(struct ttm_backend *be, struct ttm_mem_reg *mem) dma_offset += NV_CTXDMA_PAGE_SIZE; } } - dev_priv->engine.instmem.finish_access(nvbe->dev); + dev_priv->engine.instmem.flush(nvbe->dev); if (dev_priv->card_type == NV_50) { - nv_wr32(dev, 0x100c80, 0x00050001); - if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) { - NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n"); - NV_ERROR(dev, "0x100c80 = 0x%08x\n", - nv_rd32(dev, 0x100c80)); - return -EBUSY; - } - - nv_wr32(dev, 0x100c80, 0x00000001); - if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) { - NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n"); - NV_ERROR(dev, "0x100c80 = 0x%08x\n", - nv_rd32(dev, 0x100c80)); - return -EBUSY; - } + nv50_vm_flush(dev, 5); /* PGRAPH */ + nv50_vm_flush(dev, 0); /* PFIFO */ } nvbe->bound = true; @@ -154,7 +140,6 @@ nouveau_sgdma_unbind(struct ttm_backend *be) if (!nvbe->bound) return 0; - dev_priv->engine.instmem.prepare_access(nvbe->dev, true); pte = nvbe->pte_start; for (i = 0; i < nvbe->nr_pages; i++) { dma_addr_t dma_offset = dev_priv->gart_info.sg_dummy_bus; @@ -170,24 +155,11 @@ nouveau_sgdma_unbind(struct ttm_backend *be) dma_offset += NV_CTXDMA_PAGE_SIZE; } } - dev_priv->engine.instmem.finish_access(nvbe->dev); + dev_priv->engine.instmem.flush(nvbe->dev); if (dev_priv->card_type == NV_50) { - nv_wr32(dev, 0x100c80, 0x00050001); - if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) { - NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n"); - NV_ERROR(dev, "0x100c80 = 0x%08x\n", - nv_rd32(dev, 0x100c80)); - return -EBUSY; - } - - nv_wr32(dev, 0x100c80, 0x00000001); - if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) { - NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n"); - NV_ERROR(dev, "0x100c80 = 0x%08x\n", - nv_rd32(dev, 0x100c80)); - return -EBUSY; - } + nv50_vm_flush(dev, 5); + nv50_vm_flush(dev, 0); } nvbe->bound = false; @@ -272,7 +244,6 @@ nouveau_sgdma_init(struct drm_device *dev) pci_map_page(dev->pdev, dev_priv->gart_info.sg_dummy_page, 0, PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); - dev_priv->engine.instmem.prepare_access(dev, true); if (dev_priv->card_type < NV_50) { /* Maybe use NV_DMA_TARGET_AGP for PCIE? NVIDIA do this, and * confirmed to work on c51. Perhaps means NV_DMA_TARGET_PCIE @@ -294,7 +265,7 @@ nouveau_sgdma_init(struct drm_device *dev) nv_wo32(dev, gpuobj, (i+4)/4, 0); } } - dev_priv->engine.instmem.finish_access(dev); + dev_priv->engine.instmem.flush(dev); dev_priv->gart_info.type = NOUVEAU_GART_SGDMA; dev_priv->gart_info.aper_base = 0; @@ -325,14 +296,11 @@ nouveau_sgdma_get_page(struct drm_device *dev, uint32_t offset, uint32_t *page) { struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_gpuobj *gpuobj = dev_priv->gart_info.sg_ctxdma; - struct nouveau_instmem_engine *instmem = &dev_priv->engine.instmem; int pte; pte = (offset >> NV_CTXDMA_PAGE_SHIFT); if (dev_priv->card_type < NV_50) { - instmem->prepare_access(dev, false); *page = nv_ro32(dev, gpuobj, (pte + 2)) & ~NV_CTXDMA_PAGE_MASK; - instmem->finish_access(dev); return 0; } diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index b02a231..ee3729e 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c @@ -38,6 +38,7 @@ #include "nv50_display.h" static void nouveau_stub_takedown(struct drm_device *dev) {} +static int nouveau_stub_init(struct drm_device *dev) { return 0; } static int nouveau_init_engine_ptrs(struct drm_device *dev) { @@ -54,8 +55,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->instmem.clear = nv04_instmem_clear; engine->instmem.bind = nv04_instmem_bind; engine->instmem.unbind = nv04_instmem_unbind; - engine->instmem.prepare_access = nv04_instmem_prepare_access; - engine->instmem.finish_access = nv04_instmem_finish_access; + engine->instmem.flush = nv04_instmem_flush; engine->mc.init = nv04_mc_init; engine->mc.takedown = nv04_mc_takedown; engine->timer.init = nv04_timer_init; @@ -85,6 +85,16 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->fifo.destroy_context = nv04_fifo_destroy_context; engine->fifo.load_context = nv04_fifo_load_context; engine->fifo.unload_context = nv04_fifo_unload_context; + engine->display.early_init = nv04_display_early_init; + engine->display.late_takedown = nv04_display_late_takedown; + engine->display.create = nv04_display_create; + engine->display.init = nv04_display_init; + engine->display.destroy = nv04_display_destroy; + engine->gpio.init = nouveau_stub_init; + engine->gpio.takedown = nouveau_stub_takedown; + engine->gpio.get = NULL; + engine->gpio.set = NULL; + engine->gpio.irq_enable = NULL; break; case 0x10: engine->instmem.init = nv04_instmem_init; @@ -95,8 +105,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->instmem.clear = nv04_instmem_clear; engine->instmem.bind = nv04_instmem_bind; engine->instmem.unbind = nv04_instmem_unbind; - engine->instmem.prepare_access = nv04_instmem_prepare_access; - engine->instmem.finish_access = nv04_instmem_finish_access; + engine->instmem.flush = nv04_instmem_flush; engine->mc.init = nv04_mc_init; engine->mc.takedown = nv04_mc_takedown; engine->timer.init = nv04_timer_init; @@ -128,6 +137,16 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->fifo.destroy_context = nv10_fifo_destroy_context; engine->fifo.load_context = nv10_fifo_load_context; engine->fifo.unload_context = nv10_fifo_unload_context; + engine->display.early_init = nv04_display_early_init; + engine->display.late_takedown = nv04_display_late_takedown; + engine->display.create = nv04_display_create; + engine->display.init = nv04_display_init; + engine->display.destroy = nv04_display_destroy; + engine->gpio.init = nouveau_stub_init; + engine->gpio.takedown = nouveau_stub_takedown; + engine->gpio.get = nv10_gpio_get; + engine->gpio.set = nv10_gpio_set; + engine->gpio.irq_enable = NULL; break; case 0x20: engine->instmem.init = nv04_instmem_init; @@ -138,8 +157,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->instmem.clear = nv04_instmem_clear; engine->instmem.bind = nv04_instmem_bind; engine->instmem.unbind = nv04_instmem_unbind; - engine->instmem.prepare_access = nv04_instmem_prepare_access; - engine->instmem.finish_access = nv04_instmem_finish_access; + engine->instmem.flush = nv04_instmem_flush; engine->mc.init = nv04_mc_init; engine->mc.takedown = nv04_mc_takedown; engine->timer.init = nv04_timer_init; @@ -171,6 +189,16 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->fifo.destroy_context = nv10_fifo_destroy_context; engine->fifo.load_context = nv10_fifo_load_context; engine->fifo.unload_context = nv10_fifo_unload_context; + engine->display.early_init = nv04_display_early_init; + engine->display.late_takedown = nv04_display_late_takedown; + engine->display.create = nv04_display_create; + engine->display.init = nv04_display_init; + engine->display.destroy = nv04_display_destroy; + engine->gpio.init = nouveau_stub_init; + engine->gpio.takedown = nouveau_stub_takedown; + engine->gpio.get = nv10_gpio_get; + engine->gpio.set = nv10_gpio_set; + engine->gpio.irq_enable = NULL; break; case 0x30: engine->instmem.init = nv04_instmem_init; @@ -181,15 +209,14 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->instmem.clear = nv04_instmem_clear; engine->instmem.bind = nv04_instmem_bind; engine->instmem.unbind = nv04_instmem_unbind; - engine->instmem.prepare_access = nv04_instmem_prepare_access; - engine->instmem.finish_access = nv04_instmem_finish_access; + engine->instmem.flush = nv04_instmem_flush; engine->mc.init = nv04_mc_init; engine->mc.takedown = nv04_mc_takedown; engine->timer.init = nv04_timer_init; engine->timer.read = nv04_timer_read; engine->timer.takedown = nv04_timer_takedown; - engine->fb.init = nv10_fb_init; - engine->fb.takedown = nv10_fb_takedown; + engine->fb.init = nv30_fb_init; + engine->fb.takedown = nv30_fb_takedown; engine->fb.set_region_tiling = nv10_fb_set_region_tiling; engine->graph.grclass = nv30_graph_grclass; engine->graph.init = nv30_graph_init; @@ -214,6 +241,16 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->fifo.destroy_context = nv10_fifo_destroy_context; engine->fifo.load_context = nv10_fifo_load_context; engine->fifo.unload_context = nv10_fifo_unload_context; + engine->display.early_init = nv04_display_early_init; + engine->display.late_takedown = nv04_display_late_takedown; + engine->display.create = nv04_display_create; + engine->display.init = nv04_display_init; + engine->display.destroy = nv04_display_destroy; + engine->gpio.init = nouveau_stub_init; + engine->gpio.takedown = nouveau_stub_takedown; + engine->gpio.get = nv10_gpio_get; + engine->gpio.set = nv10_gpio_set; + engine->gpio.irq_enable = NULL; break; case 0x40: case 0x60: @@ -225,8 +262,7 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->instmem.clear = nv04_instmem_clear; engine->instmem.bind = nv04_instmem_bind; engine->instmem.unbind = nv04_instmem_unbind; - engine->instmem.prepare_access = nv04_instmem_prepare_access; - engine->instmem.finish_access = nv04_instmem_finish_access; + engine->instmem.flush = nv04_instmem_flush; engine->mc.init = nv40_mc_init; engine->mc.takedown = nv40_mc_takedown; engine->timer.init = nv04_timer_init; @@ -258,6 +294,16 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->fifo.destroy_context = nv40_fifo_destroy_context; engine->fifo.load_context = nv40_fifo_load_context; engine->fifo.unload_context = nv40_fifo_unload_context; + engine->display.early_init = nv04_display_early_init; + engine->display.late_takedown = nv04_display_late_takedown; + engine->display.create = nv04_display_create; + engine->display.init = nv04_display_init; + engine->display.destroy = nv04_display_destroy; + engine->gpio.init = nouveau_stub_init; + engine->gpio.takedown = nouveau_stub_takedown; + engine->gpio.get = nv10_gpio_get; + engine->gpio.set = nv10_gpio_set; + engine->gpio.irq_enable = NULL; break; case 0x50: case 0x80: /* gotta love NVIDIA's consistency.. */ @@ -271,8 +317,10 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->instmem.clear = nv50_instmem_clear; engine->instmem.bind = nv50_instmem_bind; engine->instmem.unbind = nv50_instmem_unbind; - engine->instmem.prepare_access = nv50_instmem_prepare_access; - engine->instmem.finish_access = nv50_instmem_finish_access; + if (dev_priv->chipset == 0x50) + engine->instmem.flush = nv50_instmem_flush; + else + engine->instmem.flush = nv84_instmem_flush; engine->mc.init = nv50_mc_init; engine->mc.takedown = nv50_mc_takedown; engine->timer.init = nv04_timer_init; @@ -300,6 +348,16 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) engine->fifo.destroy_context = nv50_fifo_destroy_context; engine->fifo.load_context = nv50_fifo_load_context; engine->fifo.unload_context = nv50_fifo_unload_context; + engine->display.early_init = nv50_display_early_init; + engine->display.late_takedown = nv50_display_late_takedown; + engine->display.create = nv50_display_create; + engine->display.init = nv50_display_init; + engine->display.destroy = nv50_display_destroy; + engine->gpio.init = nv50_gpio_init; + engine->gpio.takedown = nouveau_stub_takedown; + engine->gpio.get = nv50_gpio_get; + engine->gpio.set = nv50_gpio_set; + engine->gpio.irq_enable = nv50_gpio_irq_enable; break; default: NV_ERROR(dev, "NV%02x unsupported\n", dev_priv->chipset); @@ -407,11 +465,6 @@ nouveau_card_init(struct drm_device *dev) struct nouveau_engine *engine; int ret; - NV_DEBUG(dev, "prev state = %d\n", dev_priv->init_state); - - if (dev_priv->init_state == NOUVEAU_CARD_INIT_DONE) - return 0; - vga_client_register(dev->pdev, dev, NULL, nouveau_vga_set_decode); vga_switcheroo_register_client(dev->pdev, nouveau_switcheroo_set_state, nouveau_switcheroo_can_switch); @@ -421,15 +474,17 @@ nouveau_card_init(struct drm_device *dev) if (ret) goto out; engine = &dev_priv->engine; - dev_priv->init_state = NOUVEAU_CARD_INIT_FAILED; spin_lock_init(&dev_priv->context_switch_lock); + /* Make the CRTCs and I2C buses accessible */ + ret = engine->display.early_init(dev); + if (ret) + goto out; + /* Parse BIOS tables / Run init tables if card not POSTed */ - if (drm_core_check_feature(dev, DRIVER_MODESET)) { - ret = nouveau_bios_init(dev); - if (ret) - goto out; - } + ret = nouveau_bios_init(dev); + if (ret) + goto out_display_early; ret = nouveau_mem_detect(dev); if (ret) @@ -461,10 +516,15 @@ nouveau_card_init(struct drm_device *dev) if (ret) goto out_gpuobj; + /* PGPIO */ + ret = engine->gpio.init(dev); + if (ret) + goto out_mc; + /* PTIMER */ ret = engine->timer.init(dev); if (ret) - goto out_mc; + goto out_gpio; /* PFB */ ret = engine->fb.init(dev); @@ -485,12 +545,16 @@ nouveau_card_init(struct drm_device *dev) goto out_graph; } + ret = engine->display.create(dev); + if (ret) + goto out_fifo; + /* this call irq_preinstall, register irq handler and * call irq_postinstall */ ret = drm_irq_install(dev); if (ret) - goto out_fifo; + goto out_display; ret = drm_vblank_init(dev, 0); if (ret) @@ -504,35 +568,18 @@ nouveau_card_init(struct drm_device *dev) goto out_irq; } - if (drm_core_check_feature(dev, DRIVER_MODESET)) { - if (dev_priv->card_type >= NV_50) - ret = nv50_display_create(dev); - else - ret = nv04_display_create(dev); - if (ret) - goto out_channel; - } - ret = nouveau_backlight_init(dev); if (ret) NV_ERROR(dev, "Error %d registering backlight\n", ret); - dev_priv->init_state = NOUVEAU_CARD_INIT_DONE; - - if (drm_core_check_feature(dev, DRIVER_MODESET)) { - nouveau_fbcon_init(dev); - drm_kms_helper_poll_init(dev); - } - + nouveau_fbcon_init(dev); + drm_kms_helper_poll_init(dev); return 0; -out_channel: - if (dev_priv->channel) { - nouveau_channel_free(dev_priv->channel); - dev_priv->channel = NULL; - } out_irq: drm_irq_uninstall(dev); +out_display: + engine->display.destroy(dev); out_fifo: if (!nouveau_noaccel) engine->fifo.takedown(dev); @@ -543,6 +590,8 @@ out_fb: engine->fb.takedown(dev); out_timer: engine->timer.takedown(dev); +out_gpio: + engine->gpio.takedown(dev); out_mc: engine->mc.takedown(dev); out_gpuobj: @@ -556,6 +605,8 @@ out_gpuobj_early: nouveau_gpuobj_late_takedown(dev); out_bios: nouveau_bios_takedown(dev); +out_display_early: + engine->display.late_takedown(dev); out: vga_client_register(dev->pdev, NULL, NULL, NULL); return ret; @@ -566,45 +617,39 @@ static void nouveau_card_takedown(struct drm_device *dev) struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_engine *engine = &dev_priv->engine; - NV_DEBUG(dev, "prev state = %d\n", dev_priv->init_state); - - if (dev_priv->init_state != NOUVEAU_CARD_INIT_DOWN) { - - nouveau_backlight_exit(dev); - - if (dev_priv->channel) { - nouveau_channel_free(dev_priv->channel); - dev_priv->channel = NULL; - } + nouveau_backlight_exit(dev); - if (!nouveau_noaccel) { - engine->fifo.takedown(dev); - engine->graph.takedown(dev); - } - engine->fb.takedown(dev); - engine->timer.takedown(dev); - engine->mc.takedown(dev); + if (dev_priv->channel) { + nouveau_channel_free(dev_priv->channel); + dev_priv->channel = NULL; + } - mutex_lock(&dev->struct_mutex); - ttm_bo_clean_mm(&dev_priv->ttm.bdev, TTM_PL_VRAM); - ttm_bo_clean_mm(&dev_priv->ttm.bdev, TTM_PL_TT); - mutex_unlock(&dev->struct_mutex); - nouveau_sgdma_takedown(dev); + if (!nouveau_noaccel) { + engine->fifo.takedown(dev); + engine->graph.takedown(dev); + } + engine->fb.takedown(dev); + engine->timer.takedown(dev); + engine->gpio.takedown(dev); + engine->mc.takedown(dev); + engine->display.late_takedown(dev); - nouveau_gpuobj_takedown(dev); - nouveau_mem_close(dev); - engine->instmem.takedown(dev); + mutex_lock(&dev->struct_mutex); + ttm_bo_clean_mm(&dev_priv->ttm.bdev, TTM_PL_VRAM); + ttm_bo_clean_mm(&dev_priv->ttm.bdev, TTM_PL_TT); + mutex_unlock(&dev->struct_mutex); + nouveau_sgdma_takedown(dev); - if (drm_core_check_feature(dev, DRIVER_MODESET)) - drm_irq_uninstall(dev); + nouveau_gpuobj_takedown(dev); + nouveau_mem_close(dev); + engine->instmem.takedown(dev); - nouveau_gpuobj_late_takedown(dev); - nouveau_bios_takedown(dev); + drm_irq_uninstall(dev); - vga_client_register(dev->pdev, NULL, NULL, NULL); + nouveau_gpuobj_late_takedown(dev); + nouveau_bios_takedown(dev); - dev_priv->init_state = NOUVEAU_CARD_INIT_DOWN; - } + vga_client_register(dev->pdev, NULL, NULL, NULL); } /* here a client dies, release the stuff that was allocated for its @@ -691,6 +736,7 @@ int nouveau_load(struct drm_device *dev, unsigned long flags) struct drm_nouveau_private *dev_priv; uint32_t reg0; resource_size_t mmio_start_offs; + int ret; dev_priv = kzalloc(sizeof(*dev_priv), GFP_KERNEL); if (!dev_priv) @@ -699,7 +745,6 @@ int nouveau_load(struct drm_device *dev, unsigned long flags) dev_priv->dev = dev; dev_priv->flags = flags & NOUVEAU_FLAGS; - dev_priv->init_state = NOUVEAU_CARD_INIT_DOWN; NV_DEBUG(dev, "vendor: 0x%X device: 0x%X class: 0x%X\n", dev->pci_vendor, dev->pci_device, dev->pdev->class); @@ -773,11 +818,9 @@ int nouveau_load(struct drm_device *dev, unsigned long flags) NV_INFO(dev, "Detected an NV%2x generation card (0x%08x)\n", dev_priv->card_type, reg0); - if (drm_core_check_feature(dev, DRIVER_MODESET)) { - int ret = nouveau_remove_conflicting_drivers(dev); - if (ret) - return ret; - } + ret = nouveau_remove_conflicting_drivers(dev); + if (ret) + return ret; /* Map PRAMIN BAR, or on older cards, the aperture withing BAR0 */ if (dev_priv->card_type >= NV_40) { @@ -812,46 +855,26 @@ int nouveau_load(struct drm_device *dev, unsigned long flags) dev_priv->flags |= NV_NFORCE2; /* For kernel modesetting, init card now and bring up fbcon */ - if (drm_core_check_feature(dev, DRIVER_MODESET)) { - int ret = nouveau_card_init(dev); - if (ret) - return ret; - } + ret = nouveau_card_init(dev); + if (ret) + return ret; return 0; } -static void nouveau_close(struct drm_device *dev) -{ - struct drm_nouveau_private *dev_priv = dev->dev_private; - - /* In the case of an error dev_priv may not be allocated yet */ - if (dev_priv) - nouveau_card_takedown(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) { struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_engine *engine = &dev_priv->engine; - if (drm_core_check_feature(dev, DRIVER_MODESET)) { - drm_kms_helper_poll_fini(dev); - nouveau_fbcon_fini(dev); - if (dev_priv->card_type >= NV_50) - nv50_display_destroy(dev); - else - nv04_display_destroy(dev); - nouveau_close(dev); - } + drm_kms_helper_poll_fini(dev); + nouveau_fbcon_fini(dev); + engine->display.destroy(dev); + nouveau_card_takedown(dev); iounmap(dev_priv->mmio); iounmap(dev_priv->ramin); @@ -867,8 +890,6 @@ int nouveau_ioctl_getparam(struct drm_device *dev, void *data, struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_nouveau_getparam *getparam = data; - NOUVEAU_CHECK_INITIALISED_WITH_RETURN; - switch (getparam->param) { case NOUVEAU_GETPARAM_CHIPSET_ID: getparam->value = dev_priv->chipset; @@ -937,8 +958,6 @@ nouveau_ioctl_setparam(struct drm_device *dev, void *data, { struct drm_nouveau_setparam *setparam = data; - NOUVEAU_CHECK_INITIALISED_WITH_RETURN; - switch (setparam->param) { default: NV_ERROR(dev, "unknown parameter %lld\n", setparam->param); diff --git a/drivers/gpu/drm/nouveau/nouveau_ttm.c b/drivers/gpu/drm/nouveau/nouveau_ttm.c index c385d50..bd35f93 100644 --- a/drivers/gpu/drm/nouveau/nouveau_ttm.c +++ b/drivers/gpu/drm/nouveau/nouveau_ttm.c @@ -42,13 +42,13 @@ nouveau_ttm_mmap(struct file *filp, struct vm_area_struct *vma) } static int -nouveau_ttm_mem_global_init(struct ttm_global_reference *ref) +nouveau_ttm_mem_global_init(struct drm_global_reference *ref) { return ttm_mem_global_init(ref->object); } static void -nouveau_ttm_mem_global_release(struct ttm_global_reference *ref) +nouveau_ttm_mem_global_release(struct drm_global_reference *ref) { ttm_mem_global_release(ref->object); } @@ -56,16 +56,16 @@ nouveau_ttm_mem_global_release(struct ttm_global_reference *ref) int nouveau_ttm_global_init(struct drm_nouveau_private *dev_priv) { - struct ttm_global_reference *global_ref; + struct drm_global_reference *global_ref; int ret; global_ref = &dev_priv->ttm.mem_global_ref; - global_ref->global_type = TTM_GLOBAL_TTM_MEM; + global_ref->global_type = DRM_GLOBAL_TTM_MEM; global_ref->size = sizeof(struct ttm_mem_global); global_ref->init = &nouveau_ttm_mem_global_init; global_ref->release = &nouveau_ttm_mem_global_release; - ret = ttm_global_item_ref(global_ref); + ret = drm_global_item_ref(global_ref); if (unlikely(ret != 0)) { DRM_ERROR("Failed setting up TTM memory accounting\n"); dev_priv->ttm.mem_global_ref.release = NULL; @@ -74,15 +74,15 @@ nouveau_ttm_global_init(struct drm_nouveau_private *dev_priv) dev_priv->ttm.bo_global_ref.mem_glob = global_ref->object; global_ref = &dev_priv->ttm.bo_global_ref.ref; - global_ref->global_type = TTM_GLOBAL_TTM_BO; + global_ref->global_type = DRM_GLOBAL_TTM_BO; global_ref->size = sizeof(struct ttm_bo_global); global_ref->init = &ttm_bo_global_init; global_ref->release = &ttm_bo_global_release; - ret = ttm_global_item_ref(global_ref); + ret = drm_global_item_ref(global_ref); if (unlikely(ret != 0)) { DRM_ERROR("Failed setting up TTM BO subsystem\n"); - ttm_global_item_unref(&dev_priv->ttm.mem_global_ref); + drm_global_item_unref(&dev_priv->ttm.mem_global_ref); dev_priv->ttm.mem_global_ref.release = NULL; return ret; } @@ -96,8 +96,8 @@ nouveau_ttm_global_release(struct drm_nouveau_private *dev_priv) if (dev_priv->ttm.mem_global_ref.release == NULL) return; - ttm_global_item_unref(&dev_priv->ttm.bo_global_ref.ref); - ttm_global_item_unref(&dev_priv->ttm.mem_global_ref); + drm_global_item_unref(&dev_priv->ttm.bo_global_ref.ref); + drm_global_item_unref(&dev_priv->ttm.mem_global_ref); dev_priv->ttm.mem_global_ref.release = NULL; } diff --git a/drivers/gpu/drm/nouveau/nv04_crtc.c b/drivers/gpu/drm/nouveau/nv04_crtc.c index eba687f1..1c20c08 100644 --- a/drivers/gpu/drm/nouveau/nv04_crtc.c +++ b/drivers/gpu/drm/nouveau/nv04_crtc.c @@ -157,6 +157,7 @@ nv_crtc_dpms(struct drm_crtc *crtc, int mode) { struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); struct drm_device *dev = crtc->dev; + struct drm_connector *connector; unsigned char seq1 = 0, crtc17 = 0; unsigned char crtc1A; @@ -211,6 +212,10 @@ nv_crtc_dpms(struct drm_crtc *crtc, int mode) NVVgaSeqReset(dev, nv_crtc->index, false); NVWriteVgaCrtc(dev, nv_crtc->index, NV_CIO_CRE_RPC1_INDEX, crtc1A); + + /* Update connector polling modes */ + list_for_each_entry(connector, &dev->mode_config.connector_list, head) + nouveau_connector_set_polling(connector); } static bool diff --git a/drivers/gpu/drm/nouveau/nv04_dac.c b/drivers/gpu/drm/nouveau/nv04_dac.c index 1cb19e3..ea36270 100644 --- a/drivers/gpu/drm/nouveau/nv04_dac.c +++ b/drivers/gpu/drm/nouveau/nv04_dac.c @@ -220,6 +220,7 @@ uint32_t nv17_dac_sample_load(struct drm_encoder *encoder) { struct drm_device *dev = encoder->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_gpio_engine *gpio = &dev_priv->engine.gpio; struct dcb_entry *dcb = nouveau_encoder(encoder)->dcb; uint32_t sample, testval, regoffset = nv04_dac_output_offset(encoder); uint32_t saved_powerctrl_2 = 0, saved_powerctrl_4 = 0, saved_routput, @@ -251,22 +252,21 @@ uint32_t nv17_dac_sample_load(struct drm_encoder *encoder) nvWriteMC(dev, NV_PBUS_POWERCTRL_4, saved_powerctrl_4 & 0xffffffcf); } - saved_gpio1 = nv17_gpio_get(dev, DCB_GPIO_TVDAC1); - saved_gpio0 = nv17_gpio_get(dev, DCB_GPIO_TVDAC0); + saved_gpio1 = gpio->get(dev, DCB_GPIO_TVDAC1); + saved_gpio0 = gpio->get(dev, DCB_GPIO_TVDAC0); - nv17_gpio_set(dev, DCB_GPIO_TVDAC1, dcb->type == OUTPUT_TV); - nv17_gpio_set(dev, DCB_GPIO_TVDAC0, dcb->type == OUTPUT_TV); + gpio->set(dev, DCB_GPIO_TVDAC1, dcb->type == OUTPUT_TV); + gpio->set(dev, DCB_GPIO_TVDAC0, dcb->type == OUTPUT_TV); msleep(4); saved_routput = NVReadRAMDAC(dev, 0, NV_PRAMDAC_DACCLK + regoffset); head = (saved_routput & 0x100) >> 8; -#if 0 - /* if there's a spare crtc, using it will minimise flicker for the case - * where the in-use crtc is in use by an off-chip tmds encoder */ - if (xf86_config->crtc[head]->enabled && !xf86_config->crtc[head ^ 1]->enabled) + + /* if there's a spare crtc, using it will minimise flicker */ + if (!(NVReadVgaCrtc(dev, head, NV_CIO_CRE_RPC1_INDEX) & 0xC0)) head ^= 1; -#endif + /* nv driver and nv31 use 0xfffffeee, nv34 and 6600 use 0xfffffece */ routput = (saved_routput & 0xfffffece) | head << 8; @@ -304,8 +304,8 @@ uint32_t nv17_dac_sample_load(struct drm_encoder *encoder) nvWriteMC(dev, NV_PBUS_POWERCTRL_4, saved_powerctrl_4); nvWriteMC(dev, NV_PBUS_POWERCTRL_2, saved_powerctrl_2); - nv17_gpio_set(dev, DCB_GPIO_TVDAC1, saved_gpio1); - nv17_gpio_set(dev, DCB_GPIO_TVDAC0, saved_gpio0); + gpio->set(dev, DCB_GPIO_TVDAC1, saved_gpio1); + gpio->set(dev, DCB_GPIO_TVDAC0, saved_gpio0); return sample; } @@ -315,9 +315,12 @@ nv17_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector) { struct drm_device *dev = encoder->dev; struct dcb_entry *dcb = nouveau_encoder(encoder)->dcb; - uint32_t sample = nv17_dac_sample_load(encoder); - if (sample & NV_PRAMDAC_TEST_CONTROL_SENSEB_ALLHI) { + if (nv04_dac_in_use(encoder)) + return connector_status_disconnected; + + if (nv17_dac_sample_load(encoder) & + NV_PRAMDAC_TEST_CONTROL_SENSEB_ALLHI) { NV_INFO(dev, "Load detected on output %c\n", '@' + ffs(dcb->or)); return connector_status_connected; @@ -330,6 +333,9 @@ static bool nv04_dac_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { + if (nv04_dac_in_use(encoder)) + return false; + return true; } @@ -428,6 +434,17 @@ void nv04_dac_update_dacclk(struct drm_encoder *encoder, bool enable) } } +/* Check if the DAC corresponding to 'encoder' is being used by + * someone else. */ +bool nv04_dac_in_use(struct drm_encoder *encoder) +{ + struct drm_nouveau_private *dev_priv = encoder->dev->dev_private; + struct dcb_entry *dcb = nouveau_encoder(encoder)->dcb; + + return nv_gf4_disp_arch(encoder->dev) && + (dev_priv->dac_users[ffs(dcb->or) - 1] & ~(1 << dcb->index)); +} + static void nv04_dac_dpms(struct drm_encoder *encoder, int mode) { struct drm_device *dev = encoder->dev; @@ -501,11 +518,13 @@ static const struct drm_encoder_funcs nv04_dac_funcs = { .destroy = nv04_dac_destroy, }; -int nv04_dac_create(struct drm_device *dev, struct dcb_entry *entry) +int +nv04_dac_create(struct drm_connector *connector, struct dcb_entry *entry) { const struct drm_encoder_helper_funcs *helper; - struct drm_encoder *encoder; struct nouveau_encoder *nv_encoder = NULL; + struct drm_device *dev = connector->dev; + struct drm_encoder *encoder; nv_encoder = kzalloc(sizeof(*nv_encoder), GFP_KERNEL); if (!nv_encoder) @@ -527,5 +546,6 @@ int nv04_dac_create(struct drm_device *dev, struct dcb_entry *entry) encoder->possible_crtcs = entry->heads; encoder->possible_clones = 0; + drm_mode_connector_attach_encoder(connector, encoder); return 0; } diff --git a/drivers/gpu/drm/nouveau/nv04_dfp.c b/drivers/gpu/drm/nouveau/nv04_dfp.c index 41634d4..3311f3a 100644 --- a/drivers/gpu/drm/nouveau/nv04_dfp.c +++ b/drivers/gpu/drm/nouveau/nv04_dfp.c @@ -413,10 +413,6 @@ static void nv04_dfp_commit(struct drm_encoder *encoder) struct dcb_entry *dcbe = nv_encoder->dcb; int head = nouveau_crtc(encoder->crtc)->index; - NV_INFO(dev, "Output %s is running on CRTC %d using output %c\n", - drm_get_connector_name(&nouveau_encoder_connector_get(nv_encoder)->base), - nv_crtc->index, '@' + ffs(nv_encoder->dcb->or)); - if (dcbe->type == OUTPUT_TMDS) run_tmds_table(dev, dcbe, head, nv_encoder->mode.clock); else if (dcbe->type == OUTPUT_LVDS) @@ -584,11 +580,12 @@ static const struct drm_encoder_funcs nv04_dfp_funcs = { .destroy = nv04_dfp_destroy, }; -int nv04_dfp_create(struct drm_device *dev, struct dcb_entry *entry) +int +nv04_dfp_create(struct drm_connector *connector, struct dcb_entry *entry) { const struct drm_encoder_helper_funcs *helper; - struct drm_encoder *encoder; struct nouveau_encoder *nv_encoder = NULL; + struct drm_encoder *encoder; int type; switch (entry->type) { @@ -613,11 +610,12 @@ int nv04_dfp_create(struct drm_device *dev, struct dcb_entry *entry) nv_encoder->dcb = entry; nv_encoder->or = ffs(entry->or) - 1; - drm_encoder_init(dev, encoder, &nv04_dfp_funcs, type); + drm_encoder_init(connector->dev, encoder, &nv04_dfp_funcs, type); drm_encoder_helper_add(encoder, helper); encoder->possible_crtcs = entry->heads; encoder->possible_clones = 0; + drm_mode_connector_attach_encoder(connector, encoder); return 0; } diff --git a/drivers/gpu/drm/nouveau/nv04_display.c b/drivers/gpu/drm/nouveau/nv04_display.c index c7898b4..9e28cf7 100644 --- a/drivers/gpu/drm/nouveau/nv04_display.c +++ b/drivers/gpu/drm/nouveau/nv04_display.c @@ -32,8 +32,6 @@ #include "nouveau_encoder.h" #include "nouveau_connector.h" -#define MULTIPLE_ENCODERS(e) (e & (e - 1)) - static void nv04_display_store_initial_head_owner(struct drm_device *dev) { @@ -41,7 +39,7 @@ nv04_display_store_initial_head_owner(struct drm_device *dev) if (dev_priv->chipset != 0x11) { dev_priv->crtc_owner = NVReadVgaCrtc(dev, 0, NV_CIO_CRE_44); - goto ownerknown; + return; } /* reading CR44 is broken on nv11, so we attempt to infer it */ @@ -52,8 +50,6 @@ nv04_display_store_initial_head_owner(struct drm_device *dev) bool tvA = false; bool tvB = false; - NVLockVgaCrtcs(dev, false); - slaved_on_B = NVReadVgaCrtc(dev, 1, NV_CIO_CRE_PIXEL_INDEX) & 0x80; if (slaved_on_B) @@ -66,8 +62,6 @@ nv04_display_store_initial_head_owner(struct drm_device *dev) tvA = !(NVReadVgaCrtc(dev, 0, NV_CIO_CRE_LCD__INDEX) & MASK(NV_CIO_CRE_LCD_LCD_SELECT)); - NVLockVgaCrtcs(dev, true); - if (slaved_on_A && !tvA) dev_priv->crtc_owner = 0x0; else if (slaved_on_B && !tvB) @@ -79,14 +73,40 @@ nv04_display_store_initial_head_owner(struct drm_device *dev) else dev_priv->crtc_owner = 0x0; } +} + +int +nv04_display_early_init(struct drm_device *dev) +{ + /* Make the I2C buses accessible. */ + if (!nv_gf4_disp_arch(dev)) { + uint32_t pmc_enable = nv_rd32(dev, NV03_PMC_ENABLE); + + if (!(pmc_enable & 1)) + nv_wr32(dev, NV03_PMC_ENABLE, pmc_enable | 1); + } -ownerknown: - NV_INFO(dev, "Initial CRTC_OWNER is %d\n", dev_priv->crtc_owner); + /* Unlock the VGA CRTCs. */ + NVLockVgaCrtcs(dev, false); + + /* Make sure the CRTCs aren't in slaved mode. */ + if (nv_two_heads(dev)) { + nv04_display_store_initial_head_owner(dev); + NVSetOwner(dev, 0); + } + + return 0; +} + +void +nv04_display_late_takedown(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + + if (nv_two_heads(dev)) + NVSetOwner(dev, dev_priv->crtc_owner); - /* we need to ensure the heads are not tied henceforth, or reading any - * 8 bit reg on head B will fail - * setting a single arbitrary head solves that */ - NVSetOwner(dev, 0); + NVLockVgaCrtcs(dev, true); } int @@ -94,14 +114,13 @@ nv04_display_create(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; struct dcb_table *dcb = &dev_priv->vbios.dcb; + struct drm_connector *connector, *ct; struct drm_encoder *encoder; struct drm_crtc *crtc; int i, ret; NV_DEBUG_KMS(dev, "\n"); - if (nv_two_heads(dev)) - nv04_display_store_initial_head_owner(dev); nouveau_hw_save_vga_fonts(dev, 1); drm_mode_config_init(dev); @@ -132,19 +151,23 @@ nv04_display_create(struct drm_device *dev) for (i = 0; i < dcb->entries; i++) { struct dcb_entry *dcbent = &dcb->entry[i]; + connector = nouveau_connector_create(dev, dcbent->connector); + if (IS_ERR(connector)) + continue; + switch (dcbent->type) { case OUTPUT_ANALOG: - ret = nv04_dac_create(dev, dcbent); + ret = nv04_dac_create(connector, dcbent); break; case OUTPUT_LVDS: case OUTPUT_TMDS: - ret = nv04_dfp_create(dev, dcbent); + ret = nv04_dfp_create(connector, dcbent); break; case OUTPUT_TV: if (dcbent->location == DCB_LOC_ON_CHIP) - ret = nv17_tv_create(dev, dcbent); + ret = nv17_tv_create(connector, dcbent); else - ret = nv04_tv_create(dev, dcbent); + ret = nv04_tv_create(connector, dcbent); break; default: NV_WARN(dev, "DCB type %d not known\n", dcbent->type); @@ -155,12 +178,16 @@ nv04_display_create(struct drm_device *dev) continue; } - for (i = 0; i < dcb->connector.entries; i++) - nouveau_connector_create(dev, &dcb->connector.entry[i]); + list_for_each_entry_safe(connector, ct, + &dev->mode_config.connector_list, head) { + if (!connector->encoder_ids[0]) { + NV_WARN(dev, "%s has no encoders, removing\n", + drm_get_connector_name(connector)); + connector->funcs->destroy(connector); + } + } /* Save previous state */ - NVLockVgaCrtcs(dev, false); - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) crtc->funcs->save(crtc); @@ -191,8 +218,6 @@ nv04_display_destroy(struct drm_device *dev) } /* Restore state */ - NVLockVgaCrtcs(dev, false); - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { struct drm_encoder_helper_funcs *func = encoder->helper_private; @@ -207,15 +232,12 @@ nv04_display_destroy(struct drm_device *dev) nouveau_hw_save_vga_fonts(dev, 0); } -void -nv04_display_restore(struct drm_device *dev) +int +nv04_display_init(struct drm_device *dev) { - struct drm_nouveau_private *dev_priv = dev->dev_private; struct drm_encoder *encoder; struct drm_crtc *crtc; - NVLockVgaCrtcs(dev, false); - /* meh.. modeset apparently doesn't setup all the regs and depends * on pre-existing state, for now load the state of the card *before* * nouveau was loaded, and then do a modeset. @@ -233,12 +255,6 @@ nv04_display_restore(struct drm_device *dev) list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) crtc->funcs->restore(crtc); - if (nv_two_heads(dev)) { - NV_INFO(dev, "Restoring CRTC_OWNER to %d.\n", - dev_priv->crtc_owner); - NVSetOwner(dev, dev_priv->crtc_owner); - } - - NVLockVgaCrtcs(dev, true); + return 0; } diff --git a/drivers/gpu/drm/nouveau/nv04_fifo.c b/drivers/gpu/drm/nouveau/nv04_fifo.c index 66fe559..06cedd9 100644 --- a/drivers/gpu/drm/nouveau/nv04_fifo.c +++ b/drivers/gpu/drm/nouveau/nv04_fifo.c @@ -112,6 +112,12 @@ nv04_fifo_channel_id(struct drm_device *dev) NV03_PFIFO_CACHE1_PUSH1_CHID_MASK; } +#ifdef __BIG_ENDIAN +#define DMA_FETCH_ENDIANNESS NV_PFIFO_CACHE1_BIG_ENDIAN +#else +#define DMA_FETCH_ENDIANNESS 0 +#endif + int nv04_fifo_create_context(struct nouveau_channel *chan) { @@ -131,18 +137,13 @@ nv04_fifo_create_context(struct nouveau_channel *chan) spin_lock_irqsave(&dev_priv->context_switch_lock, flags); /* Setup initial state */ - dev_priv->engine.instmem.prepare_access(dev, true); RAMFC_WR(DMA_PUT, chan->pushbuf_base); RAMFC_WR(DMA_GET, chan->pushbuf_base); RAMFC_WR(DMA_INSTANCE, chan->pushbuf->instance >> 4); RAMFC_WR(DMA_FETCH, (NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES | NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES | NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8 | -#ifdef __BIG_ENDIAN - NV_PFIFO_CACHE1_BIG_ENDIAN | -#endif - 0)); - dev_priv->engine.instmem.finish_access(dev); + DMA_FETCH_ENDIANNESS)); /* enable the fifo dma operation */ nv_wr32(dev, NV04_PFIFO_MODE, @@ -169,8 +170,6 @@ nv04_fifo_do_load_context(struct drm_device *dev, int chid) struct drm_nouveau_private *dev_priv = dev->dev_private; uint32_t fc = NV04_RAMFC(chid), tmp; - dev_priv->engine.instmem.prepare_access(dev, false); - nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_PUT, nv_ri32(dev, fc + 0)); nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_GET, nv_ri32(dev, fc + 4)); tmp = nv_ri32(dev, fc + 8); @@ -181,8 +180,6 @@ nv04_fifo_do_load_context(struct drm_device *dev, int chid) nv_wr32(dev, NV04_PFIFO_CACHE1_ENGINE, nv_ri32(dev, fc + 20)); nv_wr32(dev, NV04_PFIFO_CACHE1_PULL1, nv_ri32(dev, fc + 24)); - dev_priv->engine.instmem.finish_access(dev); - nv_wr32(dev, NV03_PFIFO_CACHE1_GET, 0); nv_wr32(dev, NV03_PFIFO_CACHE1_PUT, 0); } @@ -223,7 +220,6 @@ nv04_fifo_unload_context(struct drm_device *dev) return -EINVAL; } - dev_priv->engine.instmem.prepare_access(dev, true); RAMFC_WR(DMA_PUT, nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_PUT)); RAMFC_WR(DMA_GET, nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_GET)); tmp = nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_DCOUNT) << 16; @@ -233,7 +229,6 @@ nv04_fifo_unload_context(struct drm_device *dev) RAMFC_WR(DMA_FETCH, nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_FETCH)); RAMFC_WR(ENGINE, nv_rd32(dev, NV04_PFIFO_CACHE1_ENGINE)); RAMFC_WR(PULL1_ENGINE, nv_rd32(dev, NV04_PFIFO_CACHE1_PULL1)); - dev_priv->engine.instmem.finish_access(dev); nv04_fifo_do_load_context(dev, pfifo->channels - 1); nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH1, pfifo->channels - 1); @@ -297,6 +292,7 @@ nv04_fifo_init(struct drm_device *dev) nv04_fifo_init_intr(dev); pfifo->enable(dev); + pfifo->reassign(dev, true); for (i = 0; i < dev_priv->engine.fifo.channels; i++) { if (dev_priv->fifos[i]) { diff --git a/drivers/gpu/drm/nouveau/nv04_graph.c b/drivers/gpu/drm/nouveau/nv04_graph.c index 618355e..c897342 100644 --- a/drivers/gpu/drm/nouveau/nv04_graph.c +++ b/drivers/gpu/drm/nouveau/nv04_graph.c @@ -342,7 +342,7 @@ static uint32_t nv04_graph_ctx_regs[] = { }; struct graph_state { - int nv04[ARRAY_SIZE(nv04_graph_ctx_regs)]; + uint32_t nv04[ARRAY_SIZE(nv04_graph_ctx_regs)]; }; struct nouveau_channel * @@ -527,8 +527,7 @@ static int nv04_graph_mthd_set_ref(struct nouveau_channel *chan, int grclass, int mthd, uint32_t data) { - chan->fence.last_sequence_irq = data; - nouveau_fence_handler(chan->dev, chan->id); + atomic_set(&chan->fence.last_sequence_irq, data); return 0; } diff --git a/drivers/gpu/drm/nouveau/nv04_instmem.c b/drivers/gpu/drm/nouveau/nv04_instmem.c index a3b9563..4408232 100644 --- a/drivers/gpu/drm/nouveau/nv04_instmem.c +++ b/drivers/gpu/drm/nouveau/nv04_instmem.c @@ -49,10 +49,8 @@ nv04_instmem_determine_amount(struct drm_device *dev) NV_DEBUG(dev, "RAMIN size: %dKiB\n", dev_priv->ramin_rsvd_vram >> 10); /* Clear all of it, except the BIOS image that's in the first 64KiB */ - dev_priv->engine.instmem.prepare_access(dev, true); for (i = 64 * 1024; i < dev_priv->ramin_rsvd_vram; i += 4) nv_wi32(dev, i, 0x00000000); - dev_priv->engine.instmem.finish_access(dev); } static void @@ -106,7 +104,7 @@ int nv04_instmem_init(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; uint32_t offset; - int ret = 0; + int ret; nv04_instmem_determine_amount(dev); nv04_instmem_configure_fixed_tables(dev); @@ -129,14 +127,14 @@ int nv04_instmem_init(struct drm_device *dev) offset = 0x40000; } - ret = nouveau_mem_init_heap(&dev_priv->ramin_heap, - offset, dev_priv->ramin_rsvd_vram - offset); + ret = drm_mm_init(&dev_priv->ramin_heap, offset, + dev_priv->ramin_rsvd_vram - offset); if (ret) { - dev_priv->ramin_heap = NULL; - NV_ERROR(dev, "Failed to init RAMIN heap\n"); + NV_ERROR(dev, "Failed to init RAMIN heap: %d\n", ret); + return ret; } - return ret; + return 0; } void @@ -186,12 +184,7 @@ nv04_instmem_unbind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) } void -nv04_instmem_prepare_access(struct drm_device *dev, bool write) -{ -} - -void -nv04_instmem_finish_access(struct drm_device *dev) +nv04_instmem_flush(struct drm_device *dev) { } diff --git a/drivers/gpu/drm/nouveau/nv04_mc.c b/drivers/gpu/drm/nouveau/nv04_mc.c index 617ed1e..2af43a1 100644 --- a/drivers/gpu/drm/nouveau/nv04_mc.c +++ b/drivers/gpu/drm/nouveau/nv04_mc.c @@ -11,6 +11,10 @@ nv04_mc_init(struct drm_device *dev) */ nv_wr32(dev, NV03_PMC_ENABLE, 0xFFFFFFFF); + + /* Disable PROM access. */ + nv_wr32(dev, NV_PBUS_PCI_NV_20, NV_PBUS_PCI_NV_20_ROM_SHADOW_ENABLED); + return 0; } diff --git a/drivers/gpu/drm/nouveau/nv04_tv.c b/drivers/gpu/drm/nouveau/nv04_tv.c index c4e3404..94e299c 100644 --- a/drivers/gpu/drm/nouveau/nv04_tv.c +++ b/drivers/gpu/drm/nouveau/nv04_tv.c @@ -34,69 +34,26 @@ #include "i2c/ch7006.h" -static struct { - struct i2c_board_info board_info; - struct drm_encoder_funcs funcs; - struct drm_encoder_helper_funcs hfuncs; - void *params; - -} nv04_tv_encoder_info[] = { +static struct i2c_board_info nv04_tv_encoder_info[] = { { - .board_info = { I2C_BOARD_INFO("ch7006", 0x75) }, - .params = &(struct ch7006_encoder_params) { + I2C_BOARD_INFO("ch7006", 0x75), + .platform_data = &(struct ch7006_encoder_params) { CH7006_FORMAT_RGB24m12I, CH7006_CLOCK_MASTER, 0, 0, 0, CH7006_SYNC_SLAVE, CH7006_SYNC_SEPARATED, CH7006_POUT_3_3V, CH7006_ACTIVE_HSYNC - }, + } }, + { } }; -static bool probe_i2c_addr(struct i2c_adapter *adapter, int addr) -{ - struct i2c_msg msg = { - .addr = addr, - .len = 0, - }; - - return i2c_transfer(adapter, &msg, 1) == 1; -} - int nv04_tv_identify(struct drm_device *dev, int i2c_index) { - struct nouveau_i2c_chan *i2c; - bool was_locked; - int i, ret; - - NV_TRACE(dev, "Probing TV encoders on I2C bus: %d\n", i2c_index); - - i2c = nouveau_i2c_find(dev, i2c_index); - if (!i2c) - return -ENODEV; - - was_locked = NVLockVgaCrtcs(dev, false); - - for (i = 0; i < ARRAY_SIZE(nv04_tv_encoder_info); i++) { - if (probe_i2c_addr(&i2c->adapter, - nv04_tv_encoder_info[i].board_info.addr)) { - ret = i; - break; - } - } - - if (i < ARRAY_SIZE(nv04_tv_encoder_info)) { - NV_TRACE(dev, "Detected TV encoder: %s\n", - nv04_tv_encoder_info[i].board_info.type); - - } else { - NV_TRACE(dev, "No TV encoders found.\n"); - i = -ENODEV; - } - - NVLockVgaCrtcs(dev, was_locked); - return i; + return nouveau_i2c_identify(dev, "TV encoder", + nv04_tv_encoder_info, i2c_index); } + #define PLLSEL_TV_CRTC1_MASK \ (NV_PRAMDAC_PLL_COEFF_SELECT_TV_VSCLK1 \ | NV_PRAMDAC_PLL_COEFF_SELECT_TV_PCLK1) @@ -214,30 +171,32 @@ static void nv04_tv_commit(struct drm_encoder *encoder) static void nv04_tv_destroy(struct drm_encoder *encoder) { - struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); - to_encoder_slave(encoder)->slave_funcs->destroy(encoder); drm_encoder_cleanup(encoder); - kfree(nv_encoder); + kfree(encoder->helper_private); + kfree(nouveau_encoder(encoder)); } -int nv04_tv_create(struct drm_device *dev, struct dcb_entry *entry) +static const struct drm_encoder_funcs nv04_tv_funcs = { + .destroy = nv04_tv_destroy, +}; + +int +nv04_tv_create(struct drm_connector *connector, struct dcb_entry *entry) { struct nouveau_encoder *nv_encoder; struct drm_encoder *encoder; - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct i2c_adapter *adap; - struct drm_encoder_funcs *funcs = NULL; - struct drm_encoder_helper_funcs *hfuncs = NULL; - struct drm_encoder_slave_funcs *sfuncs = NULL; - int i2c_index = entry->i2c_index; + struct drm_device *dev = connector->dev; + struct drm_encoder_helper_funcs *hfuncs; + struct drm_encoder_slave_funcs *sfuncs; + struct nouveau_i2c_chan *i2c = + nouveau_i2c_find(dev, entry->i2c_index); int type, ret; - bool was_locked; /* Ensure that we can talk to this encoder */ - type = nv04_tv_identify(dev, i2c_index); + type = nv04_tv_identify(dev, entry->i2c_index); if (type < 0) return type; @@ -246,41 +205,32 @@ int nv04_tv_create(struct drm_device *dev, struct dcb_entry *entry) if (!nv_encoder) return -ENOMEM; + hfuncs = kzalloc(sizeof(*hfuncs), GFP_KERNEL); + if (!hfuncs) { + ret = -ENOMEM; + goto fail_free; + } + /* Initialize the common members */ encoder = to_drm_encoder(nv_encoder); - funcs = &nv04_tv_encoder_info[type].funcs; - hfuncs = &nv04_tv_encoder_info[type].hfuncs; - - drm_encoder_init(dev, encoder, funcs, DRM_MODE_ENCODER_TVDAC); + drm_encoder_init(dev, encoder, &nv04_tv_funcs, DRM_MODE_ENCODER_TVDAC); drm_encoder_helper_add(encoder, hfuncs); encoder->possible_crtcs = entry->heads; encoder->possible_clones = 0; - nv_encoder->dcb = entry; nv_encoder->or = ffs(entry->or) - 1; /* Run the slave-specific initialization */ - adap = &dev_priv->vbios.dcb.i2c[i2c_index].chan->adapter; - - was_locked = NVLockVgaCrtcs(dev, false); - - ret = drm_i2c_encoder_init(encoder->dev, to_encoder_slave(encoder), adap, - &nv04_tv_encoder_info[type].board_info); - - NVLockVgaCrtcs(dev, was_locked); - + ret = drm_i2c_encoder_init(dev, to_encoder_slave(encoder), + &i2c->adapter, &nv04_tv_encoder_info[type]); if (ret < 0) - goto fail; + goto fail_cleanup; /* Fill the function pointers */ sfuncs = to_encoder_slave(encoder)->slave_funcs; - *funcs = (struct drm_encoder_funcs) { - .destroy = nv04_tv_destroy, - }; - *hfuncs = (struct drm_encoder_helper_funcs) { .dpms = nv04_tv_dpms, .save = sfuncs->save, @@ -292,14 +242,17 @@ int nv04_tv_create(struct drm_device *dev, struct dcb_entry *entry) .detect = sfuncs->detect, }; - /* Set the slave encoder configuration */ - sfuncs->set_config(encoder, nv04_tv_encoder_info[type].params); + /* Attach it to the specified connector. */ + sfuncs->set_config(encoder, nv04_tv_encoder_info[type].platform_data); + sfuncs->create_resources(encoder, connector); + drm_mode_connector_attach_encoder(connector, encoder); return 0; -fail: +fail_cleanup: drm_encoder_cleanup(encoder); - + kfree(hfuncs); +fail_free: kfree(nv_encoder); return ret; } diff --git a/drivers/gpu/drm/nouveau/nv10_fifo.c b/drivers/gpu/drm/nouveau/nv10_fifo.c index 7aeabf2..7a4069c 100644 --- a/drivers/gpu/drm/nouveau/nv10_fifo.c +++ b/drivers/gpu/drm/nouveau/nv10_fifo.c @@ -55,7 +55,6 @@ nv10_fifo_create_context(struct nouveau_channel *chan) /* Fill entries that are seen filled in dumps of nvidia driver just * after channel's is put into DMA mode */ - dev_priv->engine.instmem.prepare_access(dev, true); nv_wi32(dev, fc + 0, chan->pushbuf_base); nv_wi32(dev, fc + 4, chan->pushbuf_base); nv_wi32(dev, fc + 12, chan->pushbuf->instance >> 4); @@ -66,7 +65,6 @@ nv10_fifo_create_context(struct nouveau_channel *chan) NV_PFIFO_CACHE1_BIG_ENDIAN | #endif 0); - dev_priv->engine.instmem.finish_access(dev); /* enable the fifo dma operation */ nv_wr32(dev, NV04_PFIFO_MODE, @@ -91,8 +89,6 @@ nv10_fifo_do_load_context(struct drm_device *dev, int chid) struct drm_nouveau_private *dev_priv = dev->dev_private; uint32_t fc = NV10_RAMFC(chid), tmp; - dev_priv->engine.instmem.prepare_access(dev, false); - nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_PUT, nv_ri32(dev, fc + 0)); nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_GET, nv_ri32(dev, fc + 4)); nv_wr32(dev, NV10_PFIFO_CACHE1_REF_CNT, nv_ri32(dev, fc + 8)); @@ -117,8 +113,6 @@ nv10_fifo_do_load_context(struct drm_device *dev, int chid) nv_wr32(dev, NV10_PFIFO_CACHE1_DMA_SUBROUTINE, nv_ri32(dev, fc + 48)); out: - dev_priv->engine.instmem.finish_access(dev); - nv_wr32(dev, NV03_PFIFO_CACHE1_GET, 0); nv_wr32(dev, NV03_PFIFO_CACHE1_PUT, 0); } @@ -155,8 +149,6 @@ nv10_fifo_unload_context(struct drm_device *dev) return 0; fc = NV10_RAMFC(chid); - dev_priv->engine.instmem.prepare_access(dev, true); - nv_wi32(dev, fc + 0, nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_PUT)); nv_wi32(dev, fc + 4, nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_GET)); nv_wi32(dev, fc + 8, nv_rd32(dev, NV10_PFIFO_CACHE1_REF_CNT)); @@ -179,8 +171,6 @@ nv10_fifo_unload_context(struct drm_device *dev) nv_wi32(dev, fc + 48, nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_GET)); out: - dev_priv->engine.instmem.finish_access(dev); - nv10_fifo_do_load_context(dev, pfifo->channels - 1); nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH1, pfifo->channels - 1); return 0; diff --git a/drivers/gpu/drm/nouveau/nv17_gpio.c b/drivers/gpu/drm/nouveau/nv10_gpio.c index 2e58c33..007fc29 100644 --- a/drivers/gpu/drm/nouveau/nv17_gpio.c +++ b/drivers/gpu/drm/nouveau/nv10_gpio.c @@ -55,7 +55,7 @@ get_gpio_location(struct dcb_gpio_entry *ent, uint32_t *reg, uint32_t *shift, } int -nv17_gpio_get(struct drm_device *dev, enum dcb_gpio_tag tag) +nv10_gpio_get(struct drm_device *dev, enum dcb_gpio_tag tag) { struct dcb_gpio_entry *ent = nouveau_bios_gpio_entry(dev, tag); uint32_t reg, shift, mask, value; @@ -72,7 +72,7 @@ nv17_gpio_get(struct drm_device *dev, enum dcb_gpio_tag tag) } int -nv17_gpio_set(struct drm_device *dev, enum dcb_gpio_tag tag, int state) +nv10_gpio_set(struct drm_device *dev, enum dcb_gpio_tag tag, int state) { struct dcb_gpio_entry *ent = nouveau_bios_gpio_entry(dev, tag); uint32_t reg, shift, mask, value; diff --git a/drivers/gpu/drm/nouveau/nv17_tv.c b/drivers/gpu/drm/nouveau/nv17_tv.c index 74c8803..44fefb0 100644 --- a/drivers/gpu/drm/nouveau/nv17_tv.c +++ b/drivers/gpu/drm/nouveau/nv17_tv.c @@ -37,6 +37,7 @@ static uint32_t nv42_tv_sample_load(struct drm_encoder *encoder) { struct drm_device *dev = encoder->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_gpio_engine *gpio = &dev_priv->engine.gpio; uint32_t testval, regoffset = nv04_dac_output_offset(encoder); uint32_t gpio0, gpio1, fp_htotal, fp_hsync_start, fp_hsync_end, fp_control, test_ctrl, dacclk, ctv_14, ctv_1c, ctv_6c; @@ -52,8 +53,8 @@ static uint32_t nv42_tv_sample_load(struct drm_encoder *encoder) head = (dacclk & 0x100) >> 8; /* Save the previous state. */ - gpio1 = nv17_gpio_get(dev, DCB_GPIO_TVDAC1); - gpio0 = nv17_gpio_get(dev, DCB_GPIO_TVDAC0); + gpio1 = gpio->get(dev, DCB_GPIO_TVDAC1); + gpio0 = gpio->get(dev, DCB_GPIO_TVDAC0); fp_htotal = NVReadRAMDAC(dev, head, NV_PRAMDAC_FP_HTOTAL); fp_hsync_start = NVReadRAMDAC(dev, head, NV_PRAMDAC_FP_HSYNC_START); fp_hsync_end = NVReadRAMDAC(dev, head, NV_PRAMDAC_FP_HSYNC_END); @@ -64,8 +65,8 @@ static uint32_t nv42_tv_sample_load(struct drm_encoder *encoder) ctv_6c = NVReadRAMDAC(dev, head, 0x680c6c); /* Prepare the DAC for load detection. */ - nv17_gpio_set(dev, DCB_GPIO_TVDAC1, true); - nv17_gpio_set(dev, DCB_GPIO_TVDAC0, true); + gpio->set(dev, DCB_GPIO_TVDAC1, true); + gpio->set(dev, DCB_GPIO_TVDAC0, true); NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_HTOTAL, 1343); NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_HSYNC_START, 1047); @@ -110,12 +111,27 @@ static uint32_t nv42_tv_sample_load(struct drm_encoder *encoder) NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_HSYNC_END, fp_hsync_end); NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_HSYNC_START, fp_hsync_start); NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_HTOTAL, fp_htotal); - nv17_gpio_set(dev, DCB_GPIO_TVDAC1, gpio1); - nv17_gpio_set(dev, DCB_GPIO_TVDAC0, gpio0); + gpio->set(dev, DCB_GPIO_TVDAC1, gpio1); + gpio->set(dev, DCB_GPIO_TVDAC0, gpio0); return sample; } +static bool +get_tv_detect_quirks(struct drm_device *dev, uint32_t *pin_mask) +{ + /* Zotac FX5200 */ + if (dev->pdev->device == 0x0322 && + dev->pdev->subsystem_vendor == 0x19da && + (dev->pdev->subsystem_device == 0x1035 || + dev->pdev->subsystem_device == 0x2035)) { + *pin_mask = 0xc; + return false; + } + + return true; +} + static enum drm_connector_status nv17_tv_detect(struct drm_encoder *encoder, struct drm_connector *connector) { @@ -124,12 +140,20 @@ nv17_tv_detect(struct drm_encoder *encoder, struct drm_connector *connector) struct drm_mode_config *conf = &dev->mode_config; struct nv17_tv_encoder *tv_enc = to_tv_enc(encoder); struct dcb_entry *dcb = tv_enc->base.dcb; + bool reliable = get_tv_detect_quirks(dev, &tv_enc->pin_mask); - if (dev_priv->chipset == 0x42 || - dev_priv->chipset == 0x43) - tv_enc->pin_mask = nv42_tv_sample_load(encoder) >> 28 & 0xe; - else - tv_enc->pin_mask = nv17_dac_sample_load(encoder) >> 28 & 0xe; + if (nv04_dac_in_use(encoder)) + return connector_status_disconnected; + + if (reliable) { + if (dev_priv->chipset == 0x42 || + dev_priv->chipset == 0x43) + tv_enc->pin_mask = + nv42_tv_sample_load(encoder) >> 28 & 0xe; + else + tv_enc->pin_mask = + nv17_dac_sample_load(encoder) >> 28 & 0xe; + } switch (tv_enc->pin_mask) { case 0x2: @@ -154,7 +178,9 @@ nv17_tv_detect(struct drm_encoder *encoder, struct drm_connector *connector) conf->tv_subconnector_property, tv_enc->subconnector); - if (tv_enc->subconnector) { + if (!reliable) { + return connector_status_unknown; + } else if (tv_enc->subconnector) { NV_INFO(dev, "Load detected on output %c\n", '@' + ffs(dcb->or)); return connector_status_connected; @@ -296,6 +322,9 @@ static bool nv17_tv_mode_fixup(struct drm_encoder *encoder, { struct nv17_tv_norm_params *tv_norm = get_tv_norm(encoder); + if (nv04_dac_in_use(encoder)) + return false; + if (tv_norm->kind == CTV_ENC_MODE) adjusted_mode->clock = tv_norm->ctv_enc_mode.mode.clock; else @@ -307,6 +336,8 @@ static bool nv17_tv_mode_fixup(struct drm_encoder *encoder, static void nv17_tv_dpms(struct drm_encoder *encoder, int mode) { struct drm_device *dev = encoder->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_gpio_engine *gpio = &dev_priv->engine.gpio; struct nv17_tv_state *regs = &to_tv_enc(encoder)->state; struct nv17_tv_norm_params *tv_norm = get_tv_norm(encoder); @@ -331,8 +362,8 @@ static void nv17_tv_dpms(struct drm_encoder *encoder, int mode) nv_load_ptv(dev, regs, 200); - nv17_gpio_set(dev, DCB_GPIO_TVDAC1, mode == DRM_MODE_DPMS_ON); - nv17_gpio_set(dev, DCB_GPIO_TVDAC0, mode == DRM_MODE_DPMS_ON); + gpio->set(dev, DCB_GPIO_TVDAC1, mode == DRM_MODE_DPMS_ON); + gpio->set(dev, DCB_GPIO_TVDAC0, mode == DRM_MODE_DPMS_ON); nv04_dac_update_dacclk(encoder, mode == DRM_MODE_DPMS_ON); } @@ -744,8 +775,10 @@ static struct drm_encoder_funcs nv17_tv_funcs = { .destroy = nv17_tv_destroy, }; -int nv17_tv_create(struct drm_device *dev, struct dcb_entry *entry) +int +nv17_tv_create(struct drm_connector *connector, struct dcb_entry *entry) { + struct drm_device *dev = connector->dev; struct drm_encoder *encoder; struct nv17_tv_encoder *tv_enc = NULL; @@ -774,5 +807,7 @@ int nv17_tv_create(struct drm_device *dev, struct dcb_entry *entry) encoder->possible_crtcs = entry->heads; encoder->possible_clones = 0; + nv17_tv_create_resources(encoder, connector); + drm_mode_connector_attach_encoder(connector, encoder); return 0; } diff --git a/drivers/gpu/drm/nouveau/nv20_graph.c b/drivers/gpu/drm/nouveau/nv20_graph.c index d6fc0a8..17f309b 100644 --- a/drivers/gpu/drm/nouveau/nv20_graph.c +++ b/drivers/gpu/drm/nouveau/nv20_graph.c @@ -370,68 +370,54 @@ nv20_graph_create_context(struct nouveau_channel *chan) { struct drm_device *dev = chan->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; void (*ctx_init)(struct drm_device *, struct nouveau_gpuobj *); - unsigned int ctx_size; unsigned int idoffs = 0x28/4; int ret; switch (dev_priv->chipset) { case 0x20: - ctx_size = NV20_GRCTX_SIZE; ctx_init = nv20_graph_context_init; idoffs = 0; break; case 0x25: case 0x28: - ctx_size = NV25_GRCTX_SIZE; ctx_init = nv25_graph_context_init; break; case 0x2a: - ctx_size = NV2A_GRCTX_SIZE; ctx_init = nv2a_graph_context_init; idoffs = 0; break; case 0x30: case 0x31: - ctx_size = NV30_31_GRCTX_SIZE; ctx_init = nv30_31_graph_context_init; break; case 0x34: - ctx_size = NV34_GRCTX_SIZE; ctx_init = nv34_graph_context_init; break; case 0x35: case 0x36: - ctx_size = NV35_36_GRCTX_SIZE; ctx_init = nv35_36_graph_context_init; break; default: - ctx_size = 0; - ctx_init = nv35_36_graph_context_init; - NV_ERROR(dev, "Please contact the devs if you want your NV%x" - " card to work\n", dev_priv->chipset); - return -ENOSYS; - break; + BUG_ON(1); } - ret = nouveau_gpuobj_new_ref(dev, chan, NULL, 0, ctx_size, 16, - NVOBJ_FLAG_ZERO_ALLOC, - &chan->ramin_grctx); + ret = nouveau_gpuobj_new_ref(dev, chan, NULL, 0, pgraph->grctx_size, + 16, NVOBJ_FLAG_ZERO_ALLOC, + &chan->ramin_grctx); if (ret) return ret; /* Initialise default context values */ - dev_priv->engine.instmem.prepare_access(dev, true); ctx_init(dev, chan->ramin_grctx->gpuobj); /* nv20: nv_wo32(dev, chan->ramin_grctx->gpuobj, 10, chan->id<<24); */ nv_wo32(dev, chan->ramin_grctx->gpuobj, idoffs, (chan->id << 24) | 0x1); /* CTX_USER */ - nv_wo32(dev, dev_priv->ctx_table->gpuobj, chan->id, - chan->ramin_grctx->instance >> 4); - - dev_priv->engine.instmem.finish_access(dev); + nv_wo32(dev, pgraph->ctx_table->gpuobj, chan->id, + chan->ramin_grctx->instance >> 4); return 0; } @@ -440,13 +426,12 @@ nv20_graph_destroy_context(struct nouveau_channel *chan) { struct drm_device *dev = chan->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; if (chan->ramin_grctx) nouveau_gpuobj_ref_del(dev, &chan->ramin_grctx); - dev_priv->engine.instmem.prepare_access(dev, true); - nv_wo32(dev, dev_priv->ctx_table->gpuobj, chan->id, 0); - dev_priv->engine.instmem.finish_access(dev); + nv_wo32(dev, pgraph->ctx_table->gpuobj, chan->id, 0); } int @@ -538,29 +523,44 @@ nv20_graph_set_region_tiling(struct drm_device *dev, int i, uint32_t addr, int nv20_graph_init(struct drm_device *dev) { - struct drm_nouveau_private *dev_priv = - (struct drm_nouveau_private *)dev->dev_private; + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; uint32_t tmp, vramsz; int ret, i; + switch (dev_priv->chipset) { + case 0x20: + pgraph->grctx_size = NV20_GRCTX_SIZE; + break; + case 0x25: + case 0x28: + pgraph->grctx_size = NV25_GRCTX_SIZE; + break; + case 0x2a: + pgraph->grctx_size = NV2A_GRCTX_SIZE; + break; + default: + NV_ERROR(dev, "unknown chipset, disabling acceleration\n"); + pgraph->accel_blocked = true; + return 0; + } + nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) & ~NV_PMC_ENABLE_PGRAPH); nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) | NV_PMC_ENABLE_PGRAPH); - if (!dev_priv->ctx_table) { + if (!pgraph->ctx_table) { /* Create Context Pointer Table */ - dev_priv->ctx_table_size = 32 * 4; - ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0, - dev_priv->ctx_table_size, 16, + ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0, 32 * 4, 16, NVOBJ_FLAG_ZERO_ALLOC, - &dev_priv->ctx_table); + &pgraph->ctx_table); if (ret) return ret; } nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_TABLE, - dev_priv->ctx_table->instance >> 4); + pgraph->ctx_table->instance >> 4); nv20_graph_rdi(dev); @@ -616,7 +616,7 @@ nv20_graph_init(struct drm_device *dev) nv_wr32(dev, NV10_PGRAPH_SURFACE, tmp); /* begin RAM config */ - vramsz = drm_get_resource_len(dev, 0) - 1; + vramsz = pci_resource_len(dev->pdev, 0) - 1; nv_wr32(dev, 0x4009A4, nv_rd32(dev, NV04_PFB_CFG0)); nv_wr32(dev, 0x4009A8, nv_rd32(dev, NV04_PFB_CFG1)); nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00EA0000); @@ -644,34 +644,52 @@ void nv20_graph_takedown(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; - nouveau_gpuobj_ref_del(dev, &dev_priv->ctx_table); + nouveau_gpuobj_ref_del(dev, &pgraph->ctx_table); } int nv30_graph_init(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; int ret, i; + switch (dev_priv->chipset) { + case 0x30: + case 0x31: + pgraph->grctx_size = NV30_31_GRCTX_SIZE; + break; + case 0x34: + pgraph->grctx_size = NV34_GRCTX_SIZE; + break; + case 0x35: + case 0x36: + pgraph->grctx_size = NV35_36_GRCTX_SIZE; + break; + default: + NV_ERROR(dev, "unknown chipset, disabling acceleration\n"); + pgraph->accel_blocked = true; + return 0; + } + nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) & ~NV_PMC_ENABLE_PGRAPH); nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) | NV_PMC_ENABLE_PGRAPH); - if (!dev_priv->ctx_table) { + if (!pgraph->ctx_table) { /* Create Context Pointer Table */ - dev_priv->ctx_table_size = 32 * 4; - ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0, - dev_priv->ctx_table_size, 16, + ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0, 32 * 4, 16, NVOBJ_FLAG_ZERO_ALLOC, - &dev_priv->ctx_table); + &pgraph->ctx_table); if (ret) return ret; } nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_TABLE, - dev_priv->ctx_table->instance >> 4); + pgraph->ctx_table->instance >> 4); nv_wr32(dev, NV03_PGRAPH_INTR , 0xFFFFFFFF); nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF); @@ -717,7 +735,7 @@ nv30_graph_init(struct drm_device *dev) nv_wr32(dev, 0x0040075c , 0x00000001); /* begin RAM config */ - /* vramsz = drm_get_resource_len(dev, 0) - 1; */ + /* vramsz = pci_resource_len(dev->pdev, 0) - 1; */ nv_wr32(dev, 0x4009A4, nv_rd32(dev, NV04_PFB_CFG0)); nv_wr32(dev, 0x4009A8, nv_rd32(dev, NV04_PFB_CFG1)); if (dev_priv->chipset != 0x34) { diff --git a/drivers/gpu/drm/nouveau/nv30_fb.c b/drivers/gpu/drm/nouveau/nv30_fb.c new file mode 100644 index 0000000..9d35c8b --- /dev/null +++ b/drivers/gpu/drm/nouveau/nv30_fb.c @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2010 Francisco Jerez. + * 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 "drmP.h" +#include "drm.h" +#include "nouveau_drv.h" +#include "nouveau_drm.h" + +static int +calc_ref(int b, int l, int i) +{ + int j, x = 0; + + for (j = 0; j < 4; j++) { + int n = (b >> (8 * j) & 0xf); + int m = (l >> (8 * i) & 0xff) + 2 * (n & 0x8 ? n - 0x10 : n); + + x |= (0x80 | (m & 0x1f)) << (8 * j); + } + + return x; +} + +int +nv30_fb_init(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_fb_engine *pfb = &dev_priv->engine.fb; + int i, j; + + pfb->num_tiles = NV10_PFB_TILE__SIZE; + + /* Turn all the tiling regions off. */ + for (i = 0; i < pfb->num_tiles; i++) + pfb->set_region_tiling(dev, i, 0, 0, 0); + + /* Init the memory timing regs at 0x10037c/0x1003ac */ + if (dev_priv->chipset == 0x30 || + dev_priv->chipset == 0x31 || + dev_priv->chipset == 0x35) { + /* Related to ROP count */ + int n = (dev_priv->chipset == 0x31 ? 2 : 4); + int b = (dev_priv->chipset > 0x30 ? + nv_rd32(dev, 0x122c) & 0xf : 0); + int l = nv_rd32(dev, 0x1003d0); + + for (i = 0; i < n; i++) { + for (j = 0; j < 3; j++) + nv_wr32(dev, 0x10037c + 0xc * i + 0x4 * j, + calc_ref(b, l, j)); + + for (j = 0; j < 2; j++) + nv_wr32(dev, 0x1003ac + 0x8 * i + 0x4 * j, + calc_ref(b, l, j)); + } + } + + return 0; +} + +void +nv30_fb_takedown(struct drm_device *dev) +{ +} diff --git a/drivers/gpu/drm/nouveau/nv40_fifo.c b/drivers/gpu/drm/nouveau/nv40_fifo.c index 500ccfd..2b67f18 100644 --- a/drivers/gpu/drm/nouveau/nv40_fifo.c +++ b/drivers/gpu/drm/nouveau/nv40_fifo.c @@ -48,7 +48,6 @@ nv40_fifo_create_context(struct nouveau_channel *chan) spin_lock_irqsave(&dev_priv->context_switch_lock, flags); - dev_priv->engine.instmem.prepare_access(dev, true); nv_wi32(dev, fc + 0, chan->pushbuf_base); nv_wi32(dev, fc + 4, chan->pushbuf_base); nv_wi32(dev, fc + 12, chan->pushbuf->instance >> 4); @@ -61,7 +60,6 @@ nv40_fifo_create_context(struct nouveau_channel *chan) 0x30000000 /* no idea.. */); nv_wi32(dev, fc + 56, chan->ramin_grctx->instance >> 4); nv_wi32(dev, fc + 60, 0x0001FFFF); - dev_priv->engine.instmem.finish_access(dev); /* enable the fifo dma operation */ nv_wr32(dev, NV04_PFIFO_MODE, @@ -89,8 +87,6 @@ nv40_fifo_do_load_context(struct drm_device *dev, int chid) struct drm_nouveau_private *dev_priv = dev->dev_private; uint32_t fc = NV40_RAMFC(chid), tmp, tmp2; - dev_priv->engine.instmem.prepare_access(dev, false); - nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_PUT, nv_ri32(dev, fc + 0)); nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_GET, nv_ri32(dev, fc + 4)); nv_wr32(dev, NV10_PFIFO_CACHE1_REF_CNT, nv_ri32(dev, fc + 8)); @@ -127,8 +123,6 @@ nv40_fifo_do_load_context(struct drm_device *dev, int chid) nv_wr32(dev, 0x2088, nv_ri32(dev, fc + 76)); nv_wr32(dev, 0x3300, nv_ri32(dev, fc + 80)); - dev_priv->engine.instmem.finish_access(dev); - nv_wr32(dev, NV03_PFIFO_CACHE1_GET, 0); nv_wr32(dev, NV03_PFIFO_CACHE1_PUT, 0); } @@ -166,7 +160,6 @@ nv40_fifo_unload_context(struct drm_device *dev) return 0; fc = NV40_RAMFC(chid); - dev_priv->engine.instmem.prepare_access(dev, true); nv_wi32(dev, fc + 0, nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_PUT)); nv_wi32(dev, fc + 4, nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_GET)); nv_wi32(dev, fc + 8, nv_rd32(dev, NV10_PFIFO_CACHE1_REF_CNT)); @@ -200,7 +193,6 @@ nv40_fifo_unload_context(struct drm_device *dev) tmp |= (nv_rd32(dev, NV04_PFIFO_CACHE1_PUT) << 16); nv_wi32(dev, fc + 72, tmp); #endif - dev_priv->engine.instmem.finish_access(dev); nv40_fifo_do_load_context(dev, pfifo->channels - 1); nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH1, diff --git a/drivers/gpu/drm/nouveau/nv40_graph.c b/drivers/gpu/drm/nouveau/nv40_graph.c index 704a25d..fd7d2b5 100644 --- a/drivers/gpu/drm/nouveau/nv40_graph.c +++ b/drivers/gpu/drm/nouveau/nv40_graph.c @@ -58,6 +58,7 @@ nv40_graph_create_context(struct nouveau_channel *chan) struct drm_device *dev = chan->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; + struct nouveau_grctx ctx = {}; int ret; ret = nouveau_gpuobj_new_ref(dev, chan, NULL, 0, pgraph->grctx_size, @@ -67,20 +68,13 @@ nv40_graph_create_context(struct nouveau_channel *chan) return ret; /* Initialise default context values */ - dev_priv->engine.instmem.prepare_access(dev, true); - if (!pgraph->ctxprog) { - struct nouveau_grctx ctx = {}; - - ctx.dev = chan->dev; - ctx.mode = NOUVEAU_GRCTX_VALS; - ctx.data = chan->ramin_grctx->gpuobj; - nv40_grctx_init(&ctx); - } else { - nouveau_grctx_vals_load(dev, chan->ramin_grctx->gpuobj); - } + ctx.dev = chan->dev; + ctx.mode = NOUVEAU_GRCTX_VALS; + ctx.data = chan->ramin_grctx->gpuobj; + nv40_grctx_init(&ctx); + nv_wo32(dev, chan->ramin_grctx->gpuobj, 0, chan->ramin_grctx->gpuobj->im_pramin->start); - dev_priv->engine.instmem.finish_access(dev); return 0; } @@ -238,7 +232,8 @@ nv40_graph_init(struct drm_device *dev) struct drm_nouveau_private *dev_priv = (struct drm_nouveau_private *)dev->dev_private; struct nouveau_fb_engine *pfb = &dev_priv->engine.fb; - uint32_t vramsz; + struct nouveau_grctx ctx = {}; + uint32_t vramsz, *cp; int i, j; nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) & @@ -246,32 +241,22 @@ nv40_graph_init(struct drm_device *dev) nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) | NV_PMC_ENABLE_PGRAPH); - if (nouveau_ctxfw) { - nouveau_grctx_prog_load(dev); - dev_priv->engine.graph.grctx_size = 175 * 1024; - } + cp = kmalloc(sizeof(*cp) * 256, GFP_KERNEL); + if (!cp) + return -ENOMEM; - if (!dev_priv->engine.graph.ctxprog) { - struct nouveau_grctx ctx = {}; - uint32_t *cp; + ctx.dev = dev; + ctx.mode = NOUVEAU_GRCTX_PROG; + ctx.data = cp; + ctx.ctxprog_max = 256; + nv40_grctx_init(&ctx); + dev_priv->engine.graph.grctx_size = ctx.ctxvals_pos * 4; - cp = kmalloc(sizeof(*cp) * 256, GFP_KERNEL); - if (!cp) - return -ENOMEM; + nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_INDEX, 0); + for (i = 0; i < ctx.ctxprog_len; i++) + nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_DATA, cp[i]); - ctx.dev = dev; - ctx.mode = NOUVEAU_GRCTX_PROG; - ctx.data = cp; - ctx.ctxprog_max = 256; - nv40_grctx_init(&ctx); - dev_priv->engine.graph.grctx_size = ctx.ctxvals_pos * 4; - - nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_INDEX, 0); - for (i = 0; i < ctx.ctxprog_len; i++) - nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_DATA, cp[i]); - - kfree(cp); - } + kfree(cp); /* No context present currently */ nv_wr32(dev, NV40_PGRAPH_CTXCTL_CUR, 0x00000000); @@ -367,7 +352,7 @@ nv40_graph_init(struct drm_device *dev) nv40_graph_set_region_tiling(dev, i, 0, 0, 0); /* begin RAM config */ - vramsz = drm_get_resource_len(dev, 0) - 1; + vramsz = pci_resource_len(dev->pdev, 0) - 1; switch (dev_priv->chipset) { case 0x40: nv_wr32(dev, 0x4009A4, nv_rd32(dev, NV04_PFB_CFG0)); @@ -407,7 +392,6 @@ nv40_graph_init(struct drm_device *dev) void nv40_graph_takedown(struct drm_device *dev) { - nouveau_grctx_fini(dev); } struct nouveau_pgraph_object_class nv40_graph_grclass[] = { diff --git a/drivers/gpu/drm/nouveau/nv40_mc.c b/drivers/gpu/drm/nouveau/nv40_mc.c index 2a3495e..e4e72c1 100644 --- a/drivers/gpu/drm/nouveau/nv40_mc.c +++ b/drivers/gpu/drm/nouveau/nv40_mc.c @@ -19,7 +19,7 @@ nv40_mc_init(struct drm_device *dev) case 0x46: /* G72 */ case 0x4e: case 0x4c: /* C51_G7X */ - tmp = nv_rd32(dev, NV40_PFB_020C); + tmp = nv_rd32(dev, NV04_PFB_FIFO_DATA); nv_wr32(dev, NV40_PMC_1700, tmp); nv_wr32(dev, NV40_PMC_1704, 0); nv_wr32(dev, NV40_PMC_1708, 0); diff --git a/drivers/gpu/drm/nouveau/nv50_crtc.c b/drivers/gpu/drm/nouveau/nv50_crtc.c index b4e4a3b..5d11ea1 100644 --- a/drivers/gpu/drm/nouveau/nv50_crtc.c +++ b/drivers/gpu/drm/nouveau/nv50_crtc.c @@ -440,47 +440,15 @@ nv50_crtc_prepare(struct drm_crtc *crtc) { struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); struct drm_device *dev = crtc->dev; - struct drm_encoder *encoder; - uint32_t dac = 0, sor = 0; NV_DEBUG_KMS(dev, "index %d\n", nv_crtc->index); - /* Disconnect all unused encoders. */ - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { - struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); - - if (!drm_helper_encoder_in_use(encoder)) - continue; - - if (nv_encoder->dcb->type == OUTPUT_ANALOG || - nv_encoder->dcb->type == OUTPUT_TV) - dac |= (1 << nv_encoder->or); - else - sor |= (1 << nv_encoder->or); - } - - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { - struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); - - if (nv_encoder->dcb->type == OUTPUT_ANALOG || - nv_encoder->dcb->type == OUTPUT_TV) { - if (dac & (1 << nv_encoder->or)) - continue; - } else { - if (sor & (1 << nv_encoder->or)) - continue; - } - - nv_encoder->disconnect(nv_encoder); - } - nv50_crtc_blank(nv_crtc, true); } static void nv50_crtc_commit(struct drm_crtc *crtc) { - struct drm_crtc *crtc2; struct drm_device *dev = crtc->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_channel *evo = dev_priv->evo; @@ -491,20 +459,14 @@ nv50_crtc_commit(struct drm_crtc *crtc) nv50_crtc_blank(nv_crtc, false); - /* Explicitly blank all unused crtc's. */ - list_for_each_entry(crtc2, &dev->mode_config.crtc_list, head) { - if (!drm_helper_crtc_in_use(crtc2)) - nv50_crtc_blank(nouveau_crtc(crtc2), true); - } - ret = RING_SPACE(evo, 2); if (ret) { NV_ERROR(dev, "no space while committing crtc\n"); return; } BEGIN_RING(evo, 0, NV50_EVO_UPDATE, 1); - OUT_RING(evo, 0); - FIRE_RING(evo); + OUT_RING (evo, 0); + FIRE_RING (evo); } static bool diff --git a/drivers/gpu/drm/nouveau/nv50_dac.c b/drivers/gpu/drm/nouveau/nv50_dac.c index 1fd9537..1bc0859 100644 --- a/drivers/gpu/drm/nouveau/nv50_dac.c +++ b/drivers/gpu/drm/nouveau/nv50_dac.c @@ -37,22 +37,31 @@ #include "nv50_display.h" static void -nv50_dac_disconnect(struct nouveau_encoder *nv_encoder) +nv50_dac_disconnect(struct drm_encoder *encoder) { - struct drm_device *dev = to_drm_encoder(nv_encoder)->dev; + struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); + struct drm_device *dev = encoder->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_channel *evo = dev_priv->evo; int ret; + if (!nv_encoder->crtc) + return; + nv50_crtc_blank(nouveau_crtc(nv_encoder->crtc), true); + NV_DEBUG_KMS(dev, "Disconnecting DAC %d\n", nv_encoder->or); - ret = RING_SPACE(evo, 2); + ret = RING_SPACE(evo, 4); if (ret) { NV_ERROR(dev, "no space while disconnecting DAC\n"); return; } BEGIN_RING(evo, 0, NV50_EVO_DAC(nv_encoder->or, MODE_CTRL), 1); - OUT_RING(evo, 0); + OUT_RING (evo, 0); + BEGIN_RING(evo, 0, NV50_EVO_UPDATE, 1); + OUT_RING (evo, 0); + + nv_encoder->crtc = NULL; } static enum drm_connector_status @@ -213,7 +222,8 @@ nv50_dac_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, uint32_t mode_ctl = 0, mode_ctl2 = 0; int ret; - NV_DEBUG_KMS(dev, "or %d\n", nv_encoder->or); + NV_DEBUG_KMS(dev, "or %d type %d crtc %d\n", + nv_encoder->or, nv_encoder->dcb->type, crtc->index); nv50_dac_dpms(encoder, DRM_MODE_DPMS_ON); @@ -243,6 +253,14 @@ nv50_dac_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, BEGIN_RING(evo, 0, NV50_EVO_DAC(nv_encoder->or, MODE_CTRL), 2); OUT_RING(evo, mode_ctl); OUT_RING(evo, mode_ctl2); + + nv_encoder->crtc = encoder->crtc; +} + +static struct drm_crtc * +nv50_dac_crtc_get(struct drm_encoder *encoder) +{ + return nouveau_encoder(encoder)->crtc; } static const struct drm_encoder_helper_funcs nv50_dac_helper_funcs = { @@ -253,7 +271,9 @@ static const struct drm_encoder_helper_funcs nv50_dac_helper_funcs = { .prepare = nv50_dac_prepare, .commit = nv50_dac_commit, .mode_set = nv50_dac_mode_set, - .detect = nv50_dac_detect + .get_crtc = nv50_dac_crtc_get, + .detect = nv50_dac_detect, + .disable = nv50_dac_disconnect }; static void @@ -275,14 +295,11 @@ static const struct drm_encoder_funcs nv50_dac_encoder_funcs = { }; int -nv50_dac_create(struct drm_device *dev, struct dcb_entry *entry) +nv50_dac_create(struct drm_connector *connector, struct dcb_entry *entry) { struct nouveau_encoder *nv_encoder; struct drm_encoder *encoder; - NV_DEBUG_KMS(dev, "\n"); - NV_INFO(dev, "Detected a DAC output\n"); - nv_encoder = kzalloc(sizeof(*nv_encoder), GFP_KERNEL); if (!nv_encoder) return -ENOMEM; @@ -291,14 +308,14 @@ nv50_dac_create(struct drm_device *dev, struct dcb_entry *entry) nv_encoder->dcb = entry; nv_encoder->or = ffs(entry->or) - 1; - nv_encoder->disconnect = nv50_dac_disconnect; - - drm_encoder_init(dev, encoder, &nv50_dac_encoder_funcs, + drm_encoder_init(connector->dev, encoder, &nv50_dac_encoder_funcs, DRM_MODE_ENCODER_DAC); drm_encoder_helper_add(encoder, &nv50_dac_helper_funcs); encoder->possible_crtcs = entry->heads; encoder->possible_clones = 0; + + drm_mode_connector_attach_encoder(connector, encoder); return 0; } diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index 580a5d1..f13ad0d 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -71,14 +71,13 @@ nv50_evo_dmaobj_new(struct nouveau_channel *evo, uint32_t class, uint32_t name, return ret; } - dev_priv->engine.instmem.prepare_access(dev, true); nv_wo32(dev, obj, 0, (tile_flags << 22) | (magic_flags << 16) | class); nv_wo32(dev, obj, 1, limit); nv_wo32(dev, obj, 2, offset); nv_wo32(dev, obj, 3, 0x00000000); nv_wo32(dev, obj, 4, 0x00000000); nv_wo32(dev, obj, 5, 0x00010000); - dev_priv->engine.instmem.finish_access(dev); + dev_priv->engine.instmem.flush(dev); return 0; } @@ -110,8 +109,8 @@ nv50_evo_channel_new(struct drm_device *dev, struct nouveau_channel **pchan) return ret; } - ret = nouveau_mem_init_heap(&chan->ramin_heap, chan->ramin->gpuobj-> - im_pramin->start, 32768); + ret = drm_mm_init(&chan->ramin_heap, + chan->ramin->gpuobj->im_pramin->start, 32768); if (ret) { NV_ERROR(dev, "Error initialising EVO PRAMIN heap: %d\n", ret); nv50_evo_channel_del(pchan); @@ -179,13 +178,25 @@ nv50_evo_channel_new(struct drm_device *dev, struct nouveau_channel **pchan) } int +nv50_display_early_init(struct drm_device *dev) +{ + return 0; +} + +void +nv50_display_late_takedown(struct drm_device *dev) +{ +} + +int nv50_display_init(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_timer_engine *ptimer = &dev_priv->engine.timer; + struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio; struct nouveau_channel *evo = dev_priv->evo; struct drm_connector *connector; - uint32_t val, ram_amount, hpd_en[2]; + uint32_t val, ram_amount; uint64_t start; int ret, i; @@ -366,26 +377,13 @@ nv50_display_init(struct drm_device *dev) NV50_PDISPLAY_INTR_EN_CLK_UNK40)); /* enable hotplug interrupts */ - hpd_en[0] = hpd_en[1] = 0; list_for_each_entry(connector, &dev->mode_config.connector_list, head) { struct nouveau_connector *conn = nouveau_connector(connector); - struct dcb_gpio_entry *gpio; if (conn->dcb->gpio_tag == 0xff) continue; - gpio = nouveau_bios_gpio_entry(dev, conn->dcb->gpio_tag); - if (!gpio) - continue; - - hpd_en[gpio->line >> 4] |= (0x00010001 << (gpio->line & 0xf)); - } - - nv_wr32(dev, 0xe054, 0xffffffff); - nv_wr32(dev, 0xe050, hpd_en[0]); - if (dev_priv->chipset >= 0x90) { - nv_wr32(dev, 0xe074, 0xffffffff); - nv_wr32(dev, 0xe070, hpd_en[1]); + pgpio->irq_enable(dev, conn->dcb->gpio_tag, true); } return 0; @@ -465,6 +463,7 @@ int nv50_display_create(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; struct dcb_table *dcb = &dev_priv->vbios.dcb; + struct drm_connector *connector, *ct; int ret, i; NV_DEBUG_KMS(dev, "\n"); @@ -507,14 +506,18 @@ int nv50_display_create(struct drm_device *dev) continue; } + connector = nouveau_connector_create(dev, entry->connector); + if (IS_ERR(connector)) + continue; + switch (entry->type) { case OUTPUT_TMDS: case OUTPUT_LVDS: case OUTPUT_DP: - nv50_sor_create(dev, entry); + nv50_sor_create(connector, entry); break; case OUTPUT_ANALOG: - nv50_dac_create(dev, entry); + nv50_dac_create(connector, entry); break; default: NV_WARN(dev, "DCB encoder %d unknown\n", entry->type); @@ -522,11 +525,13 @@ int nv50_display_create(struct drm_device *dev) } } - for (i = 0 ; i < dcb->connector.entries; i++) { - if (i != 0 && dcb->connector.entry[i].index2 == - dcb->connector.entry[i - 1].index2) - continue; - nouveau_connector_create(dev, &dcb->connector.entry[i]); + list_for_each_entry_safe(connector, ct, + &dev->mode_config.connector_list, head) { + if (!connector->encoder_ids[0]) { + NV_WARN(dev, "%s has no encoders, removing\n", + drm_get_connector_name(connector)); + connector->funcs->destroy(connector); + } } ret = nv50_display_init(dev); @@ -538,7 +543,8 @@ int nv50_display_create(struct drm_device *dev) return 0; } -int nv50_display_destroy(struct drm_device *dev) +void +nv50_display_destroy(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; @@ -548,135 +554,30 @@ int nv50_display_destroy(struct drm_device *dev) nv50_display_disable(dev); nv50_evo_channel_del(&dev_priv->evo); - - return 0; -} - -static inline uint32_t -nv50_display_mode_ctrl(struct drm_device *dev, bool sor, int or) -{ - struct drm_nouveau_private *dev_priv = dev->dev_private; - uint32_t mc; - - if (sor) { - if (dev_priv->chipset < 0x90 || - dev_priv->chipset == 0x92 || dev_priv->chipset == 0xa0) - mc = nv_rd32(dev, NV50_PDISPLAY_SOR_MODE_CTRL_P(or)); - else - mc = nv_rd32(dev, NV90_PDISPLAY_SOR_MODE_CTRL_P(or)); - } else { - mc = nv_rd32(dev, NV50_PDISPLAY_DAC_MODE_CTRL_P(or)); - } - - return mc; -} - -static int -nv50_display_irq_head(struct drm_device *dev, int *phead, - struct dcb_entry **pdcbent) -{ - struct drm_nouveau_private *dev_priv = dev->dev_private; - uint32_t unk30 = nv_rd32(dev, NV50_PDISPLAY_UNK30_CTRL); - uint32_t dac = 0, sor = 0; - int head, i, or = 0, type = OUTPUT_ANY; - - /* We're assuming that head 0 *or* head 1 will be active here, - * and not both. I'm not sure if the hw will even signal both - * ever, but it definitely shouldn't for us as we commit each - * CRTC separately, and submission will be blocked by the GPU - * until we handle each in turn. - */ - NV_DEBUG_KMS(dev, "0x610030: 0x%08x\n", unk30); - head = ffs((unk30 >> 9) & 3) - 1; - if (head < 0) - return -EINVAL; - - /* This assumes CRTCs are never bound to multiple encoders, which - * should be the case. - */ - for (i = 0; i < 3 && type == OUTPUT_ANY; i++) { - uint32_t mc = nv50_display_mode_ctrl(dev, false, i); - if (!(mc & (1 << head))) - continue; - - switch ((mc >> 8) & 0xf) { - case 0: type = OUTPUT_ANALOG; break; - case 1: type = OUTPUT_TV; break; - default: - NV_ERROR(dev, "unknown dac mode_ctrl: 0x%08x\n", dac); - return -1; - } - - or = i; - } - - for (i = 0; i < 4 && type == OUTPUT_ANY; i++) { - uint32_t mc = nv50_display_mode_ctrl(dev, true, i); - if (!(mc & (1 << head))) - continue; - - switch ((mc >> 8) & 0xf) { - case 0: type = OUTPUT_LVDS; break; - case 1: type = OUTPUT_TMDS; break; - case 2: type = OUTPUT_TMDS; break; - case 5: type = OUTPUT_TMDS; break; - case 8: type = OUTPUT_DP; break; - case 9: type = OUTPUT_DP; break; - default: - NV_ERROR(dev, "unknown sor mode_ctrl: 0x%08x\n", sor); - return -1; - } - - or = i; - } - - NV_DEBUG_KMS(dev, "type %d, or %d\n", type, or); - if (type == OUTPUT_ANY) { - NV_ERROR(dev, "unknown encoder!!\n"); - return -1; - } - - for (i = 0; i < dev_priv->vbios.dcb.entries; i++) { - struct dcb_entry *dcbent = &dev_priv->vbios.dcb.entry[i]; - - if (dcbent->type != type) - continue; - - if (!(dcbent->or & (1 << or))) - continue; - - *phead = head; - *pdcbent = dcbent; - return 0; - } - - NV_ERROR(dev, "no DCB entry for %d %d\n", dac != 0, or); - return 0; } -static uint32_t -nv50_display_script_select(struct drm_device *dev, struct dcb_entry *dcbent, - int pxclk) +static u16 +nv50_display_script_select(struct drm_device *dev, struct dcb_entry *dcb, + u32 mc, int pxclk) { struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_connector *nv_connector = NULL; struct drm_encoder *encoder; struct nvbios *bios = &dev_priv->vbios; - uint32_t mc, script = 0, or; + u32 script = 0, or; list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); - if (nv_encoder->dcb != dcbent) + if (nv_encoder->dcb != dcb) continue; nv_connector = nouveau_encoder_connector_get(nv_encoder); break; } - or = ffs(dcbent->or) - 1; - mc = nv50_display_mode_ctrl(dev, dcbent->type != OUTPUT_ANALOG, or); - switch (dcbent->type) { + or = ffs(dcb->or) - 1; + switch (dcb->type) { case OUTPUT_LVDS: script = (mc >> 8) & 0xf; if (bios->fp_no_ddc) { @@ -767,17 +668,88 @@ nv50_display_vblank_handler(struct drm_device *dev, uint32_t intr) static void nv50_display_unk10_handler(struct drm_device *dev) { - struct dcb_entry *dcbent; - int head, ret; + struct drm_nouveau_private *dev_priv = dev->dev_private; + u32 unk30 = nv_rd32(dev, 0x610030), mc; + int i, crtc, or, type = OUTPUT_ANY; - ret = nv50_display_irq_head(dev, &head, &dcbent); - if (ret) - goto ack; + NV_DEBUG_KMS(dev, "0x610030: 0x%08x\n", unk30); + dev_priv->evo_irq.dcb = NULL; nv_wr32(dev, 0x619494, nv_rd32(dev, 0x619494) & ~8); - nouveau_bios_run_display_table(dev, dcbent, 0, -1); + /* Determine which CRTC we're dealing with, only 1 ever will be + * signalled at the same time with the current nouveau code. + */ + crtc = ffs((unk30 & 0x00000060) >> 5) - 1; + if (crtc < 0) + goto ack; + + /* Nothing needs to be done for the encoder */ + crtc = ffs((unk30 & 0x00000180) >> 7) - 1; + if (crtc < 0) + goto ack; + /* Find which encoder was connected to the CRTC */ + for (i = 0; type == OUTPUT_ANY && i < 3; i++) { + mc = nv_rd32(dev, NV50_PDISPLAY_DAC_MODE_CTRL_C(i)); + NV_DEBUG_KMS(dev, "DAC-%d mc: 0x%08x\n", i, mc); + if (!(mc & (1 << crtc))) + continue; + + switch ((mc & 0x00000f00) >> 8) { + case 0: type = OUTPUT_ANALOG; break; + case 1: type = OUTPUT_TV; break; + default: + NV_ERROR(dev, "invalid mc, DAC-%d: 0x%08x\n", i, mc); + goto ack; + } + + or = i; + } + + for (i = 0; type == OUTPUT_ANY && i < 4; i++) { + if (dev_priv->chipset < 0x90 || + dev_priv->chipset == 0x92 || + dev_priv->chipset == 0xa0) + mc = nv_rd32(dev, NV50_PDISPLAY_SOR_MODE_CTRL_C(i)); + else + mc = nv_rd32(dev, NV90_PDISPLAY_SOR_MODE_CTRL_C(i)); + + NV_DEBUG_KMS(dev, "SOR-%d mc: 0x%08x\n", i, mc); + if (!(mc & (1 << crtc))) + continue; + + switch ((mc & 0x00000f00) >> 8) { + case 0: type = OUTPUT_LVDS; break; + case 1: type = OUTPUT_TMDS; break; + case 2: type = OUTPUT_TMDS; break; + case 5: type = OUTPUT_TMDS; break; + case 8: type = OUTPUT_DP; break; + case 9: type = OUTPUT_DP; break; + default: + NV_ERROR(dev, "invalid mc, SOR-%d: 0x%08x\n", i, mc); + goto ack; + } + + or = i; + } + + /* There was no encoder to disable */ + if (type == OUTPUT_ANY) + goto ack; + + /* Disable the encoder */ + for (i = 0; i < dev_priv->vbios.dcb.entries; i++) { + struct dcb_entry *dcb = &dev_priv->vbios.dcb.entry[i]; + + if (dcb->type == type && (dcb->or & (1 << or))) { + nouveau_bios_run_display_table(dev, dcb, 0, -1); + dev_priv->evo_irq.dcb = dcb; + goto ack; + } + } + + NV_ERROR(dev, "no dcb for %d %d 0x%08x\n", or, type, mc); ack: nv_wr32(dev, NV50_PDISPLAY_INTR_1, NV50_PDISPLAY_INTR_1_CLK_UNK10); nv_wr32(dev, 0x610030, 0x80000000); @@ -817,33 +789,103 @@ nv50_display_unk20_dp_hack(struct drm_device *dev, struct dcb_entry *dcb) static void nv50_display_unk20_handler(struct drm_device *dev) { - struct dcb_entry *dcbent; - uint32_t tmp, pclk, script; - int head, or, ret; + struct drm_nouveau_private *dev_priv = dev->dev_private; + u32 unk30 = nv_rd32(dev, 0x610030), tmp, pclk, script, mc; + struct dcb_entry *dcb; + int i, crtc, or, type = OUTPUT_ANY; - ret = nv50_display_irq_head(dev, &head, &dcbent); - if (ret) + NV_DEBUG_KMS(dev, "0x610030: 0x%08x\n", unk30); + dcb = dev_priv->evo_irq.dcb; + if (dcb) { + nouveau_bios_run_display_table(dev, dcb, 0, -2); + dev_priv->evo_irq.dcb = NULL; + } + + /* CRTC clock change requested? */ + crtc = ffs((unk30 & 0x00000600) >> 9) - 1; + if (crtc >= 0) { + pclk = nv_rd32(dev, NV50_PDISPLAY_CRTC_P(crtc, CLOCK)); + pclk &= 0x003fffff; + + nv50_crtc_set_clock(dev, crtc, pclk); + + tmp = nv_rd32(dev, NV50_PDISPLAY_CRTC_CLK_CTRL2(crtc)); + tmp &= ~0x000000f; + nv_wr32(dev, NV50_PDISPLAY_CRTC_CLK_CTRL2(crtc), tmp); + } + + /* Nothing needs to be done for the encoder */ + crtc = ffs((unk30 & 0x00000180) >> 7) - 1; + if (crtc < 0) goto ack; - or = ffs(dcbent->or) - 1; - pclk = nv_rd32(dev, NV50_PDISPLAY_CRTC_P(head, CLOCK)) & 0x3fffff; - script = nv50_display_script_select(dev, dcbent, pclk); + pclk = nv_rd32(dev, NV50_PDISPLAY_CRTC_P(crtc, CLOCK)) & 0x003fffff; - NV_DEBUG_KMS(dev, "head %d pxclk: %dKHz\n", head, pclk); + /* Find which encoder is connected to the CRTC */ + for (i = 0; type == OUTPUT_ANY && i < 3; i++) { + mc = nv_rd32(dev, NV50_PDISPLAY_DAC_MODE_CTRL_P(i)); + NV_DEBUG_KMS(dev, "DAC-%d mc: 0x%08x\n", i, mc); + if (!(mc & (1 << crtc))) + continue; - if (dcbent->type != OUTPUT_DP) - nouveau_bios_run_display_table(dev, dcbent, 0, -2); + switch ((mc & 0x00000f00) >> 8) { + case 0: type = OUTPUT_ANALOG; break; + case 1: type = OUTPUT_TV; break; + default: + NV_ERROR(dev, "invalid mc, DAC-%d: 0x%08x\n", i, mc); + goto ack; + } - nv50_crtc_set_clock(dev, head, pclk); + or = i; + } - nouveau_bios_run_display_table(dev, dcbent, script, pclk); + for (i = 0; type == OUTPUT_ANY && i < 4; i++) { + if (dev_priv->chipset < 0x90 || + dev_priv->chipset == 0x92 || + dev_priv->chipset == 0xa0) + mc = nv_rd32(dev, NV50_PDISPLAY_SOR_MODE_CTRL_P(i)); + else + mc = nv_rd32(dev, NV90_PDISPLAY_SOR_MODE_CTRL_P(i)); - nv50_display_unk20_dp_hack(dev, dcbent); + NV_DEBUG_KMS(dev, "SOR-%d mc: 0x%08x\n", i, mc); + if (!(mc & (1 << crtc))) + continue; + + switch ((mc & 0x00000f00) >> 8) { + case 0: type = OUTPUT_LVDS; break; + case 1: type = OUTPUT_TMDS; break; + case 2: type = OUTPUT_TMDS; break; + case 5: type = OUTPUT_TMDS; break; + case 8: type = OUTPUT_DP; break; + case 9: type = OUTPUT_DP; break; + default: + NV_ERROR(dev, "invalid mc, SOR-%d: 0x%08x\n", i, mc); + goto ack; + } + + or = i; + } + + if (type == OUTPUT_ANY) + goto ack; + + /* Enable the encoder */ + for (i = 0; i < dev_priv->vbios.dcb.entries; i++) { + dcb = &dev_priv->vbios.dcb.entry[i]; + if (dcb->type == type && (dcb->or & (1 << or))) + break; + } + + if (i == dev_priv->vbios.dcb.entries) { + NV_ERROR(dev, "no dcb for %d %d 0x%08x\n", or, type, mc); + goto ack; + } - tmp = nv_rd32(dev, NV50_PDISPLAY_CRTC_CLK_CTRL2(head)); - tmp &= ~0x000000f; - nv_wr32(dev, NV50_PDISPLAY_CRTC_CLK_CTRL2(head), tmp); + script = nv50_display_script_select(dev, dcb, mc, pclk); + nouveau_bios_run_display_table(dev, dcb, script, pclk); - if (dcbent->type != OUTPUT_ANALOG) { + nv50_display_unk20_dp_hack(dev, dcb); + + if (dcb->type != OUTPUT_ANALOG) { tmp = nv_rd32(dev, NV50_PDISPLAY_SOR_CLK_CTRL2(or)); tmp &= ~0x00000f0f; if (script & 0x0100) @@ -853,24 +895,61 @@ nv50_display_unk20_handler(struct drm_device *dev) nv_wr32(dev, NV50_PDISPLAY_DAC_CLK_CTRL2(or), 0); } + dev_priv->evo_irq.dcb = dcb; + dev_priv->evo_irq.pclk = pclk; + dev_priv->evo_irq.script = script; + ack: nv_wr32(dev, NV50_PDISPLAY_INTR_1, NV50_PDISPLAY_INTR_1_CLK_UNK20); nv_wr32(dev, 0x610030, 0x80000000); } +/* If programming a TMDS output on a SOR that can also be configured for + * DisplayPort, make sure NV50_SOR_DP_CTRL_ENABLE is forced off. + * + * It looks like the VBIOS TMDS scripts make an attempt at this, however, + * the VBIOS scripts on at least one board I have only switch it off on + * link 0, causing a blank display if the output has previously been + * programmed for DisplayPort. + */ +static void +nv50_display_unk40_dp_set_tmds(struct drm_device *dev, struct dcb_entry *dcb) +{ + int or = ffs(dcb->or) - 1, link = !(dcb->dpconf.sor.link & 1); + struct drm_encoder *encoder; + u32 tmp; + + if (dcb->type != OUTPUT_TMDS) + return; + + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); + + if (nv_encoder->dcb->type == OUTPUT_DP && + nv_encoder->dcb->or & (1 << or)) { + tmp = nv_rd32(dev, NV50_SOR_DP_CTRL(or, link)); + tmp &= ~NV50_SOR_DP_CTRL_ENABLED; + nv_wr32(dev, NV50_SOR_DP_CTRL(or, link), tmp); + break; + } + } +} + static void nv50_display_unk40_handler(struct drm_device *dev) { - struct dcb_entry *dcbent; - int head, pclk, script, ret; + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct dcb_entry *dcb = dev_priv->evo_irq.dcb; + u16 script = dev_priv->evo_irq.script; + u32 unk30 = nv_rd32(dev, 0x610030), pclk = dev_priv->evo_irq.pclk; - ret = nv50_display_irq_head(dev, &head, &dcbent); - if (ret) + NV_DEBUG_KMS(dev, "0x610030: 0x%08x\n", unk30); + dev_priv->evo_irq.dcb = NULL; + if (!dcb) goto ack; - pclk = nv_rd32(dev, NV50_PDISPLAY_CRTC_P(head, CLOCK)) & 0x3fffff; - script = nv50_display_script_select(dev, dcbent, pclk); - nouveau_bios_run_display_table(dev, dcbent, script, -pclk); + nouveau_bios_run_display_table(dev, dcb, script, -pclk); + nv50_display_unk40_dp_set_tmds(dev, dcb); ack: nv_wr32(dev, NV50_PDISPLAY_INTR_1, NV50_PDISPLAY_INTR_1_CLK_UNK40); diff --git a/drivers/gpu/drm/nouveau/nv50_display.h b/drivers/gpu/drm/nouveau/nv50_display.h index 581d405..c551f0b 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.h +++ b/drivers/gpu/drm/nouveau/nv50_display.h @@ -38,9 +38,11 @@ void nv50_display_irq_handler(struct drm_device *dev); void nv50_display_irq_handler_bh(struct work_struct *work); void nv50_display_irq_hotplug_bh(struct work_struct *work); -int nv50_display_init(struct drm_device *dev); +int nv50_display_early_init(struct drm_device *dev); +void nv50_display_late_takedown(struct drm_device *dev); int nv50_display_create(struct drm_device *dev); -int nv50_display_destroy(struct drm_device *dev); +int nv50_display_init(struct drm_device *dev); +void nv50_display_destroy(struct drm_device *dev); int nv50_crtc_blank(struct nouveau_crtc *, bool blank); int nv50_crtc_set_clock(struct drm_device *, int head, int pclk); diff --git a/drivers/gpu/drm/nouveau/nv50_fifo.c b/drivers/gpu/drm/nouveau/nv50_fifo.c index e20c0e2..fb0281a 100644 --- a/drivers/gpu/drm/nouveau/nv50_fifo.c +++ b/drivers/gpu/drm/nouveau/nv50_fifo.c @@ -28,41 +28,33 @@ #include "drm.h" #include "nouveau_drv.h" -struct nv50_fifo_priv { - struct nouveau_gpuobj_ref *thingo[2]; - int cur_thingo; -}; - -#define IS_G80 ((dev_priv->chipset & 0xf0) == 0x50) - static void -nv50_fifo_init_thingo(struct drm_device *dev) +nv50_fifo_playlist_update(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nv50_fifo_priv *priv = dev_priv->engine.fifo.priv; + struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo; struct nouveau_gpuobj_ref *cur; int i, nr; NV_DEBUG(dev, "\n"); - cur = priv->thingo[priv->cur_thingo]; - priv->cur_thingo = !priv->cur_thingo; + cur = pfifo->playlist[pfifo->cur_playlist]; + pfifo->cur_playlist = !pfifo->cur_playlist; /* We never schedule channel 0 or 127 */ - dev_priv->engine.instmem.prepare_access(dev, true); for (i = 1, nr = 0; i < 127; i++) { if (dev_priv->fifos[i] && dev_priv->fifos[i]->ramfc) nv_wo32(dev, cur->gpuobj, nr++, i); } - dev_priv->engine.instmem.finish_access(dev); + dev_priv->engine.instmem.flush(dev); nv_wr32(dev, 0x32f4, cur->instance >> 12); nv_wr32(dev, 0x32ec, nr); nv_wr32(dev, 0x2500, 0x101); } -static int -nv50_fifo_channel_enable(struct drm_device *dev, int channel, bool nt) +static void +nv50_fifo_channel_enable(struct drm_device *dev, int channel) { struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_channel *chan = dev_priv->fifos[channel]; @@ -70,37 +62,28 @@ nv50_fifo_channel_enable(struct drm_device *dev, int channel, bool nt) NV_DEBUG(dev, "ch%d\n", channel); - if (!chan->ramfc) - return -EINVAL; - - if (IS_G80) + if (dev_priv->chipset == 0x50) inst = chan->ramfc->instance >> 12; else inst = chan->ramfc->instance >> 8; - nv_wr32(dev, NV50_PFIFO_CTX_TABLE(channel), - inst | NV50_PFIFO_CTX_TABLE_CHANNEL_ENABLED); - if (!nt) - nv50_fifo_init_thingo(dev); - return 0; + nv_wr32(dev, NV50_PFIFO_CTX_TABLE(channel), inst | + NV50_PFIFO_CTX_TABLE_CHANNEL_ENABLED); } static void -nv50_fifo_channel_disable(struct drm_device *dev, int channel, bool nt) +nv50_fifo_channel_disable(struct drm_device *dev, int channel) { struct drm_nouveau_private *dev_priv = dev->dev_private; uint32_t inst; - NV_DEBUG(dev, "ch%d, nt=%d\n", channel, nt); + NV_DEBUG(dev, "ch%d\n", channel); - if (IS_G80) + if (dev_priv->chipset == 0x50) inst = NV50_PFIFO_CTX_TABLE_INSTANCE_MASK_G80; else inst = NV50_PFIFO_CTX_TABLE_INSTANCE_MASK_G84; nv_wr32(dev, NV50_PFIFO_CTX_TABLE(channel), inst); - - if (!nt) - nv50_fifo_init_thingo(dev); } static void @@ -133,12 +116,12 @@ nv50_fifo_init_context_table(struct drm_device *dev) for (i = 0; i < NV50_PFIFO_CTX_TABLE__SIZE; i++) { if (dev_priv->fifos[i]) - nv50_fifo_channel_enable(dev, i, true); + nv50_fifo_channel_enable(dev, i); else - nv50_fifo_channel_disable(dev, i, true); + nv50_fifo_channel_disable(dev, i); } - nv50_fifo_init_thingo(dev); + nv50_fifo_playlist_update(dev); } static void @@ -162,41 +145,38 @@ nv50_fifo_init_regs(struct drm_device *dev) nv_wr32(dev, 0x3270, 0); /* Enable dummy channels setup by nv50_instmem.c */ - nv50_fifo_channel_enable(dev, 0, true); - nv50_fifo_channel_enable(dev, 127, true); + nv50_fifo_channel_enable(dev, 0); + nv50_fifo_channel_enable(dev, 127); } int nv50_fifo_init(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nv50_fifo_priv *priv; + struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo; int ret; NV_DEBUG(dev, "\n"); - priv = dev_priv->engine.fifo.priv; - if (priv) { - priv->cur_thingo = !priv->cur_thingo; + if (pfifo->playlist[0]) { + pfifo->cur_playlist = !pfifo->cur_playlist; goto just_reset; } - priv = kzalloc(sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - dev_priv->engine.fifo.priv = priv; - ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0, 128*4, 0x1000, - NVOBJ_FLAG_ZERO_ALLOC, &priv->thingo[0]); + NVOBJ_FLAG_ZERO_ALLOC, + &pfifo->playlist[0]); if (ret) { - NV_ERROR(dev, "error creating thingo0: %d\n", ret); + NV_ERROR(dev, "error creating playlist 0: %d\n", ret); return ret; } ret = nouveau_gpuobj_new_ref(dev, NULL, NULL, 0, 128*4, 0x1000, - NVOBJ_FLAG_ZERO_ALLOC, &priv->thingo[1]); + NVOBJ_FLAG_ZERO_ALLOC, + &pfifo->playlist[1]); if (ret) { - NV_ERROR(dev, "error creating thingo1: %d\n", ret); + nouveau_gpuobj_ref_del(dev, &pfifo->playlist[0]); + NV_ERROR(dev, "error creating playlist 1: %d\n", ret); return ret; } @@ -216,18 +196,15 @@ void nv50_fifo_takedown(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nv50_fifo_priv *priv = dev_priv->engine.fifo.priv; + struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo; NV_DEBUG(dev, "\n"); - if (!priv) + if (!pfifo->playlist[0]) return; - nouveau_gpuobj_ref_del(dev, &priv->thingo[0]); - nouveau_gpuobj_ref_del(dev, &priv->thingo[1]); - - dev_priv->engine.fifo.priv = NULL; - kfree(priv); + nouveau_gpuobj_ref_del(dev, &pfifo->playlist[0]); + nouveau_gpuobj_ref_del(dev, &pfifo->playlist[1]); } int @@ -248,7 +225,7 @@ nv50_fifo_create_context(struct nouveau_channel *chan) NV_DEBUG(dev, "ch%d\n", chan->id); - if (IS_G80) { + if (dev_priv->chipset == 0x50) { uint32_t ramin_poffset = chan->ramin->gpuobj->im_pramin->start; uint32_t ramin_voffset = chan->ramin->gpuobj->im_backing_start; @@ -281,10 +258,10 @@ nv50_fifo_create_context(struct nouveau_channel *chan) spin_lock_irqsave(&dev_priv->context_switch_lock, flags); - dev_priv->engine.instmem.prepare_access(dev, true); - nv_wo32(dev, ramfc, 0x48/4, chan->pushbuf->instance >> 4); - nv_wo32(dev, ramfc, 0x80/4, (0xc << 24) | (chan->ramht->instance >> 4)); + nv_wo32(dev, ramfc, 0x80/4, (0 << 27) /* 4KiB */ | + (4 << 24) /* SEARCH_FULL */ | + (chan->ramht->instance >> 4)); nv_wo32(dev, ramfc, 0x44/4, 0x2101ffff); nv_wo32(dev, ramfc, 0x60/4, 0x7fffffff); nv_wo32(dev, ramfc, 0x40/4, 0x00000000); @@ -295,7 +272,7 @@ nv50_fifo_create_context(struct nouveau_channel *chan) chan->dma.ib_base * 4); nv_wo32(dev, ramfc, 0x54/4, drm_order(chan->dma.ib_max + 1) << 16); - if (!IS_G80) { + if (dev_priv->chipset != 0x50) { nv_wo32(dev, chan->ramin->gpuobj, 0, chan->id); nv_wo32(dev, chan->ramin->gpuobj, 1, chan->ramfc->instance >> 8); @@ -304,16 +281,10 @@ nv50_fifo_create_context(struct nouveau_channel *chan) nv_wo32(dev, ramfc, 0x98/4, chan->ramin->instance >> 12); } - dev_priv->engine.instmem.finish_access(dev); - - ret = nv50_fifo_channel_enable(dev, chan->id, false); - if (ret) { - NV_ERROR(dev, "error enabling ch%d: %d\n", chan->id, ret); - spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); - nouveau_gpuobj_ref_del(dev, &chan->ramfc); - return ret; - } + dev_priv->engine.instmem.flush(dev); + nv50_fifo_channel_enable(dev, chan->id); + nv50_fifo_playlist_update(dev); spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); return 0; } @@ -328,11 +299,12 @@ nv50_fifo_destroy_context(struct nouveau_channel *chan) /* This will ensure the channel is seen as disabled. */ chan->ramfc = NULL; - nv50_fifo_channel_disable(dev, chan->id, false); + nv50_fifo_channel_disable(dev, chan->id); /* Dummy channel, also used on ch 127 */ if (chan->id == 0) - nv50_fifo_channel_disable(dev, 127, false); + nv50_fifo_channel_disable(dev, 127); + nv50_fifo_playlist_update(dev); nouveau_gpuobj_ref_del(dev, &ramfc); nouveau_gpuobj_ref_del(dev, &chan->cache); @@ -349,8 +321,6 @@ nv50_fifo_load_context(struct nouveau_channel *chan) NV_DEBUG(dev, "ch%d\n", chan->id); - dev_priv->engine.instmem.prepare_access(dev, false); - nv_wr32(dev, 0x3330, nv_ro32(dev, ramfc, 0x00/4)); nv_wr32(dev, 0x3334, nv_ro32(dev, ramfc, 0x04/4)); nv_wr32(dev, 0x3240, nv_ro32(dev, ramfc, 0x08/4)); @@ -396,7 +366,7 @@ nv50_fifo_load_context(struct nouveau_channel *chan) nv_wr32(dev, NV03_PFIFO_CACHE1_GET, 0); /* guessing that all the 0x34xx regs aren't on NV50 */ - if (!IS_G80) { + if (dev_priv->chipset != 0x50) { nv_wr32(dev, 0x340c, nv_ro32(dev, ramfc, 0x88/4)); nv_wr32(dev, 0x3400, nv_ro32(dev, ramfc, 0x8c/4)); nv_wr32(dev, 0x3404, nv_ro32(dev, ramfc, 0x90/4)); @@ -404,8 +374,6 @@ nv50_fifo_load_context(struct nouveau_channel *chan) nv_wr32(dev, 0x3410, nv_ro32(dev, ramfc, 0x98/4)); } - dev_priv->engine.instmem.finish_access(dev); - nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH1, chan->id | (1<<16)); return 0; } @@ -434,8 +402,6 @@ nv50_fifo_unload_context(struct drm_device *dev) ramfc = chan->ramfc->gpuobj; cache = chan->cache->gpuobj; - dev_priv->engine.instmem.prepare_access(dev, true); - nv_wo32(dev, ramfc, 0x00/4, nv_rd32(dev, 0x3330)); nv_wo32(dev, ramfc, 0x04/4, nv_rd32(dev, 0x3334)); nv_wo32(dev, ramfc, 0x08/4, nv_rd32(dev, 0x3240)); @@ -482,7 +448,7 @@ nv50_fifo_unload_context(struct drm_device *dev) } /* guessing that all the 0x34xx regs aren't on NV50 */ - if (!IS_G80) { + if (dev_priv->chipset != 0x50) { nv_wo32(dev, ramfc, 0x84/4, ptr >> 1); nv_wo32(dev, ramfc, 0x88/4, nv_rd32(dev, 0x340c)); nv_wo32(dev, ramfc, 0x8c/4, nv_rd32(dev, 0x3400)); @@ -491,7 +457,7 @@ nv50_fifo_unload_context(struct drm_device *dev) nv_wo32(dev, ramfc, 0x98/4, nv_rd32(dev, 0x3410)); } - dev_priv->engine.instmem.finish_access(dev); + dev_priv->engine.instmem.flush(dev); /*XXX: probably reload ch127 (NULL) state back too */ nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH1, 127); diff --git a/drivers/gpu/drm/nouveau/nv50_gpio.c b/drivers/gpu/drm/nouveau/nv50_gpio.c index bb47ad7..b2fab2b 100644 --- a/drivers/gpu/drm/nouveau/nv50_gpio.c +++ b/drivers/gpu/drm/nouveau/nv50_gpio.c @@ -74,3 +74,38 @@ nv50_gpio_set(struct drm_device *dev, enum dcb_gpio_tag tag, int state) nv_wr32(dev, r, v); return 0; } + +void +nv50_gpio_irq_enable(struct drm_device *dev, enum dcb_gpio_tag tag, bool on) +{ + struct dcb_gpio_entry *gpio; + u32 reg, mask; + + gpio = nouveau_bios_gpio_entry(dev, tag); + if (!gpio) { + NV_ERROR(dev, "gpio tag 0x%02x not found\n", tag); + return; + } + + reg = gpio->line < 16 ? 0xe050 : 0xe070; + mask = 0x00010001 << (gpio->line & 0xf); + + nv_wr32(dev, reg + 4, mask); + nv_mask(dev, reg + 0, mask, on ? mask : 0); +} + +int +nv50_gpio_init(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + + /* disable, and ack any pending gpio interrupts */ + nv_wr32(dev, 0xe050, 0x00000000); + nv_wr32(dev, 0xe054, 0xffffffff); + if (dev_priv->chipset >= 0x90) { + nv_wr32(dev, 0xe070, 0x00000000); + nv_wr32(dev, 0xe074, 0xffffffff); + } + + return 0; +} diff --git a/drivers/gpu/drm/nouveau/nv50_graph.c b/drivers/gpu/drm/nouveau/nv50_graph.c index b203d06..1413028 100644 --- a/drivers/gpu/drm/nouveau/nv50_graph.c +++ b/drivers/gpu/drm/nouveau/nv50_graph.c @@ -30,8 +30,6 @@ #include "nouveau_grctx.h" -#define IS_G80 ((dev_priv->chipset & 0xf0) == 0x50) - static void nv50_graph_init_reset(struct drm_device *dev) { @@ -103,37 +101,33 @@ static int nv50_graph_init_ctxctl(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_grctx ctx = {}; + uint32_t *cp; + int i; NV_DEBUG(dev, "\n"); - if (nouveau_ctxfw) { - nouveau_grctx_prog_load(dev); - dev_priv->engine.graph.grctx_size = 0x70000; + cp = kmalloc(512 * 4, GFP_KERNEL); + if (!cp) { + NV_ERROR(dev, "failed to allocate ctxprog\n"); + dev_priv->engine.graph.accel_blocked = true; + return 0; } - if (!dev_priv->engine.graph.ctxprog) { - struct nouveau_grctx ctx = {}; - uint32_t *cp = kmalloc(512 * 4, GFP_KERNEL); - int i; - if (!cp) { - NV_ERROR(dev, "Couldn't alloc ctxprog! Disabling acceleration.\n"); - dev_priv->engine.graph.accel_blocked = true; - return 0; - } - ctx.dev = dev; - ctx.mode = NOUVEAU_GRCTX_PROG; - ctx.data = cp; - ctx.ctxprog_max = 512; - if (!nv50_grctx_init(&ctx)) { - dev_priv->engine.graph.grctx_size = ctx.ctxvals_pos * 4; - - nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_INDEX, 0); - for (i = 0; i < ctx.ctxprog_len; i++) - nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_DATA, cp[i]); - } else { - dev_priv->engine.graph.accel_blocked = true; - } - kfree(cp); + + ctx.dev = dev; + ctx.mode = NOUVEAU_GRCTX_PROG; + ctx.data = cp; + ctx.ctxprog_max = 512; + if (!nv50_grctx_init(&ctx)) { + dev_priv->engine.graph.grctx_size = ctx.ctxvals_pos * 4; + + nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_INDEX, 0); + for (i = 0; i < ctx.ctxprog_len; i++) + nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_DATA, cp[i]); + } else { + dev_priv->engine.graph.accel_blocked = true; } + kfree(cp); nv_wr32(dev, 0x400320, 4); nv_wr32(dev, NV40_PGRAPH_CTXCTL_CUR, 0); @@ -164,7 +158,6 @@ void nv50_graph_takedown(struct drm_device *dev) { NV_DEBUG(dev, "\n"); - nouveau_grctx_fini(dev); } void @@ -212,8 +205,9 @@ nv50_graph_create_context(struct nouveau_channel *chan) struct drm_device *dev = chan->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_gpuobj *ramin = chan->ramin->gpuobj; - struct nouveau_gpuobj *ctx; + struct nouveau_gpuobj *obj; struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; + struct nouveau_grctx ctx = {}; int hdr, ret; NV_DEBUG(dev, "ch%d\n", chan->id); @@ -223,10 +217,9 @@ nv50_graph_create_context(struct nouveau_channel *chan) NVOBJ_FLAG_ZERO_FREE, &chan->ramin_grctx); if (ret) return ret; - ctx = chan->ramin_grctx->gpuobj; + obj = chan->ramin_grctx->gpuobj; - hdr = IS_G80 ? 0x200 : 0x20; - dev_priv->engine.instmem.prepare_access(dev, true); + hdr = (dev_priv->chipset == 0x50) ? 0x200 : 0x20; nv_wo32(dev, ramin, (hdr + 0x00)/4, 0x00190002); nv_wo32(dev, ramin, (hdr + 0x04)/4, chan->ramin_grctx->instance + pgraph->grctx_size - 1); @@ -234,21 +227,15 @@ nv50_graph_create_context(struct nouveau_channel *chan) nv_wo32(dev, ramin, (hdr + 0x0c)/4, 0); nv_wo32(dev, ramin, (hdr + 0x10)/4, 0); nv_wo32(dev, ramin, (hdr + 0x14)/4, 0x00010000); - dev_priv->engine.instmem.finish_access(dev); - - dev_priv->engine.instmem.prepare_access(dev, true); - if (!pgraph->ctxprog) { - struct nouveau_grctx ctx = {}; - ctx.dev = chan->dev; - ctx.mode = NOUVEAU_GRCTX_VALS; - ctx.data = chan->ramin_grctx->gpuobj; - nv50_grctx_init(&ctx); - } else { - nouveau_grctx_vals_load(dev, ctx); - } - nv_wo32(dev, ctx, 0x00000/4, chan->ramin->instance >> 12); - dev_priv->engine.instmem.finish_access(dev); + ctx.dev = chan->dev; + ctx.mode = NOUVEAU_GRCTX_VALS; + ctx.data = obj; + nv50_grctx_init(&ctx); + + nv_wo32(dev, obj, 0x00000/4, chan->ramin->instance >> 12); + + dev_priv->engine.instmem.flush(dev); return 0; } @@ -257,17 +244,16 @@ nv50_graph_destroy_context(struct nouveau_channel *chan) { struct drm_device *dev = chan->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; - int i, hdr = IS_G80 ? 0x200 : 0x20; + int i, hdr = (dev_priv->chipset == 0x50) ? 0x200 : 0x20; NV_DEBUG(dev, "ch%d\n", chan->id); if (!chan->ramin || !chan->ramin->gpuobj) return; - dev_priv->engine.instmem.prepare_access(dev, true); for (i = hdr; i < hdr + 24; i += 4) nv_wo32(dev, chan->ramin->gpuobj, i/4, 0); - dev_priv->engine.instmem.finish_access(dev); + dev_priv->engine.instmem.flush(dev); nouveau_gpuobj_ref_del(dev, &chan->ramin_grctx); } diff --git a/drivers/gpu/drm/nouveau/nv50_instmem.c b/drivers/gpu/drm/nouveau/nv50_instmem.c index 5f21df3..37c7b48 100644 --- a/drivers/gpu/drm/nouveau/nv50_instmem.c +++ b/drivers/gpu/drm/nouveau/nv50_instmem.c @@ -35,8 +35,6 @@ struct nv50_instmem_priv { struct nouveau_gpuobj_ref *pramin_pt; struct nouveau_gpuobj_ref *pramin_bar; struct nouveau_gpuobj_ref *fb_bar; - - bool last_access_wr; }; #define NV50_INSTMEM_PAGE_SHIFT 12 @@ -147,7 +145,7 @@ nv50_instmem_init(struct drm_device *dev) if (ret) return ret; - if (nouveau_mem_init_heap(&chan->ramin_heap, c_base, c_size - c_base)) + if (drm_mm_init(&chan->ramin_heap, c_base, c_size - c_base)) return -ENOMEM; /* RAMFC + zero channel's PRAMIN up to start of VM pagedir */ @@ -241,7 +239,7 @@ nv50_instmem_init(struct drm_device *dev) return ret; BAR0_WI32(priv->fb_bar->gpuobj, 0x00, 0x7fc00000); BAR0_WI32(priv->fb_bar->gpuobj, 0x04, 0x40000000 + - drm_get_resource_len(dev, 1) - 1); + pci_resource_len(dev->pdev, 1) - 1); BAR0_WI32(priv->fb_bar->gpuobj, 0x08, 0x40000000); BAR0_WI32(priv->fb_bar->gpuobj, 0x0c, 0x00000000); BAR0_WI32(priv->fb_bar->gpuobj, 0x10, 0x00000000); @@ -262,23 +260,18 @@ nv50_instmem_init(struct drm_device *dev) /* Assume that praying isn't enough, check that we can re-read the * entire fake channel back from the PRAMIN BAR */ - dev_priv->engine.instmem.prepare_access(dev, false); for (i = 0; i < c_size; i += 4) { if (nv_rd32(dev, NV_RAMIN + i) != nv_ri32(dev, i)) { NV_ERROR(dev, "Error reading back PRAMIN at 0x%08x\n", i); - dev_priv->engine.instmem.finish_access(dev); return -EINVAL; } } - dev_priv->engine.instmem.finish_access(dev); nv_wr32(dev, NV50_PUNK_BAR0_PRAMIN, save_nv001700); /* Global PRAMIN heap */ - if (nouveau_mem_init_heap(&dev_priv->ramin_heap, - c_size, dev_priv->ramin_size - c_size)) { - dev_priv->ramin_heap = NULL; + if (drm_mm_init(&dev_priv->ramin_heap, c_size, dev_priv->ramin_size - c_size)) { NV_ERROR(dev, "Failed to init RAMIN heap\n"); } @@ -321,7 +314,7 @@ nv50_instmem_takedown(struct drm_device *dev) nouveau_gpuobj_del(dev, &chan->vm_pd); nouveau_gpuobj_ref_del(dev, &chan->ramfc); nouveau_gpuobj_ref_del(dev, &chan->ramin); - nouveau_mem_takedown(&chan->ramin_heap); + drm_mm_takedown(&chan->ramin_heap); dev_priv->fifos[0] = dev_priv->fifos[127] = NULL; kfree(chan); @@ -436,14 +429,14 @@ nv50_instmem_bind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) if (!gpuobj->im_backing || !gpuobj->im_pramin || gpuobj->im_bound) return -EINVAL; - NV_DEBUG(dev, "st=0x%0llx sz=0x%0llx\n", + NV_DEBUG(dev, "st=0x%lx sz=0x%lx\n", gpuobj->im_pramin->start, gpuobj->im_pramin->size); pte = (gpuobj->im_pramin->start >> 12) << 1; pte_end = ((gpuobj->im_pramin->size >> 12) << 1) + pte; vram = gpuobj->im_backing_start; - NV_DEBUG(dev, "pramin=0x%llx, pte=%d, pte_end=%d\n", + NV_DEBUG(dev, "pramin=0x%lx, pte=%d, pte_end=%d\n", gpuobj->im_pramin->start, pte, pte_end); NV_DEBUG(dev, "first vram page: 0x%08x\n", gpuobj->im_backing_start); @@ -453,27 +446,15 @@ nv50_instmem_bind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) vram |= 0x30; } - dev_priv->engine.instmem.prepare_access(dev, true); while (pte < pte_end) { nv_wo32(dev, pramin_pt, pte++, lower_32_bits(vram)); nv_wo32(dev, pramin_pt, pte++, upper_32_bits(vram)); vram += NV50_INSTMEM_PAGE_SIZE; } - dev_priv->engine.instmem.finish_access(dev); - - nv_wr32(dev, 0x100c80, 0x00040001); - if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) { - NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (1)\n"); - NV_ERROR(dev, "0x100c80 = 0x%08x\n", nv_rd32(dev, 0x100c80)); - return -EBUSY; - } + dev_priv->engine.instmem.flush(dev); - nv_wr32(dev, 0x100c80, 0x00060001); - if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) { - NV_ERROR(dev, "timeout: (0x100c80 & 1) == 0 (2)\n"); - NV_ERROR(dev, "0x100c80 = 0x%08x\n", nv_rd32(dev, 0x100c80)); - return -EBUSY; - } + nv50_vm_flush(dev, 4); + nv50_vm_flush(dev, 6); gpuobj->im_bound = 1; return 0; @@ -492,36 +473,37 @@ nv50_instmem_unbind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) pte = (gpuobj->im_pramin->start >> 12) << 1; pte_end = ((gpuobj->im_pramin->size >> 12) << 1) + pte; - dev_priv->engine.instmem.prepare_access(dev, true); while (pte < pte_end) { nv_wo32(dev, priv->pramin_pt->gpuobj, pte++, 0x00000000); nv_wo32(dev, priv->pramin_pt->gpuobj, pte++, 0x00000000); } - dev_priv->engine.instmem.finish_access(dev); + dev_priv->engine.instmem.flush(dev); gpuobj->im_bound = 0; return 0; } void -nv50_instmem_prepare_access(struct drm_device *dev, bool write) +nv50_instmem_flush(struct drm_device *dev) { - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nv50_instmem_priv *priv = dev_priv->engine.instmem.priv; - - priv->last_access_wr = write; + nv_wr32(dev, 0x00330c, 0x00000001); + if (!nv_wait(0x00330c, 0x00000002, 0x00000000)) + NV_ERROR(dev, "PRAMIN flush timeout\n"); } void -nv50_instmem_finish_access(struct drm_device *dev) +nv84_instmem_flush(struct drm_device *dev) { - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nv50_instmem_priv *priv = dev_priv->engine.instmem.priv; + nv_wr32(dev, 0x070000, 0x00000001); + if (!nv_wait(0x070000, 0x00000002, 0x00000000)) + NV_ERROR(dev, "PRAMIN flush timeout\n"); +} - if (priv->last_access_wr) { - nv_wr32(dev, 0x070000, 0x00000001); - if (!nv_wait(0x070000, 0x00000001, 0x00000000)) - NV_ERROR(dev, "PRAMIN flush timeout\n"); - } +void +nv50_vm_flush(struct drm_device *dev, int engine) +{ + nv_wr32(dev, 0x100c80, (engine << 16) | 1); + if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) + NV_ERROR(dev, "vm flush timeout: engine %d\n", engine); } diff --git a/drivers/gpu/drm/nouveau/nv50_sor.c b/drivers/gpu/drm/nouveau/nv50_sor.c index 812778d..bcd4cf8 100644 --- a/drivers/gpu/drm/nouveau/nv50_sor.c +++ b/drivers/gpu/drm/nouveau/nv50_sor.c @@ -37,52 +37,32 @@ #include "nv50_display.h" static void -nv50_sor_disconnect(struct nouveau_encoder *nv_encoder) +nv50_sor_disconnect(struct drm_encoder *encoder) { - struct drm_device *dev = to_drm_encoder(nv_encoder)->dev; + struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); + struct drm_device *dev = encoder->dev; struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_channel *evo = dev_priv->evo; int ret; + if (!nv_encoder->crtc) + return; + nv50_crtc_blank(nouveau_crtc(nv_encoder->crtc), true); + NV_DEBUG_KMS(dev, "Disconnecting SOR %d\n", nv_encoder->or); - ret = RING_SPACE(evo, 2); + ret = RING_SPACE(evo, 4); if (ret) { NV_ERROR(dev, "no space while disconnecting SOR\n"); return; } BEGIN_RING(evo, 0, NV50_EVO_SOR(nv_encoder->or, MODE_CTRL), 1); - OUT_RING(evo, 0); -} - -static void -nv50_sor_dp_link_train(struct drm_encoder *encoder) -{ - struct drm_device *dev = encoder->dev; - struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); - struct bit_displayport_encoder_table *dpe; - int dpe_headerlen; - - dpe = nouveau_bios_dp_table(dev, nv_encoder->dcb, &dpe_headerlen); - if (!dpe) { - NV_ERROR(dev, "SOR-%d: no DP encoder table!\n", nv_encoder->or); - return; - } + OUT_RING (evo, 0); + BEGIN_RING(evo, 0, NV50_EVO_UPDATE, 1); + OUT_RING (evo, 0); - if (dpe->script0) { - NV_DEBUG_KMS(dev, "SOR-%d: running DP script 0\n", nv_encoder->or); - nouveau_bios_run_init_table(dev, le16_to_cpu(dpe->script0), - nv_encoder->dcb); - } - - if (!nouveau_dp_link_train(encoder)) - NV_ERROR(dev, "SOR-%d: link training failed\n", nv_encoder->or); - - if (dpe->script1) { - NV_DEBUG_KMS(dev, "SOR-%d: running DP script 1\n", nv_encoder->or); - nouveau_bios_run_init_table(dev, le16_to_cpu(dpe->script1), - nv_encoder->dcb); - } + nv_encoder->crtc = NULL; + nv_encoder->last_dpms = DRM_MODE_DPMS_OFF; } static void @@ -94,14 +74,16 @@ nv50_sor_dpms(struct drm_encoder *encoder, int mode) uint32_t val; int or = nv_encoder->or; - NV_DEBUG_KMS(dev, "or %d mode %d\n", or, mode); + NV_DEBUG_KMS(dev, "or %d type %d mode %d\n", or, nv_encoder->dcb->type, mode); nv_encoder->last_dpms = mode; list_for_each_entry(enc, &dev->mode_config.encoder_list, head) { struct nouveau_encoder *nvenc = nouveau_encoder(enc); if (nvenc == nv_encoder || - nvenc->disconnect != nv50_sor_disconnect || + (nvenc->dcb->type != OUTPUT_TMDS && + nvenc->dcb->type != OUTPUT_LVDS && + nvenc->dcb->type != OUTPUT_DP) || nvenc->dcb->or != nv_encoder->dcb->or) continue; @@ -133,8 +115,22 @@ nv50_sor_dpms(struct drm_encoder *encoder, int mode) nv_rd32(dev, NV50_PDISPLAY_SOR_DPMS_STATE(or))); } - if (nv_encoder->dcb->type == OUTPUT_DP && mode == DRM_MODE_DPMS_ON) - nv50_sor_dp_link_train(encoder); + if (nv_encoder->dcb->type == OUTPUT_DP) { + struct nouveau_i2c_chan *auxch; + + auxch = nouveau_i2c_find(dev, nv_encoder->dcb->i2c_index); + if (!auxch) + return; + + if (mode == DRM_MODE_DPMS_ON) { + u8 status = DP_SET_POWER_D0; + nouveau_dp_auxch(auxch, 8, DP_SET_POWER, &status, 1); + nouveau_dp_link_train(encoder); + } else { + u8 status = DP_SET_POWER_D3; + nouveau_dp_auxch(auxch, 8, DP_SET_POWER, &status, 1); + } + } } static void @@ -196,7 +192,8 @@ nv50_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, uint32_t mode_ctl = 0; int ret; - NV_DEBUG_KMS(dev, "or %d\n", nv_encoder->or); + NV_DEBUG_KMS(dev, "or %d type %d -> crtc %d\n", + nv_encoder->or, nv_encoder->dcb->type, crtc->index); nv50_sor_dpms(encoder, DRM_MODE_DPMS_ON); @@ -239,6 +236,14 @@ nv50_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, } BEGIN_RING(evo, 0, NV50_EVO_SOR(nv_encoder->or, MODE_CTRL), 1); OUT_RING(evo, mode_ctl); + + nv_encoder->crtc = encoder->crtc; +} + +static struct drm_crtc * +nv50_sor_crtc_get(struct drm_encoder *encoder) +{ + return nouveau_encoder(encoder)->crtc; } static const struct drm_encoder_helper_funcs nv50_sor_helper_funcs = { @@ -249,7 +254,9 @@ static const struct drm_encoder_helper_funcs nv50_sor_helper_funcs = { .prepare = nv50_sor_prepare, .commit = nv50_sor_commit, .mode_set = nv50_sor_mode_set, - .detect = NULL + .get_crtc = nv50_sor_crtc_get, + .detect = NULL, + .disable = nv50_sor_disconnect }; static void @@ -272,32 +279,22 @@ static const struct drm_encoder_funcs nv50_sor_encoder_funcs = { }; int -nv50_sor_create(struct drm_device *dev, struct dcb_entry *entry) +nv50_sor_create(struct drm_connector *connector, struct dcb_entry *entry) { struct nouveau_encoder *nv_encoder = NULL; + struct drm_device *dev = connector->dev; struct drm_encoder *encoder; - bool dum; int type; NV_DEBUG_KMS(dev, "\n"); switch (entry->type) { case OUTPUT_TMDS: - NV_INFO(dev, "Detected a TMDS output\n"); + case OUTPUT_DP: type = DRM_MODE_ENCODER_TMDS; break; case OUTPUT_LVDS: - NV_INFO(dev, "Detected a LVDS output\n"); type = DRM_MODE_ENCODER_LVDS; - - if (nouveau_bios_parse_lvds_table(dev, 0, &dum, &dum)) { - NV_ERROR(dev, "Failed parsing LVDS table\n"); - return -EINVAL; - } - break; - case OUTPUT_DP: - NV_INFO(dev, "Detected a DP output\n"); - type = DRM_MODE_ENCODER_TMDS; break; default: return -EINVAL; @@ -310,8 +307,7 @@ nv50_sor_create(struct drm_device *dev, struct dcb_entry *entry) nv_encoder->dcb = entry; nv_encoder->or = ffs(entry->or) - 1; - - nv_encoder->disconnect = nv50_sor_disconnect; + nv_encoder->last_dpms = DRM_MODE_DPMS_OFF; drm_encoder_init(dev, encoder, &nv50_sor_encoder_funcs, type); drm_encoder_helper_add(encoder, &nv50_sor_helper_funcs); @@ -342,5 +338,6 @@ nv50_sor_create(struct drm_device *dev, struct dcb_entry *entry) nv_encoder->dp.mc_unknown = 5; } + drm_mode_connector_attach_encoder(connector, encoder); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvreg.h b/drivers/gpu/drm/nouveau/nvreg.h index 5998c35..ad64673 100644 --- a/drivers/gpu/drm/nouveau/nvreg.h +++ b/drivers/gpu/drm/nouveau/nvreg.h @@ -147,28 +147,6 @@ # define NV_VIO_GX_DONT_CARE_INDEX 0x07 # define NV_VIO_GX_BIT_MASK_INDEX 0x08 -#define NV_PFB_BOOT_0 0x00100000 -#define NV_PFB_CFG0 0x00100200 -#define NV_PFB_CFG1 0x00100204 -#define NV_PFB_CSTATUS 0x0010020C -#define NV_PFB_REFCTRL 0x00100210 -# define NV_PFB_REFCTRL_VALID_1 (1 << 31) -#define NV_PFB_PAD 0x0010021C -# define NV_PFB_PAD_CKE_NORMAL (1 << 0) -#define NV_PFB_TILE_NV10 0x00100240 -#define NV_PFB_TILE_SIZE_NV10 0x00100244 -#define NV_PFB_REF 0x001002D0 -# define NV_PFB_REF_CMD_REFRESH (1 << 0) -#define NV_PFB_PRE 0x001002D4 -# define NV_PFB_PRE_CMD_PRECHARGE (1 << 0) -#define NV_PFB_CLOSE_PAGE2 0x0010033C -#define NV_PFB_TILE_NV40 0x00100600 -#define NV_PFB_TILE_SIZE_NV40 0x00100604 - -#define NV_PEXTDEV_BOOT_0 0x00101000 -# define NV_PEXTDEV_BOOT_0_STRAP_FP_IFACE_12BIT (8 << 12) -#define NV_PEXTDEV_BOOT_3 0x0010100c - #define NV_PCRTC_INTR_0 0x00600100 # define NV_PCRTC_INTR_0_VBLANK (1 << 0) #define NV_PCRTC_INTR_EN_0 0x00600140 diff --git a/drivers/gpu/drm/r128/r128_cce.c b/drivers/gpu/drm/r128/r128_cce.c index e671d0e..570e190 100644 --- a/drivers/gpu/drm/r128/r128_cce.c +++ b/drivers/gpu/drm/r128/r128_cce.c @@ -44,7 +44,7 @@ MODULE_FIRMWARE(FIRMWARE_NAME); -static int R128_READ_PLL(struct drm_device * dev, int addr) +static int R128_READ_PLL(struct drm_device *dev, int addr) { drm_r128_private_t *dev_priv = dev->dev_private; @@ -53,7 +53,7 @@ static int R128_READ_PLL(struct drm_device * dev, int addr) } #if R128_FIFO_DEBUG -static void r128_status(drm_r128_private_t * dev_priv) +static void r128_status(drm_r128_private_t *dev_priv) { printk("GUI_STAT = 0x%08x\n", (unsigned int)R128_READ(R128_GUI_STAT)); @@ -74,7 +74,7 @@ static void r128_status(drm_r128_private_t * dev_priv) * Engine, FIFO control */ -static int r128_do_pixcache_flush(drm_r128_private_t * dev_priv) +static int r128_do_pixcache_flush(drm_r128_private_t *dev_priv) { u32 tmp; int i; @@ -83,9 +83,8 @@ static int r128_do_pixcache_flush(drm_r128_private_t * dev_priv) R128_WRITE(R128_PC_NGUI_CTLSTAT, tmp); for (i = 0; i < dev_priv->usec_timeout; i++) { - if (!(R128_READ(R128_PC_NGUI_CTLSTAT) & R128_PC_BUSY)) { + if (!(R128_READ(R128_PC_NGUI_CTLSTAT) & R128_PC_BUSY)) return 0; - } DRM_UDELAY(1); } @@ -95,7 +94,7 @@ static int r128_do_pixcache_flush(drm_r128_private_t * dev_priv) return -EBUSY; } -static int r128_do_wait_for_fifo(drm_r128_private_t * dev_priv, int entries) +static int r128_do_wait_for_fifo(drm_r128_private_t *dev_priv, int entries) { int i; @@ -112,7 +111,7 @@ static int r128_do_wait_for_fifo(drm_r128_private_t * dev_priv, int entries) return -EBUSY; } -static int r128_do_wait_for_idle(drm_r128_private_t * dev_priv) +static int r128_do_wait_for_idle(drm_r128_private_t *dev_priv) { int i, ret; @@ -189,7 +188,7 @@ out_release: * prior to a wait for idle, as it informs the engine that the command * stream is ending. */ -static void r128_do_cce_flush(drm_r128_private_t * dev_priv) +static void r128_do_cce_flush(drm_r128_private_t *dev_priv) { u32 tmp; @@ -199,7 +198,7 @@ static void r128_do_cce_flush(drm_r128_private_t * dev_priv) /* Wait for the CCE to go idle. */ -int r128_do_cce_idle(drm_r128_private_t * dev_priv) +int r128_do_cce_idle(drm_r128_private_t *dev_priv) { int i; @@ -225,7 +224,7 @@ int r128_do_cce_idle(drm_r128_private_t * dev_priv) /* Start the Concurrent Command Engine. */ -static void r128_do_cce_start(drm_r128_private_t * dev_priv) +static void r128_do_cce_start(drm_r128_private_t *dev_priv) { r128_do_wait_for_idle(dev_priv); @@ -242,7 +241,7 @@ static void r128_do_cce_start(drm_r128_private_t * dev_priv) * commands, so you must wait for the CCE command stream to complete * before calling this routine. */ -static void r128_do_cce_reset(drm_r128_private_t * dev_priv) +static void r128_do_cce_reset(drm_r128_private_t *dev_priv) { R128_WRITE(R128_PM4_BUFFER_DL_WPTR, 0); R128_WRITE(R128_PM4_BUFFER_DL_RPTR, 0); @@ -253,7 +252,7 @@ static void r128_do_cce_reset(drm_r128_private_t * dev_priv) * commands, so you must flush the command stream and wait for the CCE * to go idle before calling this routine. */ -static void r128_do_cce_stop(drm_r128_private_t * dev_priv) +static void r128_do_cce_stop(drm_r128_private_t *dev_priv) { R128_WRITE(R128_PM4_MICRO_CNTL, 0); R128_WRITE(R128_PM4_BUFFER_CNTL, @@ -264,7 +263,7 @@ static void r128_do_cce_stop(drm_r128_private_t * dev_priv) /* Reset the engine. This will stop the CCE if it is running. */ -static int r128_do_engine_reset(struct drm_device * dev) +static int r128_do_engine_reset(struct drm_device *dev) { drm_r128_private_t *dev_priv = dev->dev_private; u32 clock_cntl_index, mclk_cntl, gen_reset_cntl; @@ -301,8 +300,8 @@ static int r128_do_engine_reset(struct drm_device * dev) return 0; } -static void r128_cce_init_ring_buffer(struct drm_device * dev, - drm_r128_private_t * dev_priv) +static void r128_cce_init_ring_buffer(struct drm_device *dev, + drm_r128_private_t *dev_priv) { u32 ring_start; u32 tmp; @@ -340,7 +339,7 @@ static void r128_cce_init_ring_buffer(struct drm_device * dev, R128_WRITE(R128_BUS_CNTL, tmp); } -static int r128_do_init_cce(struct drm_device * dev, drm_r128_init_t * init) +static int r128_do_init_cce(struct drm_device *dev, drm_r128_init_t *init) { drm_r128_private_t *dev_priv; int rc; @@ -588,7 +587,7 @@ static int r128_do_init_cce(struct drm_device * dev, drm_r128_init_t * init) return rc; } -int r128_do_cleanup_cce(struct drm_device * dev) +int r128_do_cleanup_cce(struct drm_device *dev) { /* Make sure interrupts are disabled here because the uninstall ioctl @@ -682,9 +681,8 @@ int r128_cce_stop(struct drm_device *dev, void *data, struct drm_file *file_priv /* Flush any pending CCE commands. This ensures any outstanding * commands are exectuted by the engine before we turn it off. */ - if (stop->flush) { + if (stop->flush) r128_do_cce_flush(dev_priv); - } /* If we fail to make the engine go idle, we return an error * code so that the DRM ioctl wrapper can try again. @@ -735,9 +733,8 @@ int r128_cce_idle(struct drm_device *dev, void *data, struct drm_file *file_priv DEV_INIT_TEST_WITH_RETURN(dev_priv); - if (dev_priv->cce_running) { + if (dev_priv->cce_running) r128_do_cce_flush(dev_priv); - } return r128_do_cce_idle(dev_priv); } @@ -765,7 +762,7 @@ int r128_fullscreen(struct drm_device *dev, void *data, struct drm_file *file_pr #define R128_BUFFER_FREE 0 #if 0 -static int r128_freelist_init(struct drm_device * dev) +static int r128_freelist_init(struct drm_device *dev) { struct drm_device_dma *dma = dev->dma; drm_r128_private_t *dev_priv = dev->dev_private; @@ -848,7 +845,7 @@ static struct drm_buf *r128_freelist_get(struct drm_device * dev) return NULL; } -void r128_freelist_reset(struct drm_device * dev) +void r128_freelist_reset(struct drm_device *dev) { struct drm_device_dma *dma = dev->dma; int i; @@ -864,7 +861,7 @@ void r128_freelist_reset(struct drm_device * dev) * CCE command submission */ -int r128_wait_ring(drm_r128_private_t * dev_priv, int n) +int r128_wait_ring(drm_r128_private_t *dev_priv, int n) { drm_r128_ring_buffer_t *ring = &dev_priv->ring; int i; @@ -881,9 +878,9 @@ int r128_wait_ring(drm_r128_private_t * dev_priv, int n) return -EBUSY; } -static int r128_cce_get_buffers(struct drm_device * dev, +static int r128_cce_get_buffers(struct drm_device *dev, struct drm_file *file_priv, - struct drm_dma * d) + struct drm_dma *d) { int i; struct drm_buf *buf; @@ -933,9 +930,8 @@ int r128_cce_buffers(struct drm_device *dev, void *data, struct drm_file *file_p d->granted_count = 0; - if (d->request_count) { + if (d->request_count) ret = r128_cce_get_buffers(dev, file_priv, d); - } return ret; } diff --git a/drivers/gpu/drm/r128/r128_drv.c b/drivers/gpu/drm/r128/r128_drv.c index b806fdc..1e2971f 100644 --- a/drivers/gpu/drm/r128/r128_drv.c +++ b/drivers/gpu/drm/r128/r128_drv.c @@ -85,7 +85,7 @@ static struct drm_driver driver = { .patchlevel = DRIVER_PATCHLEVEL, }; -int r128_driver_load(struct drm_device * dev, unsigned long flags) +int r128_driver_load(struct drm_device *dev, unsigned long flags) { return drm_vblank_init(dev, 1); } diff --git a/drivers/gpu/drm/r128/r128_drv.h b/drivers/gpu/drm/r128/r128_drv.h index 3c60829..930c71b 100644 --- a/drivers/gpu/drm/r128/r128_drv.h +++ b/drivers/gpu/drm/r128/r128_drv.h @@ -53,7 +53,7 @@ #define DRIVER_MINOR 5 #define DRIVER_PATCHLEVEL 0 -#define GET_RING_HEAD(dev_priv) R128_READ( R128_PM4_BUFFER_DL_RPTR ) +#define GET_RING_HEAD(dev_priv) R128_READ(R128_PM4_BUFFER_DL_RPTR) typedef struct drm_r128_freelist { unsigned int age; @@ -144,23 +144,23 @@ extern int r128_engine_reset(struct drm_device *dev, void *data, struct drm_file extern int r128_fullscreen(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int r128_cce_buffers(struct drm_device *dev, void *data, struct drm_file *file_priv); -extern void r128_freelist_reset(struct drm_device * dev); +extern void r128_freelist_reset(struct drm_device *dev); -extern int r128_wait_ring(drm_r128_private_t * dev_priv, int n); +extern int r128_wait_ring(drm_r128_private_t *dev_priv, int n); -extern int r128_do_cce_idle(drm_r128_private_t * dev_priv); -extern int r128_do_cleanup_cce(struct drm_device * dev); +extern int r128_do_cce_idle(drm_r128_private_t *dev_priv); +extern int r128_do_cleanup_cce(struct drm_device *dev); extern int r128_enable_vblank(struct drm_device *dev, int crtc); extern void r128_disable_vblank(struct drm_device *dev, int crtc); extern u32 r128_get_vblank_counter(struct drm_device *dev, int crtc); extern irqreturn_t r128_driver_irq_handler(DRM_IRQ_ARGS); -extern void r128_driver_irq_preinstall(struct drm_device * dev); +extern void r128_driver_irq_preinstall(struct drm_device *dev); extern int r128_driver_irq_postinstall(struct drm_device *dev); -extern void r128_driver_irq_uninstall(struct drm_device * dev); -extern void r128_driver_lastclose(struct drm_device * dev); -extern int r128_driver_load(struct drm_device * dev, unsigned long flags); -extern void r128_driver_preclose(struct drm_device * dev, +extern void r128_driver_irq_uninstall(struct drm_device *dev); +extern void r128_driver_lastclose(struct drm_device *dev); +extern int r128_driver_load(struct drm_device *dev, unsigned long flags); +extern void r128_driver_preclose(struct drm_device *dev, struct drm_file *file_priv); extern long r128_compat_ioctl(struct file *filp, unsigned int cmd, @@ -390,27 +390,27 @@ extern long r128_compat_ioctl(struct file *filp, unsigned int cmd, #define R128_PCIGART_TABLE_SIZE 32768 -#define R128_READ(reg) DRM_READ32( dev_priv->mmio, (reg) ) -#define R128_WRITE(reg,val) DRM_WRITE32( dev_priv->mmio, (reg), (val) ) -#define R128_READ8(reg) DRM_READ8( dev_priv->mmio, (reg) ) -#define R128_WRITE8(reg,val) DRM_WRITE8( dev_priv->mmio, (reg), (val) ) +#define R128_READ(reg) DRM_READ32(dev_priv->mmio, (reg)) +#define R128_WRITE(reg, val) DRM_WRITE32(dev_priv->mmio, (reg), (val)) +#define R128_READ8(reg) DRM_READ8(dev_priv->mmio, (reg)) +#define R128_WRITE8(reg, val) DRM_WRITE8(dev_priv->mmio, (reg), (val)) -#define R128_WRITE_PLL(addr,val) \ +#define R128_WRITE_PLL(addr, val) \ do { \ R128_WRITE8(R128_CLOCK_CNTL_INDEX, \ ((addr) & 0x1f) | R128_PLL_WR_EN); \ R128_WRITE(R128_CLOCK_CNTL_DATA, (val)); \ } while (0) -#define CCE_PACKET0( reg, n ) (R128_CCE_PACKET0 | \ +#define CCE_PACKET0(reg, n) (R128_CCE_PACKET0 | \ ((n) << 16) | ((reg) >> 2)) -#define CCE_PACKET1( reg0, reg1 ) (R128_CCE_PACKET1 | \ +#define CCE_PACKET1(reg0, reg1) (R128_CCE_PACKET1 | \ (((reg1) >> 2) << 11) | ((reg0) >> 2)) #define CCE_PACKET2() (R128_CCE_PACKET2) -#define CCE_PACKET3( pkt, n ) (R128_CCE_PACKET3 | \ +#define CCE_PACKET3(pkt, n) (R128_CCE_PACKET3 | \ (pkt) | ((n) << 16)) -static __inline__ void r128_update_ring_snapshot(drm_r128_private_t * dev_priv) +static __inline__ void r128_update_ring_snapshot(drm_r128_private_t *dev_priv) { drm_r128_ring_buffer_t *ring = &dev_priv->ring; ring->space = (GET_RING_HEAD(dev_priv) - ring->tail) * sizeof(u32); @@ -430,37 +430,38 @@ do { \ } \ } while (0) -#define RING_SPACE_TEST_WITH_RETURN( dev_priv ) \ +#define RING_SPACE_TEST_WITH_RETURN(dev_priv) \ do { \ drm_r128_ring_buffer_t *ring = &dev_priv->ring; int i; \ - if ( ring->space < ring->high_mark ) { \ - for ( i = 0 ; i < dev_priv->usec_timeout ; i++ ) { \ - r128_update_ring_snapshot( dev_priv ); \ - if ( ring->space >= ring->high_mark ) \ + if (ring->space < ring->high_mark) { \ + for (i = 0 ; i < dev_priv->usec_timeout ; i++) { \ + r128_update_ring_snapshot(dev_priv); \ + if (ring->space >= ring->high_mark) \ goto __ring_space_done; \ - DRM_UDELAY(1); \ + DRM_UDELAY(1); \ } \ - DRM_ERROR( "ring space check failed!\n" ); \ - return -EBUSY; \ + DRM_ERROR("ring space check failed!\n"); \ + return -EBUSY; \ } \ __ring_space_done: \ ; \ } while (0) -#define VB_AGE_TEST_WITH_RETURN( dev_priv ) \ +#define VB_AGE_TEST_WITH_RETURN(dev_priv) \ do { \ drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv; \ - if ( sarea_priv->last_dispatch >= R128_MAX_VB_AGE ) { \ - int __ret = r128_do_cce_idle( dev_priv ); \ - if ( __ret ) return __ret; \ + if (sarea_priv->last_dispatch >= R128_MAX_VB_AGE) { \ + int __ret = r128_do_cce_idle(dev_priv); \ + if (__ret) \ + return __ret; \ sarea_priv->last_dispatch = 0; \ - r128_freelist_reset( dev ); \ + r128_freelist_reset(dev); \ } \ } while (0) #define R128_WAIT_UNTIL_PAGE_FLIPPED() do { \ - OUT_RING( CCE_PACKET0( R128_WAIT_UNTIL, 0 ) ); \ - OUT_RING( R128_EVENT_CRTC_OFFSET ); \ + OUT_RING(CCE_PACKET0(R128_WAIT_UNTIL, 0)); \ + OUT_RING(R128_EVENT_CRTC_OFFSET); \ } while (0) /* ================================================================ @@ -472,13 +473,12 @@ do { \ #define RING_LOCALS \ int write, _nr; unsigned int tail_mask; volatile u32 *ring; -#define BEGIN_RING( n ) do { \ - if ( R128_VERBOSE ) { \ - DRM_INFO( "BEGIN_RING( %d )\n", (n)); \ - } \ - if ( dev_priv->ring.space <= (n) * sizeof(u32) ) { \ +#define BEGIN_RING(n) do { \ + if (R128_VERBOSE) \ + DRM_INFO("BEGIN_RING(%d)\n", (n)); \ + if (dev_priv->ring.space <= (n) * sizeof(u32)) { \ COMMIT_RING(); \ - r128_wait_ring( dev_priv, (n) * sizeof(u32) ); \ + r128_wait_ring(dev_priv, (n) * sizeof(u32)); \ } \ _nr = n; dev_priv->ring.space -= (n) * sizeof(u32); \ ring = dev_priv->ring.start; \ @@ -494,40 +494,36 @@ do { \ #define R128_BROKEN_CCE 1 #define ADVANCE_RING() do { \ - if ( R128_VERBOSE ) { \ - DRM_INFO( "ADVANCE_RING() wr=0x%06x tail=0x%06x\n", \ - write, dev_priv->ring.tail ); \ - } \ - if ( R128_BROKEN_CCE && write < 32 ) { \ - memcpy( dev_priv->ring.end, \ - dev_priv->ring.start, \ - write * sizeof(u32) ); \ - } \ - if (((dev_priv->ring.tail + _nr) & tail_mask) != write) { \ + if (R128_VERBOSE) \ + DRM_INFO("ADVANCE_RING() wr=0x%06x tail=0x%06x\n", \ + write, dev_priv->ring.tail); \ + if (R128_BROKEN_CCE && write < 32) \ + memcpy(dev_priv->ring.end, \ + dev_priv->ring.start, \ + write * sizeof(u32)); \ + if (((dev_priv->ring.tail + _nr) & tail_mask) != write) \ DRM_ERROR( \ "ADVANCE_RING(): mismatch: nr: %x write: %x line: %d\n", \ ((dev_priv->ring.tail + _nr) & tail_mask), \ write, __LINE__); \ - } else \ + else \ dev_priv->ring.tail = write; \ } while (0) #define COMMIT_RING() do { \ - if ( R128_VERBOSE ) { \ - DRM_INFO( "COMMIT_RING() tail=0x%06x\n", \ - dev_priv->ring.tail ); \ - } \ + if (R128_VERBOSE) \ + DRM_INFO("COMMIT_RING() tail=0x%06x\n", \ + dev_priv->ring.tail); \ DRM_MEMORYBARRIER(); \ - R128_WRITE( R128_PM4_BUFFER_DL_WPTR, dev_priv->ring.tail ); \ - R128_READ( R128_PM4_BUFFER_DL_WPTR ); \ + R128_WRITE(R128_PM4_BUFFER_DL_WPTR, dev_priv->ring.tail); \ + R128_READ(R128_PM4_BUFFER_DL_WPTR); \ } while (0) -#define OUT_RING( x ) do { \ - if ( R128_VERBOSE ) { \ - DRM_INFO( " OUT_RING( 0x%08x ) at 0x%x\n", \ - (unsigned int)(x), write ); \ - } \ - ring[write++] = cpu_to_le32( x ); \ +#define OUT_RING(x) do { \ + if (R128_VERBOSE) \ + DRM_INFO(" OUT_RING( 0x%08x ) at 0x%x\n", \ + (unsigned int)(x), write); \ + ring[write++] = cpu_to_le32(x); \ write &= tail_mask; \ } while (0) diff --git a/drivers/gpu/drm/r128/r128_irq.c b/drivers/gpu/drm/r128/r128_irq.c index 69810fb..429d5a0 100644 --- a/drivers/gpu/drm/r128/r128_irq.c +++ b/drivers/gpu/drm/r128/r128_irq.c @@ -90,7 +90,7 @@ void r128_disable_vblank(struct drm_device *dev, int crtc) */ } -void r128_driver_irq_preinstall(struct drm_device * dev) +void r128_driver_irq_preinstall(struct drm_device *dev) { drm_r128_private_t *dev_priv = (drm_r128_private_t *) dev->dev_private; @@ -105,7 +105,7 @@ int r128_driver_irq_postinstall(struct drm_device *dev) return 0; } -void r128_driver_irq_uninstall(struct drm_device * dev) +void r128_driver_irq_uninstall(struct drm_device *dev) { drm_r128_private_t *dev_priv = (drm_r128_private_t *) dev->dev_private; if (!dev_priv) diff --git a/drivers/gpu/drm/r128/r128_state.c b/drivers/gpu/drm/r128/r128_state.c index af2665c..077af1f 100644 --- a/drivers/gpu/drm/r128/r128_state.c +++ b/drivers/gpu/drm/r128/r128_state.c @@ -37,8 +37,8 @@ * CCE hardware state programming functions */ -static void r128_emit_clip_rects(drm_r128_private_t * dev_priv, - struct drm_clip_rect * boxes, int count) +static void r128_emit_clip_rects(drm_r128_private_t *dev_priv, + struct drm_clip_rect *boxes, int count) { u32 aux_sc_cntl = 0x00000000; RING_LOCALS; @@ -80,7 +80,7 @@ static void r128_emit_clip_rects(drm_r128_private_t * dev_priv, ADVANCE_RING(); } -static __inline__ void r128_emit_core(drm_r128_private_t * dev_priv) +static __inline__ void r128_emit_core(drm_r128_private_t *dev_priv) { drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv; drm_r128_context_regs_t *ctx = &sarea_priv->context_state; @@ -95,7 +95,7 @@ static __inline__ void r128_emit_core(drm_r128_private_t * dev_priv) ADVANCE_RING(); } -static __inline__ void r128_emit_context(drm_r128_private_t * dev_priv) +static __inline__ void r128_emit_context(drm_r128_private_t *dev_priv) { drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv; drm_r128_context_regs_t *ctx = &sarea_priv->context_state; @@ -121,7 +121,7 @@ static __inline__ void r128_emit_context(drm_r128_private_t * dev_priv) ADVANCE_RING(); } -static __inline__ void r128_emit_setup(drm_r128_private_t * dev_priv) +static __inline__ void r128_emit_setup(drm_r128_private_t *dev_priv) { drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv; drm_r128_context_regs_t *ctx = &sarea_priv->context_state; @@ -137,7 +137,7 @@ static __inline__ void r128_emit_setup(drm_r128_private_t * dev_priv) ADVANCE_RING(); } -static __inline__ void r128_emit_masks(drm_r128_private_t * dev_priv) +static __inline__ void r128_emit_masks(drm_r128_private_t *dev_priv) { drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv; drm_r128_context_regs_t *ctx = &sarea_priv->context_state; @@ -156,7 +156,7 @@ static __inline__ void r128_emit_masks(drm_r128_private_t * dev_priv) ADVANCE_RING(); } -static __inline__ void r128_emit_window(drm_r128_private_t * dev_priv) +static __inline__ void r128_emit_window(drm_r128_private_t *dev_priv) { drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv; drm_r128_context_regs_t *ctx = &sarea_priv->context_state; @@ -171,7 +171,7 @@ static __inline__ void r128_emit_window(drm_r128_private_t * dev_priv) ADVANCE_RING(); } -static __inline__ void r128_emit_tex0(drm_r128_private_t * dev_priv) +static __inline__ void r128_emit_tex0(drm_r128_private_t *dev_priv) { drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv; drm_r128_context_regs_t *ctx = &sarea_priv->context_state; @@ -187,9 +187,8 @@ static __inline__ void r128_emit_tex0(drm_r128_private_t * dev_priv) OUT_RING(tex->tex_cntl); OUT_RING(tex->tex_combine_cntl); OUT_RING(ctx->tex_size_pitch_c); - for (i = 0; i < R128_MAX_TEXTURE_LEVELS; i++) { + for (i = 0; i < R128_MAX_TEXTURE_LEVELS; i++) OUT_RING(tex->tex_offset[i]); - } OUT_RING(CCE_PACKET0(R128_CONSTANT_COLOR_C, 1)); OUT_RING(ctx->constant_color_c); @@ -198,7 +197,7 @@ static __inline__ void r128_emit_tex0(drm_r128_private_t * dev_priv) ADVANCE_RING(); } -static __inline__ void r128_emit_tex1(drm_r128_private_t * dev_priv) +static __inline__ void r128_emit_tex1(drm_r128_private_t *dev_priv) { drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv; drm_r128_texture_regs_t *tex = &sarea_priv->tex_state[1]; @@ -211,9 +210,8 @@ static __inline__ void r128_emit_tex1(drm_r128_private_t * dev_priv) OUT_RING(CCE_PACKET0(R128_SEC_TEX_CNTL_C, 1 + R128_MAX_TEXTURE_LEVELS)); OUT_RING(tex->tex_cntl); OUT_RING(tex->tex_combine_cntl); - for (i = 0; i < R128_MAX_TEXTURE_LEVELS; i++) { + for (i = 0; i < R128_MAX_TEXTURE_LEVELS; i++) OUT_RING(tex->tex_offset[i]); - } OUT_RING(CCE_PACKET0(R128_SEC_TEXTURE_BORDER_COLOR_C, 0)); OUT_RING(tex->tex_border_color); @@ -221,7 +219,7 @@ static __inline__ void r128_emit_tex1(drm_r128_private_t * dev_priv) ADVANCE_RING(); } -static void r128_emit_state(drm_r128_private_t * dev_priv) +static void r128_emit_state(drm_r128_private_t *dev_priv) { drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv; unsigned int dirty = sarea_priv->dirty; @@ -274,7 +272,7 @@ static void r128_emit_state(drm_r128_private_t * dev_priv) * Performance monitoring functions */ -static void r128_clear_box(drm_r128_private_t * dev_priv, +static void r128_clear_box(drm_r128_private_t *dev_priv, int x, int y, int w, int h, int r, int g, int b) { u32 pitch, offset; @@ -321,13 +319,12 @@ static void r128_clear_box(drm_r128_private_t * dev_priv, ADVANCE_RING(); } -static void r128_cce_performance_boxes(drm_r128_private_t * dev_priv) +static void r128_cce_performance_boxes(drm_r128_private_t *dev_priv) { - if (atomic_read(&dev_priv->idle_count) == 0) { + if (atomic_read(&dev_priv->idle_count) == 0) r128_clear_box(dev_priv, 64, 4, 8, 8, 0, 255, 0); - } else { + else atomic_set(&dev_priv->idle_count, 0); - } } #endif @@ -352,8 +349,8 @@ static void r128_print_dirty(const char *msg, unsigned int flags) (flags & R128_REQUIRE_QUIESCENCE) ? "quiescence, " : ""); } -static void r128_cce_dispatch_clear(struct drm_device * dev, - drm_r128_clear_t * clear) +static void r128_cce_dispatch_clear(struct drm_device *dev, + drm_r128_clear_t *clear) { drm_r128_private_t *dev_priv = dev->dev_private; drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv; @@ -458,7 +455,7 @@ static void r128_cce_dispatch_clear(struct drm_device * dev, } } -static void r128_cce_dispatch_swap(struct drm_device * dev) +static void r128_cce_dispatch_swap(struct drm_device *dev) { drm_r128_private_t *dev_priv = dev->dev_private; drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv; @@ -524,7 +521,7 @@ static void r128_cce_dispatch_swap(struct drm_device * dev) ADVANCE_RING(); } -static void r128_cce_dispatch_flip(struct drm_device * dev) +static void r128_cce_dispatch_flip(struct drm_device *dev) { drm_r128_private_t *dev_priv = dev->dev_private; RING_LOCALS; @@ -542,11 +539,10 @@ static void r128_cce_dispatch_flip(struct drm_device * dev) R128_WAIT_UNTIL_PAGE_FLIPPED(); OUT_RING(CCE_PACKET0(R128_CRTC_OFFSET, 0)); - if (dev_priv->current_page == 0) { + if (dev_priv->current_page == 0) OUT_RING(dev_priv->back_offset); - } else { + else OUT_RING(dev_priv->front_offset); - } ADVANCE_RING(); @@ -566,7 +562,7 @@ static void r128_cce_dispatch_flip(struct drm_device * dev) ADVANCE_RING(); } -static void r128_cce_dispatch_vertex(struct drm_device * dev, struct drm_buf * buf) +static void r128_cce_dispatch_vertex(struct drm_device *dev, struct drm_buf *buf) { drm_r128_private_t *dev_priv = dev->dev_private; drm_r128_buf_priv_t *buf_priv = buf->dev_private; @@ -585,9 +581,8 @@ static void r128_cce_dispatch_vertex(struct drm_device * dev, struct drm_buf * b if (buf->used) { buf_priv->dispatched = 1; - if (sarea_priv->dirty & ~R128_UPLOAD_CLIPRECTS) { + if (sarea_priv->dirty & ~R128_UPLOAD_CLIPRECTS) r128_emit_state(dev_priv); - } do { /* Emit the next set of up to three cliprects */ @@ -636,8 +631,8 @@ static void r128_cce_dispatch_vertex(struct drm_device * dev, struct drm_buf * b sarea_priv->nbox = 0; } -static void r128_cce_dispatch_indirect(struct drm_device * dev, - struct drm_buf * buf, int start, int end) +static void r128_cce_dispatch_indirect(struct drm_device *dev, + struct drm_buf *buf, int start, int end) { drm_r128_private_t *dev_priv = dev->dev_private; drm_r128_buf_priv_t *buf_priv = buf->dev_private; @@ -691,8 +686,8 @@ static void r128_cce_dispatch_indirect(struct drm_device * dev, dev_priv->sarea_priv->last_dispatch++; } -static void r128_cce_dispatch_indices(struct drm_device * dev, - struct drm_buf * buf, +static void r128_cce_dispatch_indices(struct drm_device *dev, + struct drm_buf *buf, int start, int end, int count) { drm_r128_private_t *dev_priv = dev->dev_private; @@ -713,9 +708,8 @@ static void r128_cce_dispatch_indices(struct drm_device * dev, if (start != end) { buf_priv->dispatched = 1; - if (sarea_priv->dirty & ~R128_UPLOAD_CLIPRECTS) { + if (sarea_priv->dirty & ~R128_UPLOAD_CLIPRECTS) r128_emit_state(dev_priv); - } dwords = (end - start + 3) / sizeof(u32); @@ -775,9 +769,9 @@ static void r128_cce_dispatch_indices(struct drm_device * dev, sarea_priv->nbox = 0; } -static int r128_cce_dispatch_blit(struct drm_device * dev, +static int r128_cce_dispatch_blit(struct drm_device *dev, struct drm_file *file_priv, - drm_r128_blit_t * blit) + drm_r128_blit_t *blit) { drm_r128_private_t *dev_priv = dev->dev_private; struct drm_device_dma *dma = dev->dma; @@ -887,8 +881,8 @@ static int r128_cce_dispatch_blit(struct drm_device * dev, * have hardware stencil support. */ -static int r128_cce_dispatch_write_span(struct drm_device * dev, - drm_r128_depth_t * depth) +static int r128_cce_dispatch_write_span(struct drm_device *dev, + drm_r128_depth_t *depth) { drm_r128_private_t *dev_priv = dev->dev_private; int count, x, y; @@ -902,12 +896,10 @@ static int r128_cce_dispatch_write_span(struct drm_device * dev, if (count > 4096 || count <= 0) return -EMSGSIZE; - if (DRM_COPY_FROM_USER(&x, depth->x, sizeof(x))) { + if (DRM_COPY_FROM_USER(&x, depth->x, sizeof(x))) return -EFAULT; - } - if (DRM_COPY_FROM_USER(&y, depth->y, sizeof(y))) { + if (DRM_COPY_FROM_USER(&y, depth->y, sizeof(y))) return -EFAULT; - } buffer_size = depth->n * sizeof(u32); buffer = kmalloc(buffer_size, GFP_KERNEL); @@ -983,8 +975,8 @@ static int r128_cce_dispatch_write_span(struct drm_device * dev, return 0; } -static int r128_cce_dispatch_write_pixels(struct drm_device * dev, - drm_r128_depth_t * depth) +static int r128_cce_dispatch_write_pixels(struct drm_device *dev, + drm_r128_depth_t *depth) { drm_r128_private_t *dev_priv = dev->dev_private; int count, *x, *y; @@ -1001,9 +993,8 @@ static int r128_cce_dispatch_write_pixels(struct drm_device * dev, xbuf_size = count * sizeof(*x); ybuf_size = count * sizeof(*y); x = kmalloc(xbuf_size, GFP_KERNEL); - if (x == NULL) { + if (x == NULL) return -ENOMEM; - } y = kmalloc(ybuf_size, GFP_KERNEL); if (y == NULL) { kfree(x); @@ -1105,8 +1096,8 @@ static int r128_cce_dispatch_write_pixels(struct drm_device * dev, return 0; } -static int r128_cce_dispatch_read_span(struct drm_device * dev, - drm_r128_depth_t * depth) +static int r128_cce_dispatch_read_span(struct drm_device *dev, + drm_r128_depth_t *depth) { drm_r128_private_t *dev_priv = dev->dev_private; int count, x, y; @@ -1117,12 +1108,10 @@ static int r128_cce_dispatch_read_span(struct drm_device * dev, if (count > 4096 || count <= 0) return -EMSGSIZE; - if (DRM_COPY_FROM_USER(&x, depth->x, sizeof(x))) { + if (DRM_COPY_FROM_USER(&x, depth->x, sizeof(x))) return -EFAULT; - } - if (DRM_COPY_FROM_USER(&y, depth->y, sizeof(y))) { + if (DRM_COPY_FROM_USER(&y, depth->y, sizeof(y))) return -EFAULT; - } BEGIN_RING(7); @@ -1148,8 +1137,8 @@ static int r128_cce_dispatch_read_span(struct drm_device * dev, return 0; } -static int r128_cce_dispatch_read_pixels(struct drm_device * dev, - drm_r128_depth_t * depth) +static int r128_cce_dispatch_read_pixels(struct drm_device *dev, + drm_r128_depth_t *depth) { drm_r128_private_t *dev_priv = dev->dev_private; int count, *x, *y; @@ -1161,16 +1150,14 @@ static int r128_cce_dispatch_read_pixels(struct drm_device * dev, if (count > 4096 || count <= 0) return -EMSGSIZE; - if (count > dev_priv->depth_pitch) { + if (count > dev_priv->depth_pitch) count = dev_priv->depth_pitch; - } xbuf_size = count * sizeof(*x); ybuf_size = count * sizeof(*y); x = kmalloc(xbuf_size, GFP_KERNEL); - if (x == NULL) { + if (x == NULL) return -ENOMEM; - } y = kmalloc(ybuf_size, GFP_KERNEL); if (y == NULL) { kfree(x); @@ -1220,7 +1207,7 @@ static int r128_cce_dispatch_read_pixels(struct drm_device * dev, * Polygon stipple */ -static void r128_cce_dispatch_stipple(struct drm_device * dev, u32 * stipple) +static void r128_cce_dispatch_stipple(struct drm_device *dev, u32 *stipple) { drm_r128_private_t *dev_priv = dev->dev_private; int i; @@ -1230,9 +1217,8 @@ static void r128_cce_dispatch_stipple(struct drm_device * dev, u32 * stipple) BEGIN_RING(33); OUT_RING(CCE_PACKET0(R128_BRUSH_DATA0, 31)); - for (i = 0; i < 32; i++) { + for (i = 0; i < 32; i++) OUT_RING(stipple[i]); - } ADVANCE_RING(); } @@ -1269,7 +1255,7 @@ static int r128_cce_clear(struct drm_device *dev, void *data, struct drm_file *f return 0; } -static int r128_do_init_pageflip(struct drm_device * dev) +static int r128_do_init_pageflip(struct drm_device *dev) { drm_r128_private_t *dev_priv = dev->dev_private; DRM_DEBUG("\n"); @@ -1288,7 +1274,7 @@ static int r128_do_init_pageflip(struct drm_device * dev) return 0; } -static int r128_do_cleanup_pageflip(struct drm_device * dev) +static int r128_do_cleanup_pageflip(struct drm_device *dev) { drm_r128_private_t *dev_priv = dev->dev_private; DRM_DEBUG("\n"); @@ -1645,17 +1631,16 @@ static int r128_getparam(struct drm_device *dev, void *data, struct drm_file *fi return 0; } -void r128_driver_preclose(struct drm_device * dev, struct drm_file *file_priv) +void r128_driver_preclose(struct drm_device *dev, struct drm_file *file_priv) { if (dev->dev_private) { drm_r128_private_t *dev_priv = dev->dev_private; - if (dev_priv->page_flipping) { + if (dev_priv->page_flipping) r128_do_cleanup_pageflip(dev); - } } } -void r128_driver_lastclose(struct drm_device * dev) +void r128_driver_lastclose(struct drm_device *dev) { r128_do_cleanup_cce(dev); } diff --git a/drivers/gpu/drm/radeon/Makefile b/drivers/gpu/drm/radeon/Makefile index 84b1f27..aebe008 100644 --- a/drivers/gpu/drm/radeon/Makefile +++ b/drivers/gpu/drm/radeon/Makefile @@ -69,5 +69,6 @@ radeon-y += radeon_device.o radeon_asic.o radeon_kms.o \ radeon-$(CONFIG_COMPAT) += radeon_ioc32.o radeon-$(CONFIG_VGA_SWITCHEROO) += radeon_atpx_handler.o +radeon-$(CONFIG_ACPI) += radeon_acpi.o obj-$(CONFIG_DRM_RADEON)+= radeon.o diff --git a/drivers/gpu/drm/radeon/atom.c b/drivers/gpu/drm/radeon/atom.c index 1d56983..8e421f6 100644 --- a/drivers/gpu/drm/radeon/atom.c +++ b/drivers/gpu/drm/radeon/atom.c @@ -108,12 +108,11 @@ static uint32_t atom_iio_execute(struct atom_context *ctx, int base, base++; break; case ATOM_IIO_READ: - temp = ctx->card->reg_read(ctx->card, CU16(base + 1)); + temp = ctx->card->ioreg_read(ctx->card, CU16(base + 1)); base += 3; break; case ATOM_IIO_WRITE: - (void)ctx->card->reg_read(ctx->card, CU16(base + 1)); - ctx->card->reg_write(ctx->card, CU16(base + 1), temp); + ctx->card->ioreg_write(ctx->card, CU16(base + 1), temp); base += 3; break; case ATOM_IIO_CLEAR: @@ -715,8 +714,8 @@ static void atom_op_jump(atom_exec_context *ctx, int *ptr, int arg) cjiffies = jiffies; if (time_after(cjiffies, ctx->last_jump_jiffies)) { cjiffies -= ctx->last_jump_jiffies; - if ((jiffies_to_msecs(cjiffies) > 1000)) { - DRM_ERROR("atombios stuck in loop for more than 1sec aborting\n"); + if ((jiffies_to_msecs(cjiffies) > 5000)) { + DRM_ERROR("atombios stuck in loop for more than 5secs aborting\n"); ctx->abort = true; } } else { diff --git a/drivers/gpu/drm/radeon/atom.h b/drivers/gpu/drm/radeon/atom.h index cd1b64a..a589a55 100644 --- a/drivers/gpu/drm/radeon/atom.h +++ b/drivers/gpu/drm/radeon/atom.h @@ -113,6 +113,8 @@ struct card_info { struct drm_device *dev; void (* reg_write)(struct card_info *, uint32_t, uint32_t); /* filled by driver */ uint32_t (* reg_read)(struct card_info *, uint32_t); /* filled by driver */ + void (* ioreg_write)(struct card_info *, uint32_t, uint32_t); /* filled by driver */ + uint32_t (* ioreg_read)(struct card_info *, uint32_t); /* filled by driver */ void (* mc_write)(struct card_info *, uint32_t, uint32_t); /* filled by driver */ uint32_t (* mc_read)(struct card_info *, uint32_t); /* filled by driver */ void (* pll_write)(struct card_info *, uint32_t, uint32_t); /* filled by driver */ diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index 8c2d647..12ad512 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -44,10 +44,6 @@ static void atombios_overscan_setup(struct drm_crtc *crtc, memset(&args, 0, sizeof(args)); - args.usOverscanRight = 0; - args.usOverscanLeft = 0; - args.usOverscanBottom = 0; - args.usOverscanTop = 0; args.ucCRTC = radeon_crtc->crtc_id; switch (radeon_crtc->rmx_type) { @@ -56,7 +52,6 @@ static void atombios_overscan_setup(struct drm_crtc *crtc, args.usOverscanBottom = (adjusted_mode->crtc_vdisplay - mode->crtc_vdisplay) / 2; args.usOverscanLeft = (adjusted_mode->crtc_hdisplay - mode->crtc_hdisplay) / 2; args.usOverscanRight = (adjusted_mode->crtc_hdisplay - mode->crtc_hdisplay) / 2; - atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); break; case RMX_ASPECT: a1 = mode->crtc_vdisplay * adjusted_mode->crtc_hdisplay; @@ -69,17 +64,16 @@ static void atombios_overscan_setup(struct drm_crtc *crtc, args.usOverscanLeft = (adjusted_mode->crtc_vdisplay - (a1 / mode->crtc_hdisplay)) / 2; args.usOverscanRight = (adjusted_mode->crtc_vdisplay - (a1 / mode->crtc_hdisplay)) / 2; } - atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); break; case RMX_FULL: default: - args.usOverscanRight = 0; - args.usOverscanLeft = 0; - args.usOverscanBottom = 0; - args.usOverscanTop = 0; - atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); + args.usOverscanRight = radeon_crtc->h_border; + args.usOverscanLeft = radeon_crtc->h_border; + args.usOverscanBottom = radeon_crtc->v_border; + args.usOverscanTop = radeon_crtc->v_border; break; } + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); } static void atombios_scaler_setup(struct drm_crtc *crtc) @@ -282,22 +276,22 @@ atombios_set_crtc_dtd_timing(struct drm_crtc *crtc, u16 misc = 0; memset(&args, 0, sizeof(args)); - args.usH_Size = cpu_to_le16(mode->crtc_hdisplay); + args.usH_Size = cpu_to_le16(mode->crtc_hdisplay - (radeon_crtc->h_border * 2)); args.usH_Blanking_Time = - cpu_to_le16(mode->crtc_hblank_end - mode->crtc_hdisplay); - args.usV_Size = cpu_to_le16(mode->crtc_vdisplay); + cpu_to_le16(mode->crtc_hblank_end - mode->crtc_hdisplay + (radeon_crtc->h_border * 2)); + args.usV_Size = cpu_to_le16(mode->crtc_vdisplay - (radeon_crtc->v_border * 2)); args.usV_Blanking_Time = - cpu_to_le16(mode->crtc_vblank_end - mode->crtc_vdisplay); + cpu_to_le16(mode->crtc_vblank_end - mode->crtc_vdisplay + (radeon_crtc->v_border * 2)); args.usH_SyncOffset = - cpu_to_le16(mode->crtc_hsync_start - mode->crtc_hdisplay); + cpu_to_le16(mode->crtc_hsync_start - mode->crtc_hdisplay + radeon_crtc->h_border); args.usH_SyncWidth = cpu_to_le16(mode->crtc_hsync_end - mode->crtc_hsync_start); args.usV_SyncOffset = - cpu_to_le16(mode->crtc_vsync_start - mode->crtc_vdisplay); + cpu_to_le16(mode->crtc_vsync_start - mode->crtc_vdisplay + radeon_crtc->v_border); args.usV_SyncWidth = cpu_to_le16(mode->crtc_vsync_end - mode->crtc_vsync_start); - /*args.ucH_Border = mode->hborder;*/ - /*args.ucV_Border = mode->vborder;*/ + args.ucH_Border = radeon_crtc->h_border; + args.ucV_Border = radeon_crtc->v_border; if (mode->flags & DRM_MODE_FLAG_NVSYNC) misc |= ATOM_VSYNC_POLARITY; @@ -669,56 +663,25 @@ static void atombios_crtc_set_dcpll(struct drm_crtc *crtc) atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); } -static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) +static void atombios_crtc_program_pll(struct drm_crtc *crtc, + int crtc_id, + int pll_id, + u32 encoder_mode, + u32 encoder_id, + u32 clock, + u32 ref_div, + u32 fb_div, + u32 frac_fb_div, + u32 post_div) { - struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); struct drm_device *dev = crtc->dev; struct radeon_device *rdev = dev->dev_private; - struct drm_encoder *encoder = NULL; - struct radeon_encoder *radeon_encoder = NULL; u8 frev, crev; - int index; + int index = GetIndexIntoMasterTable(COMMAND, SetPixelClock); union set_pixel_clock args; - u32 pll_clock = mode->clock; - u32 ref_div = 0, fb_div = 0, frac_fb_div = 0, post_div = 0; - struct radeon_pll *pll; - u32 adjusted_clock; - int encoder_mode = 0; memset(&args, 0, sizeof(args)); - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { - if (encoder->crtc == crtc) { - radeon_encoder = to_radeon_encoder(encoder); - encoder_mode = atombios_get_encoder_mode(encoder); - break; - } - } - - if (!radeon_encoder) - return; - - switch (radeon_crtc->pll_id) { - case ATOM_PPLL1: - pll = &rdev->clock.p1pll; - break; - case ATOM_PPLL2: - pll = &rdev->clock.p2pll; - break; - case ATOM_DCPLL: - case ATOM_PPLL_INVALID: - default: - pll = &rdev->clock.dcpll; - break; - } - - /* adjust pixel clock as needed */ - adjusted_clock = atombios_adjust_pll(crtc, mode, pll); - - radeon_compute_pll(pll, adjusted_clock, &pll_clock, &fb_div, &frac_fb_div, - &ref_div, &post_div); - - index = GetIndexIntoMasterTable(COMMAND, SetPixelClock); if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) return; @@ -727,47 +690,49 @@ static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode case 1: switch (crev) { case 1: - args.v1.usPixelClock = cpu_to_le16(mode->clock / 10); + if (clock == ATOM_DISABLE) + return; + args.v1.usPixelClock = cpu_to_le16(clock / 10); args.v1.usRefDiv = cpu_to_le16(ref_div); args.v1.usFbDiv = cpu_to_le16(fb_div); args.v1.ucFracFbDiv = frac_fb_div; args.v1.ucPostDiv = post_div; - args.v1.ucPpll = radeon_crtc->pll_id; - args.v1.ucCRTC = radeon_crtc->crtc_id; + args.v1.ucPpll = pll_id; + args.v1.ucCRTC = crtc_id; args.v1.ucRefDivSrc = 1; break; case 2: - args.v2.usPixelClock = cpu_to_le16(mode->clock / 10); + args.v2.usPixelClock = cpu_to_le16(clock / 10); args.v2.usRefDiv = cpu_to_le16(ref_div); args.v2.usFbDiv = cpu_to_le16(fb_div); args.v2.ucFracFbDiv = frac_fb_div; args.v2.ucPostDiv = post_div; - args.v2.ucPpll = radeon_crtc->pll_id; - args.v2.ucCRTC = radeon_crtc->crtc_id; + args.v2.ucPpll = pll_id; + args.v2.ucCRTC = crtc_id; args.v2.ucRefDivSrc = 1; break; case 3: - args.v3.usPixelClock = cpu_to_le16(mode->clock / 10); + args.v3.usPixelClock = cpu_to_le16(clock / 10); args.v3.usRefDiv = cpu_to_le16(ref_div); args.v3.usFbDiv = cpu_to_le16(fb_div); args.v3.ucFracFbDiv = frac_fb_div; args.v3.ucPostDiv = post_div; - args.v3.ucPpll = radeon_crtc->pll_id; - args.v3.ucMiscInfo = (radeon_crtc->pll_id << 2); - args.v3.ucTransmitterId = radeon_encoder->encoder_id; + args.v3.ucPpll = pll_id; + args.v3.ucMiscInfo = (pll_id << 2); + args.v3.ucTransmitterId = encoder_id; args.v3.ucEncoderMode = encoder_mode; break; case 5: - args.v5.ucCRTC = radeon_crtc->crtc_id; - args.v5.usPixelClock = cpu_to_le16(mode->clock / 10); + args.v5.ucCRTC = crtc_id; + args.v5.usPixelClock = cpu_to_le16(clock / 10); args.v5.ucRefDiv = ref_div; args.v5.usFbDiv = cpu_to_le16(fb_div); args.v5.ulFbDivDecFrac = cpu_to_le32(frac_fb_div * 100000); args.v5.ucPostDiv = post_div; args.v5.ucMiscInfo = 0; /* HDMI depth, etc. */ - args.v5.ucTransmitterID = radeon_encoder->encoder_id; + args.v5.ucTransmitterID = encoder_id; args.v5.ucEncoderMode = encoder_mode; - args.v5.ucPpll = radeon_crtc->pll_id; + args.v5.ucPpll = pll_id; break; default: DRM_ERROR("Unknown table version %d %d\n", frev, crev); @@ -782,6 +747,56 @@ static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); } +static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) +{ + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + struct drm_device *dev = crtc->dev; + struct radeon_device *rdev = dev->dev_private; + struct drm_encoder *encoder = NULL; + struct radeon_encoder *radeon_encoder = NULL; + u32 pll_clock = mode->clock; + u32 ref_div = 0, fb_div = 0, frac_fb_div = 0, post_div = 0; + struct radeon_pll *pll; + u32 adjusted_clock; + int encoder_mode = 0; + + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + if (encoder->crtc == crtc) { + radeon_encoder = to_radeon_encoder(encoder); + encoder_mode = atombios_get_encoder_mode(encoder); + break; + } + } + + if (!radeon_encoder) + return; + + switch (radeon_crtc->pll_id) { + case ATOM_PPLL1: + pll = &rdev->clock.p1pll; + break; + case ATOM_PPLL2: + pll = &rdev->clock.p2pll; + break; + case ATOM_DCPLL: + case ATOM_PPLL_INVALID: + default: + pll = &rdev->clock.dcpll; + break; + } + + /* adjust pixel clock as needed */ + adjusted_clock = atombios_adjust_pll(crtc, mode, pll); + + radeon_compute_pll(pll, adjusted_clock, &pll_clock, &fb_div, &frac_fb_div, + &ref_div, &post_div); + + atombios_crtc_program_pll(crtc, radeon_crtc->crtc_id, radeon_crtc->pll_id, + encoder_mode, radeon_encoder->encoder_id, mode->clock, + ref_div, fb_div, frac_fb_div, post_div); + +} + static int evergreen_crtc_set_base(struct drm_crtc *crtc, int x, int y, struct drm_framebuffer *old_fb) { @@ -797,7 +812,7 @@ static int evergreen_crtc_set_base(struct drm_crtc *crtc, int x, int y, /* no fb bound */ if (!crtc->fb) { - DRM_DEBUG("No FB bound\n"); + DRM_DEBUG_KMS("No FB bound\n"); return 0; } @@ -841,6 +856,11 @@ static int evergreen_crtc_set_base(struct drm_crtc *crtc, int x, int y, return -EINVAL; } + if (tiling_flags & RADEON_TILING_MACRO) + fb_format |= EVERGREEN_GRPH_ARRAY_MODE(EVERGREEN_GRPH_ARRAY_2D_TILED_THIN1); + else if (tiling_flags & RADEON_TILING_MICRO) + fb_format |= EVERGREEN_GRPH_ARRAY_MODE(EVERGREEN_GRPH_ARRAY_1D_TILED_THIN1); + switch (radeon_crtc->crtc_id) { case 0: WREG32(AVIVO_D1VGA_CONTROL, 0); @@ -931,7 +951,7 @@ static int avivo_crtc_set_base(struct drm_crtc *crtc, int x, int y, /* no fb bound */ if (!crtc->fb) { - DRM_DEBUG("No FB bound\n"); + DRM_DEBUG_KMS("No FB bound\n"); return 0; } @@ -979,11 +999,18 @@ static int avivo_crtc_set_base(struct drm_crtc *crtc, int x, int y, return -EINVAL; } - if (tiling_flags & RADEON_TILING_MACRO) - fb_format |= AVIVO_D1GRPH_MACRO_ADDRESS_MODE; + if (rdev->family >= CHIP_R600) { + if (tiling_flags & RADEON_TILING_MACRO) + fb_format |= R600_D1GRPH_ARRAY_MODE_2D_TILED_THIN1; + else if (tiling_flags & RADEON_TILING_MICRO) + fb_format |= R600_D1GRPH_ARRAY_MODE_1D_TILED_THIN1; + } else { + if (tiling_flags & RADEON_TILING_MACRO) + fb_format |= AVIVO_D1GRPH_MACRO_ADDRESS_MODE; - if (tiling_flags & RADEON_TILING_MICRO) - fb_format |= AVIVO_D1GRPH_TILED; + if (tiling_flags & RADEON_TILING_MICRO) + fb_format |= AVIVO_D1GRPH_TILED; + } if (radeon_crtc->crtc_id == 0) WREG32(AVIVO_D1VGA_CONTROL, 0); @@ -1143,10 +1170,8 @@ int atombios_crtc_mode_set(struct drm_crtc *crtc, atombios_crtc_set_pll(crtc, adjusted_mode); atombios_enable_ss(crtc); - if (ASIC_IS_DCE4(rdev)) + if (ASIC_IS_AVIVO(rdev)) atombios_set_crtc_dtd_timing(crtc, adjusted_mode); - else if (ASIC_IS_AVIVO(rdev)) - atombios_crtc_set_timing(crtc, adjusted_mode); else { atombios_crtc_set_timing(crtc, adjusted_mode); if (radeon_crtc->crtc_id == 0) @@ -1191,6 +1216,24 @@ static void atombios_crtc_commit(struct drm_crtc *crtc) atombios_lock_crtc(crtc, ATOM_DISABLE); } +static void atombios_crtc_disable(struct drm_crtc *crtc) +{ + struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); + atombios_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); + + switch (radeon_crtc->pll_id) { + case ATOM_PPLL1: + case ATOM_PPLL2: + /* disable the ppll */ + atombios_crtc_program_pll(crtc, radeon_crtc->crtc_id, radeon_crtc->pll_id, + 0, 0, ATOM_DISABLE, 0, 0, 0, 0); + break; + default: + break; + } + radeon_crtc->pll_id = -1; +} + static const struct drm_crtc_helper_funcs atombios_helper_funcs = { .dpms = atombios_crtc_dpms, .mode_fixup = atombios_crtc_mode_fixup, @@ -1199,6 +1242,7 @@ static const struct drm_crtc_helper_funcs atombios_helper_funcs = { .prepare = atombios_crtc_prepare, .commit = atombios_crtc_commit, .load_lut = radeon_crtc_load_lut, + .disable = atombios_crtc_disable, }; void radeon_atombios_init_crtc(struct drm_device *dev, diff --git a/drivers/gpu/drm/radeon/atombios_dp.c b/drivers/gpu/drm/radeon/atombios_dp.c index abffb14..36e0d4b 100644 --- a/drivers/gpu/drm/radeon/atombios_dp.c +++ b/drivers/gpu/drm/radeon/atombios_dp.c @@ -296,7 +296,7 @@ static void dp_get_adjust_train(u8 link_status[DP_LINK_STATUS_SIZE], u8 this_v = dp_get_adjust_request_voltage(link_status, lane); u8 this_p = dp_get_adjust_request_pre_emphasis(link_status, lane); - DRM_DEBUG("requested signal parameters: lane %d voltage %s pre_emph %s\n", + DRM_DEBUG_KMS("requested signal parameters: lane %d voltage %s pre_emph %s\n", lane, voltage_names[this_v >> DP_TRAIN_VOLTAGE_SWING_SHIFT], pre_emph_names[this_p >> DP_TRAIN_PRE_EMPHASIS_SHIFT]); @@ -313,7 +313,7 @@ static void dp_get_adjust_train(u8 link_status[DP_LINK_STATUS_SIZE], if (p >= dp_pre_emphasis_max(v)) p = dp_pre_emphasis_max(v) | DP_TRAIN_MAX_PRE_EMPHASIS_REACHED; - DRM_DEBUG("using signal parameters: voltage %s pre_emph %s\n", + DRM_DEBUG_KMS("using signal parameters: voltage %s pre_emph %s\n", voltage_names[(v & DP_TRAIN_VOLTAGE_SWING_MASK) >> DP_TRAIN_VOLTAGE_SWING_SHIFT], pre_emph_names[(p & DP_TRAIN_PRE_EMPHASIS_MASK) >> DP_TRAIN_PRE_EMPHASIS_SHIFT]); @@ -358,7 +358,7 @@ retry: if (args.v1.ucReplyStatus && !args.v1.ucDataOutLen) { if (args.v1.ucReplyStatus == 0x20 && retry_count++ < 10) goto retry; - DRM_DEBUG("failed to get auxch %02x%02x %02x %02x 0x%02x %02x after %d retries\n", + DRM_DEBUG_KMS("failed to get auxch %02x%02x %02x %02x 0x%02x %02x after %d retries\n", req_bytes[1], req_bytes[0], req_bytes[2], req_bytes[3], chan->rec.i2c_id, args.v1.ucReplyStatus, retry_count); return false; @@ -461,10 +461,10 @@ bool radeon_dp_getdpcd(struct radeon_connector *radeon_connector) memcpy(dig_connector->dpcd, msg, 8); { int i; - DRM_DEBUG("DPCD: "); + DRM_DEBUG_KMS("DPCD: "); for (i = 0; i < 8; i++) - DRM_DEBUG("%02x ", msg[i]); - DRM_DEBUG("\n"); + DRM_DEBUG_KMS("%02x ", msg[i]); + DRM_DEBUG_KMS("\n"); } return true; } @@ -512,7 +512,7 @@ static bool atom_dp_get_link_status(struct radeon_connector *radeon_connector, return false; } - DRM_DEBUG("link status %02x %02x %02x %02x %02x %02x\n", + DRM_DEBUG_KMS("link status %02x %02x %02x %02x %02x %02x\n", link_status[0], link_status[1], link_status[2], link_status[3], link_status[4], link_status[5]); return true; @@ -695,7 +695,7 @@ void dp_link_train(struct drm_encoder *encoder, if (!clock_recovery) DRM_ERROR("clock recovery failed\n"); else - DRM_DEBUG("clock recovery at voltage %d pre-emphasis %d\n", + DRM_DEBUG_KMS("clock recovery at voltage %d pre-emphasis %d\n", train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK, (train_set[0] & DP_TRAIN_PRE_EMPHASIS_MASK) >> DP_TRAIN_PRE_EMPHASIS_SHIFT); @@ -739,7 +739,7 @@ void dp_link_train(struct drm_encoder *encoder, if (!channel_eq) DRM_ERROR("channel eq failed\n"); else - DRM_DEBUG("channel eq at voltage %d pre-emphasis %d\n", + DRM_DEBUG_KMS("channel eq at voltage %d pre-emphasis %d\n", train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK, (train_set[0] & DP_TRAIN_PRE_EMPHASIS_MASK) >> DP_TRAIN_PRE_EMPHASIS_SHIFT); diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 1caf625..957d506 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -39,6 +39,23 @@ static void evergreen_gpu_init(struct radeon_device *rdev); void evergreen_fini(struct radeon_device *rdev); +/* get temperature in millidegrees */ +u32 evergreen_get_temp(struct radeon_device *rdev) +{ + u32 temp = (RREG32(CG_MULT_THERMAL_STATUS) & ASIC_T_MASK) >> + ASIC_T_SHIFT; + u32 actual_temp = 0; + + if ((temp >> 10) & 1) + actual_temp = 0; + else if ((temp >> 9) & 1) + actual_temp = 255; + else + actual_temp = (temp >> 1) & 0xff; + + return actual_temp * 1000; +} + void evergreen_pm_misc(struct radeon_device *rdev) { int req_ps_idx = rdev->pm.requested_power_state_index; @@ -1115,6 +1132,7 @@ static void evergreen_gpu_init(struct radeon_device *rdev) rdev->config.evergreen.max_backends) & EVERGREEN_MAX_BACKENDS_MASK)); + rdev->config.evergreen.tile_config = gb_addr_config; WREG32(GB_BACKEND_MAP, gb_backend_map); WREG32(GB_ADDR_CONFIG, gb_addr_config); WREG32(DMIF_ADDR_CONFIG, gb_addr_config); @@ -1334,8 +1352,8 @@ int evergreen_mc_init(struct radeon_device *rdev) } rdev->mc.vram_width = numchan * chansize; /* Could aper size report 0 ? */ - rdev->mc.aper_base = drm_get_resource_start(rdev->ddev, 0); - rdev->mc.aper_size = drm_get_resource_len(rdev->ddev, 0); + rdev->mc.aper_base = pci_resource_start(rdev->pdev, 0); + rdev->mc.aper_size = pci_resource_len(rdev->pdev, 0); /* Setup GPU memory space */ /* size in MB on evergreen */ rdev->mc.mc_vram_size = RREG32(CONFIG_MEMSIZE) * 1024 * 1024; diff --git a/drivers/gpu/drm/radeon/evergreen_reg.h b/drivers/gpu/drm/radeon/evergreen_reg.h index e028c1c..2330f3a 100644 --- a/drivers/gpu/drm/radeon/evergreen_reg.h +++ b/drivers/gpu/drm/radeon/evergreen_reg.h @@ -61,6 +61,11 @@ # define EVERGREEN_GRPH_FORMAT_8B_BGRA1010102 5 # define EVERGREEN_GRPH_FORMAT_RGB111110 6 # define EVERGREEN_GRPH_FORMAT_BGR101111 7 +# define EVERGREEN_GRPH_ARRAY_MODE(x) (((x) & 0x7) << 20) +# define EVERGREEN_GRPH_ARRAY_LINEAR_GENERAL 0 +# define EVERGREEN_GRPH_ARRAY_LINEAR_ALIGNED 1 +# define EVERGREEN_GRPH_ARRAY_1D_TILED_THIN1 2 +# define EVERGREEN_GRPH_ARRAY_2D_TILED_THIN1 4 #define EVERGREEN_GRPH_SWAP_CONTROL 0x680c # define EVERGREEN_GRPH_ENDIAN_SWAP(x) (((x) & 0x3) << 0) # define EVERGREEN_GRPH_ENDIAN_NONE 0 diff --git a/drivers/gpu/drm/radeon/evergreend.h b/drivers/gpu/drm/radeon/evergreend.h index a1cd621..9b7532d 100644 --- a/drivers/gpu/drm/radeon/evergreend.h +++ b/drivers/gpu/drm/radeon/evergreend.h @@ -165,6 +165,11 @@ #define SE_DB_BUSY (1 << 30) #define SE_CB_BUSY (1 << 31) +#define CG_MULT_THERMAL_STATUS 0x740 +#define ASIC_T(x) ((x) << 16) +#define ASIC_T_MASK 0x7FF0000 +#define ASIC_T_SHIFT 16 + #define HDP_HOST_PATH_CNTL 0x2C00 #define HDP_NONSURFACE_BASE 0x2C04 #define HDP_NONSURFACE_INFO 0x2C08 diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index a89a15a..e817a0b 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -141,7 +141,7 @@ void r100_pm_get_dynpm_state(struct radeon_device *rdev) /* only one clock mode per power state */ rdev->pm.requested_clock_mode_index = 0; - DRM_DEBUG("Requested: e: %d m: %d p: %d\n", + DRM_DEBUG_DRIVER("Requested: e: %d m: %d p: %d\n", rdev->pm.power_state[rdev->pm.requested_power_state_index]. clock_info[rdev->pm.requested_clock_mode_index].sclk, rdev->pm.power_state[rdev->pm.requested_power_state_index]. @@ -276,7 +276,7 @@ void r100_pm_misc(struct radeon_device *rdev) rdev->pm.power_state[rdev->pm.current_power_state_index].pcie_lanes)) { radeon_set_pcie_lanes(rdev, ps->pcie_lanes); - DRM_DEBUG("Setting: p: %d\n", ps->pcie_lanes); + DRM_DEBUG_DRIVER("Setting: p: %d\n", ps->pcie_lanes); } } @@ -849,7 +849,7 @@ static int r100_cp_init_microcode(struct radeon_device *rdev) const char *fw_name = NULL; int err; - DRM_DEBUG("\n"); + DRM_DEBUG_KMS("\n"); pdev = platform_device_register_simple("radeon_cp", 0, NULL, 0); err = IS_ERR(pdev); @@ -1803,6 +1803,11 @@ static int r100_packet3_check(struct radeon_cs_parser *p, return r; break; /* triggers drawing using indices to vertex buffer */ + case PACKET3_3D_CLEAR_HIZ: + case PACKET3_3D_CLEAR_ZMASK: + if (p->rdev->hyperz_filp != p->filp) + return -EINVAL; + break; case PACKET3_NOP: break; default: @@ -2295,8 +2300,8 @@ void r100_vram_init_sizes(struct radeon_device *rdev) u64 config_aper_size; /* work out accessible VRAM */ - rdev->mc.aper_base = drm_get_resource_start(rdev->ddev, 0); - rdev->mc.aper_size = drm_get_resource_len(rdev->ddev, 0); + rdev->mc.aper_base = pci_resource_start(rdev->pdev, 0); + rdev->mc.aper_size = pci_resource_len(rdev->pdev, 0); rdev->mc.visible_vram_size = r100_get_accessible_vram(rdev); /* FIXME we don't use the second aperture yet when we could use it */ if (rdev->mc.visible_vram_size > rdev->mc.aper_size) @@ -2364,11 +2369,10 @@ void r100_mc_init(struct radeon_device *rdev) */ void r100_pll_errata_after_index(struct radeon_device *rdev) { - if (!(rdev->pll_errata & CHIP_ERRATA_PLL_DUMMYREADS)) { - return; + if (rdev->pll_errata & CHIP_ERRATA_PLL_DUMMYREADS) { + (void)RREG32(RADEON_CLOCK_CNTL_DATA); + (void)RREG32(RADEON_CRTC_GEN_CNTL); } - (void)RREG32(RADEON_CLOCK_CNTL_DATA); - (void)RREG32(RADEON_CRTC_GEN_CNTL); } static void r100_pll_errata_after_data(struct radeon_device *rdev) @@ -2643,7 +2647,7 @@ int r100_set_surface_reg(struct radeon_device *rdev, int reg, flags |= pitch / 8; - DRM_DEBUG("writing surface %d %d %x %x\n", reg, flags, offset, offset+obj_size-1); + DRM_DEBUG_KMS("writing surface %d %d %x %x\n", reg, flags, offset, offset+obj_size-1); WREG32(RADEON_SURFACE0_INFO + surf_index, flags); WREG32(RADEON_SURFACE0_LOWER_BOUND + surf_index, offset); WREG32(RADEON_SURFACE0_UPPER_BOUND + surf_index, offset + obj_size - 1); @@ -3039,7 +3043,7 @@ void r100_bandwidth_update(struct radeon_device *rdev) } #endif - DRM_DEBUG("GRPH_BUFFER_CNTL from to %x\n", + DRM_DEBUG_KMS("GRPH_BUFFER_CNTL from to %x\n", /* (unsigned int)info->SavedReg->grph_buffer_cntl, */ (unsigned int)RREG32(RADEON_GRPH_BUFFER_CNTL)); } @@ -3135,7 +3139,7 @@ void r100_bandwidth_update(struct radeon_device *rdev) WREG32(RS400_DISP1_REQ_CNTL1, 0x28FBC3AC); } - DRM_DEBUG("GRPH2_BUFFER_CNTL from to %x\n", + DRM_DEBUG_KMS("GRPH2_BUFFER_CNTL from to %x\n", (unsigned int)RREG32(RADEON_GRPH2_BUFFER_CNTL)); } } @@ -3809,6 +3813,31 @@ void r100_fini(struct radeon_device *rdev) rdev->bios = NULL; } +/* + * Due to how kexec works, it can leave the hw fully initialised when it + * boots the new kernel. However doing our init sequence with the CP and + * WB stuff setup causes GPU hangs on the RN50 at least. So at startup + * do some quick sanity checks and restore sane values to avoid this + * problem. + */ +void r100_restore_sanity(struct radeon_device *rdev) +{ + u32 tmp; + + tmp = RREG32(RADEON_CP_CSQ_CNTL); + if (tmp) { + WREG32(RADEON_CP_CSQ_CNTL, 0); + } + tmp = RREG32(RADEON_CP_RB_CNTL); + if (tmp) { + WREG32(RADEON_CP_RB_CNTL, 0); + } + tmp = RREG32(RADEON_SCRATCH_UMSK); + if (tmp) { + WREG32(RADEON_SCRATCH_UMSK, 0); + } +} + int r100_init(struct radeon_device *rdev) { int r; @@ -3821,6 +3850,8 @@ int r100_init(struct radeon_device *rdev) radeon_scratch_init(rdev); /* Initialize surface registers */ radeon_surface_init(rdev); + /* sanity check some register to avoid hangs like after kexec */ + r100_restore_sanity(rdev); /* TODO: disable VGA need to use VGA request */ /* BIOS*/ if (!radeon_get_bios(rdev)) { diff --git a/drivers/gpu/drm/radeon/r100d.h b/drivers/gpu/drm/radeon/r100d.h index d016b16..b121b6c 100644 --- a/drivers/gpu/drm/radeon/r100d.h +++ b/drivers/gpu/drm/radeon/r100d.h @@ -48,10 +48,12 @@ #define PACKET3_3D_DRAW_IMMD 0x29 #define PACKET3_3D_DRAW_INDX 0x2A #define PACKET3_3D_LOAD_VBPNTR 0x2F +#define PACKET3_3D_CLEAR_ZMASK 0x32 #define PACKET3_INDX_BUFFER 0x33 #define PACKET3_3D_DRAW_VBUF_2 0x34 #define PACKET3_3D_DRAW_IMMD_2 0x35 #define PACKET3_3D_DRAW_INDX_2 0x36 +#define PACKET3_3D_CLEAR_HIZ 0x37 #define PACKET3_BITBLT_MULTI 0x9B #define PACKET0(reg, n) (CP_PACKET0 | \ diff --git a/drivers/gpu/drm/radeon/r300.c b/drivers/gpu/drm/radeon/r300.c index 19a7ef7..c827738 100644 --- a/drivers/gpu/drm/radeon/r300.c +++ b/drivers/gpu/drm/radeon/r300.c @@ -1048,14 +1048,47 @@ static int r300_packet0_check(struct radeon_cs_parser *p, /* RB3D_COLOR_CHANNEL_MASK */ track->color_channel_mask = idx_value; break; - case 0x4d1c: + case 0x43a4: + /* SC_HYPERZ_EN */ + /* r300c emits this register - we need to disable hyperz for it + * without complaining */ + if (p->rdev->hyperz_filp != p->filp) { + if (idx_value & 0x1) + ib[idx] = idx_value & ~1; + } + break; + case 0x4f1c: /* ZB_BW_CNTL */ track->zb_cb_clear = !!(idx_value & (1 << 5)); + if (p->rdev->hyperz_filp != p->filp) { + if (idx_value & (R300_HIZ_ENABLE | + R300_RD_COMP_ENABLE | + R300_WR_COMP_ENABLE | + R300_FAST_FILL_ENABLE)) + goto fail; + } break; case 0x4e04: /* RB3D_BLENDCNTL */ track->blend_read_enable = !!(idx_value & (1 << 2)); break; + case 0x4f28: /* ZB_DEPTHCLEARVALUE */ + break; + case 0x4f30: /* ZB_MASK_OFFSET */ + case 0x4f34: /* ZB_ZMASK_PITCH */ + case 0x4f44: /* ZB_HIZ_OFFSET */ + case 0x4f54: /* ZB_HIZ_PITCH */ + if (idx_value && (p->rdev->hyperz_filp != p->filp)) + goto fail; + break; + case 0x4028: + if (idx_value && (p->rdev->hyperz_filp != p->filp)) + goto fail; + /* GB_Z_PEQ_CONFIG */ + if (p->rdev->family >= CHIP_RV350) + break; + goto fail; + break; case 0x4be8: /* valid register only on RV530 */ if (p->rdev->family == CHIP_RV530) @@ -1066,8 +1099,8 @@ static int r300_packet0_check(struct radeon_cs_parser *p, } return 0; fail: - printk(KERN_ERR "Forbidden register 0x%04X in cs at %d\n", - reg, idx); + printk(KERN_ERR "Forbidden register 0x%04X in cs at %d (val=%08x)\n", + reg, idx, idx_value); return -EINVAL; } @@ -1161,6 +1194,11 @@ static int r300_packet3_check(struct radeon_cs_parser *p, return r; } break; + case PACKET3_3D_CLEAR_HIZ: + case PACKET3_3D_CLEAR_ZMASK: + if (p->rdev->hyperz_filp != p->filp) + return -EINVAL; + break; case PACKET3_NOP: break; default: @@ -1380,6 +1418,8 @@ int r300_init(struct radeon_device *rdev) /* Initialize surface registers */ radeon_surface_init(rdev); /* TODO: disable VGA need to use VGA request */ + /* restore some register to sane defaults */ + r100_restore_sanity(rdev); /* BIOS*/ if (!radeon_get_bios(rdev)) { if (ASIC_IS_AVIVO(rdev)) diff --git a/drivers/gpu/drm/radeon/r300d.h b/drivers/gpu/drm/radeon/r300d.h index 968a333..0c036c6 100644 --- a/drivers/gpu/drm/radeon/r300d.h +++ b/drivers/gpu/drm/radeon/r300d.h @@ -48,10 +48,12 @@ #define PACKET3_3D_DRAW_IMMD 0x29 #define PACKET3_3D_DRAW_INDX 0x2A #define PACKET3_3D_LOAD_VBPNTR 0x2F +#define PACKET3_3D_CLEAR_ZMASK 0x32 #define PACKET3_INDX_BUFFER 0x33 #define PACKET3_3D_DRAW_VBUF_2 0x34 #define PACKET3_3D_DRAW_IMMD_2 0x35 #define PACKET3_3D_DRAW_INDX_2 0x36 +#define PACKET3_3D_CLEAR_HIZ 0x37 #define PACKET3_BITBLT_MULTI 0x9B #define PACKET0(reg, n) (CP_PACKET0 | \ diff --git a/drivers/gpu/drm/radeon/r420.c b/drivers/gpu/drm/radeon/r420.c index e6c8914..59f7bcc 100644 --- a/drivers/gpu/drm/radeon/r420.c +++ b/drivers/gpu/drm/radeon/r420.c @@ -343,6 +343,8 @@ int r420_init(struct radeon_device *rdev) /* Initialize surface registers */ radeon_surface_init(rdev); /* TODO: disable VGA need to use VGA request */ + /* restore some register to sane defaults */ + r100_restore_sanity(rdev); /* BIOS*/ if (!radeon_get_bios(rdev)) { if (ASIC_IS_AVIVO(rdev)) diff --git a/drivers/gpu/drm/radeon/r500_reg.h b/drivers/gpu/drm/radeon/r500_reg.h index 93c9a2b..6ac1f60 100644 --- a/drivers/gpu/drm/radeon/r500_reg.h +++ b/drivers/gpu/drm/radeon/r500_reg.h @@ -386,6 +386,11 @@ # define AVIVO_D1GRPH_TILED (1 << 20) # define AVIVO_D1GRPH_MACRO_ADDRESS_MODE (1 << 21) +# define R600_D1GRPH_ARRAY_MODE_LINEAR_GENERAL (0 << 20) +# define R600_D1GRPH_ARRAY_MODE_LINEAR_ALIGNED (1 << 20) +# define R600_D1GRPH_ARRAY_MODE_1D_TILED_THIN1 (2 << 20) +# define R600_D1GRPH_ARRAY_MODE_2D_TILED_THIN1 (4 << 20) + /* The R7xx *_HIGH surface regs are backwards; the D1 regs are in the D2 * block and vice versa. This applies to GRPH, CUR, etc. */ diff --git a/drivers/gpu/drm/radeon/r520.c b/drivers/gpu/drm/radeon/r520.c index 694af7c..1458dee 100644 --- a/drivers/gpu/drm/radeon/r520.c +++ b/drivers/gpu/drm/radeon/r520.c @@ -231,6 +231,8 @@ int r520_init(struct radeon_device *rdev) radeon_scratch_init(rdev); /* Initialize surface registers */ radeon_surface_init(rdev); + /* restore some register to sane defaults */ + r100_restore_sanity(rdev); /* TODO: disable VGA need to use VGA request */ /* BIOS*/ if (!radeon_get_bios(rdev)) { diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index e100f69..d0ebae9 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -92,6 +92,21 @@ void r600_gpu_init(struct radeon_device *rdev); void r600_fini(struct radeon_device *rdev); void r600_irq_disable(struct radeon_device *rdev); +/* get temperature in millidegrees */ +u32 rv6xx_get_temp(struct radeon_device *rdev) +{ + u32 temp = (RREG32(CG_THERMAL_STATUS) & ASIC_T_MASK) >> + ASIC_T_SHIFT; + u32 actual_temp = 0; + + if ((temp >> 7) & 1) + actual_temp = 0; + else + actual_temp = (temp >> 1) & 0xff; + + return actual_temp * 1000; +} + void r600_pm_get_dynpm_state(struct radeon_device *rdev) { int i; @@ -256,7 +271,7 @@ void r600_pm_get_dynpm_state(struct radeon_device *rdev) } } - DRM_DEBUG("Requested: e: %d m: %d p: %d\n", + DRM_DEBUG_DRIVER("Requested: e: %d m: %d p: %d\n", rdev->pm.power_state[rdev->pm.requested_power_state_index]. clock_info[rdev->pm.requested_clock_mode_index].sclk, rdev->pm.power_state[rdev->pm.requested_power_state_index]. @@ -571,7 +586,7 @@ void r600_pm_misc(struct radeon_device *rdev) if (voltage->voltage != rdev->pm.current_vddc) { radeon_atom_set_voltage(rdev, voltage->voltage); rdev->pm.current_vddc = voltage->voltage; - DRM_DEBUG("Setting: v: %d\n", voltage->voltage); + DRM_DEBUG_DRIVER("Setting: v: %d\n", voltage->voltage); } } } @@ -869,7 +884,17 @@ void r600_pcie_gart_tlb_flush(struct radeon_device *rdev) u32 tmp; /* flush hdp cache so updates hit vram */ - WREG32(R_005480_HDP_MEM_COHERENCY_FLUSH_CNTL, 0x1); + if ((rdev->family >= CHIP_RV770) && (rdev->family <= CHIP_RV740)) { + void __iomem *ptr = (void *)rdev->gart.table.vram.ptr; + u32 tmp; + + /* r7xx hw bug. write to HDP_DEBUG1 followed by fb read + * rather than write to HDP_REG_COHERENCY_FLUSH_CNTL + */ + WREG32(HDP_DEBUG1, 0); + tmp = readl((void __iomem *)ptr); + } else + WREG32(R_005480_HDP_MEM_COHERENCY_FLUSH_CNTL, 0x1); WREG32(VM_CONTEXT0_INVALIDATION_LOW_ADDR, rdev->mc.gtt_start >> 12); WREG32(VM_CONTEXT0_INVALIDATION_HIGH_ADDR, (rdev->mc.gtt_end - 1) >> 12); @@ -1217,8 +1242,8 @@ int r600_mc_init(struct radeon_device *rdev) } rdev->mc.vram_width = numchan * chansize; /* Could aper size report 0 ? */ - rdev->mc.aper_base = drm_get_resource_start(rdev->ddev, 0); - rdev->mc.aper_size = drm_get_resource_len(rdev->ddev, 0); + rdev->mc.aper_base = pci_resource_start(rdev->pdev, 0); + rdev->mc.aper_size = pci_resource_len(rdev->pdev, 0); /* Setup GPU memory space */ rdev->mc.mc_vram_size = RREG32(CONFIG_MEMSIZE); rdev->mc.real_vram_size = RREG32(CONFIG_MEMSIZE); @@ -1609,7 +1634,7 @@ void r600_gpu_init(struct radeon_device *rdev) r600_count_pipe_bits((cc_rb_backend_disable & R6XX_MAX_BACKENDS_MASK) >> 16)), (cc_rb_backend_disable >> 16)); - + rdev->config.r600.tile_config = tiling_config; tiling_config |= BACKEND_MAP(backend_map); WREG32(GB_TILING_CONFIG, tiling_config); WREG32(DCP_TILING_CONFIG, tiling_config & 0xffff); @@ -3512,5 +3537,15 @@ int r600_debugfs_mc_info_init(struct radeon_device *rdev) */ void r600_ioctl_wait_idle(struct radeon_device *rdev, struct radeon_bo *bo) { - WREG32(R_005480_HDP_MEM_COHERENCY_FLUSH_CNTL, 0x1); + /* r7xx hw bug. write to HDP_DEBUG1 followed by fb read + * rather than write to HDP_REG_COHERENCY_FLUSH_CNTL + */ + if ((rdev->family >= CHIP_RV770) && (rdev->family <= CHIP_RV740)) { + void __iomem *ptr = (void *)rdev->gart.table.vram.ptr; + u32 tmp; + + WREG32(HDP_DEBUG1, 0); + tmp = readl((void __iomem *)ptr); + } else + WREG32(R_005480_HDP_MEM_COHERENCY_FLUSH_CNTL, 0x1); } diff --git a/drivers/gpu/drm/radeon/r600_audio.c b/drivers/gpu/drm/radeon/r600_audio.c index 2b26553..b5443fe 100644 --- a/drivers/gpu/drm/radeon/r600_audio.c +++ b/drivers/gpu/drm/radeon/r600_audio.c @@ -63,7 +63,8 @@ int r600_audio_bits_per_sample(struct radeon_device *rdev) case 0x4: return 32; } - DRM_ERROR("Unknown bits per sample 0x%x using 16 instead.\n", (int)value); + dev_err(rdev->dev, "Unknown bits per sample 0x%x using 16 instead\n", + (int)value); return 16; } @@ -150,7 +151,8 @@ static void r600_audio_update_hdmi(unsigned long param) r600_hdmi_update_audio_settings(encoder); } - if(still_going) r600_audio_schedule_polling(rdev); + if (still_going) + r600_audio_schedule_polling(rdev); } /* @@ -158,8 +160,9 @@ static void r600_audio_update_hdmi(unsigned long param) */ static void r600_audio_engine_enable(struct radeon_device *rdev, bool enable) { - DRM_INFO("%s audio support", enable ? "Enabling" : "Disabling"); + DRM_INFO("%s audio support\n", enable ? "Enabling" : "Disabling"); WREG32_P(R600_AUDIO_ENABLE, enable ? 0x81000000 : 0x0, ~0x81000000); + rdev->audio_enabled = enable; } /* @@ -195,12 +198,14 @@ void r600_audio_enable_polling(struct drm_encoder *encoder) struct radeon_device *rdev = dev->dev_private; struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - DRM_DEBUG("r600_audio_enable_polling: %d", radeon_encoder->audio_polling_active); + DRM_DEBUG("r600_audio_enable_polling: %d\n", + radeon_encoder->audio_polling_active); if (radeon_encoder->audio_polling_active) return; radeon_encoder->audio_polling_active = 1; - mod_timer(&rdev->audio_timer, jiffies + 1); + if (rdev->audio_enabled) + mod_timer(&rdev->audio_timer, jiffies + 1); } /* @@ -209,7 +214,8 @@ void r600_audio_enable_polling(struct drm_encoder *encoder) void r600_audio_disable_polling(struct drm_encoder *encoder) { struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - DRM_DEBUG("r600_audio_disable_polling: %d", radeon_encoder->audio_polling_active); + DRM_DEBUG("r600_audio_disable_polling: %d\n", + radeon_encoder->audio_polling_active); radeon_encoder->audio_polling_active = 0; } @@ -236,7 +242,7 @@ void r600_audio_set_clock(struct drm_encoder *encoder, int clock) WREG32_P(R600_AUDIO_TIMING, 0x100, ~0x301); break; default: - DRM_ERROR("Unsupported encoder type 0x%02X\n", + dev_err(rdev->dev, "Unsupported encoder type 0x%02X\n", radeon_encoder->encoder_id); return; } @@ -266,7 +272,7 @@ void r600_audio_set_clock(struct drm_encoder *encoder, int clock) */ void r600_audio_fini(struct radeon_device *rdev) { - if (!radeon_audio || !r600_audio_chipset_supported(rdev)) + if (!rdev->audio_enabled) return; del_timer(&rdev->audio_timer); diff --git a/drivers/gpu/drm/radeon/r600_blit_shaders.c b/drivers/gpu/drm/radeon/r600_blit_shaders.c index 0271b53..e8151c1 100644 --- a/drivers/gpu/drm/radeon/r600_blit_shaders.c +++ b/drivers/gpu/drm/radeon/r600_blit_shaders.c @@ -39,37 +39,45 @@ const u32 r6xx_default_state[] = { - 0xc0002400, + 0xc0002400, /* START_3D_CMDBUF */ 0x00000000, - 0xc0012800, + + 0xc0012800, /* CONTEXT_CONTROL */ 0x80000000, 0x80000000, + 0xc0016800, 0x00000010, - 0x00008000, + 0x00008000, /* WAIT_UNTIL */ + 0xc0016800, 0x00000542, - 0x07000003, + 0x07000003, /* TA_CNTL_AUX */ + 0xc0016800, 0x000005c5, - 0x00000000, + 0x00000000, /* VC_ENHANCE */ + 0xc0016800, 0x00000363, - 0x00000000, + 0x00000000, /* SQ_DYN_GPR_CNTL_PS_FLUSH_REQ */ + 0xc0016800, 0x0000060c, - 0x82000000, + 0x82000000, /* DB_DEBUG */ + 0xc0016800, 0x0000060e, - 0x01020204, - 0xc0016f00, - 0x00000000, - 0x00000000, - 0xc0016f00, - 0x00000001, + 0x01020204, /* DB_WATERMARKS */ + + 0xc0026f00, 0x00000000, + 0x00000000, /* SQ_VTX_BASE_VTX_LOC */ + 0x00000000, /* SQ_VTX_START_INST_LOC */ + 0xc0096900, 0x0000022a, + 0x00000000, /* SQ_ESGS_RING_ITEMSIZE */ 0x00000000, 0x00000000, 0x00000000, @@ -78,515 +86,317 @@ const u32 r6xx_default_state[] = 0x00000000, 0x00000000, 0x00000000, - 0x00000000, + 0xc0016900, 0x00000004, - 0x00000000, - 0xc0016900, + 0x00000000, /* DB_DEPTH_INFO */ + + 0xc0026900, 0x0000000a, - 0x00000000, - 0xc0016900, - 0x0000000b, - 0x00000000, - 0xc0016900, - 0x0000010c, - 0x00000000, - 0xc0016900, - 0x0000010d, - 0x00000000, + 0x00000000, /* DB_STENCIL_CLEAR */ + 0x00000000, /* DB_DEPTH_CLEAR */ + 0xc0016900, 0x00000200, - 0x00000000, - 0xc0016900, + 0x00000000, /* DB_DEPTH_CONTROL */ + + 0xc0026900, 0x00000343, - 0x00000060, - 0xc0016900, - 0x00000344, - 0x00000040, + 0x00000060, /* DB_RENDER_CONTROL */ + 0x00000040, /* DB_RENDER_OVERRIDE */ + 0xc0016900, 0x00000351, - 0x0000aa00, - 0xc0016900, - 0x00000104, - 0x00000000, - 0xc0016900, - 0x0000010e, - 0x00000000, - 0xc0046900, - 0x00000105, - 0x00000000, - 0x00000000, + 0x0000aa00, /* DB_ALPHA_TO_MASK */ + + 0xc00f6900, + 0x00000100, + 0x00000800, /* VGT_MAX_VTX_INDX */ + 0x00000000, /* VGT_MIN_VTX_INDX */ + 0x00000000, /* VGT_INDX_OFFSET */ + 0x00000000, /* VGT_MULTI_PRIM_IB_RESET_INDX */ + 0x00000000, /* SX_ALPHA_TEST_CONTROL */ + 0x00000000, /* CB_BLEND_RED */ 0x00000000, 0x00000000, - 0xc0036900, - 0x00000109, 0x00000000, + 0x00000000, /* CB_FOG_RED */ 0x00000000, 0x00000000, + 0x00000000, /* DB_STENCILREFMASK */ + 0x00000000, /* DB_STENCILREFMASK_BF */ + 0x00000000, /* SX_ALPHA_REF */ + 0xc0046900, 0x0000030c, - 0x01000000, + 0x01000000, /* CB_CLRCMP_CNTL */ 0x00000000, 0x00000000, 0x00000000, + 0xc0046900, 0x00000048, - 0x3f800000, + 0x3f800000, /* CB_CLEAR_RED */ 0x00000000, 0x3f800000, 0x3f800000, - 0xc0016900, - 0x0000008e, - 0x0000000f, + 0xc0016900, 0x00000080, - 0x00000000, - 0xc0016900, + 0x00000000, /* PA_SC_WINDOW_OFFSET */ + + 0xc00a6900, 0x00000083, - 0x0000ffff, - 0xc0016900, - 0x00000084, - 0x00000000, - 0xc0016900, - 0x00000085, + 0x0000ffff, /* PA_SC_CLIP_RECT_RULE */ + 0x00000000, /* PA_SC_CLIPRECT_0_TL */ 0x20002000, - 0xc0016900, - 0x00000086, 0x00000000, - 0xc0016900, - 0x00000087, 0x20002000, - 0xc0016900, - 0x00000088, 0x00000000, - 0xc0016900, - 0x00000089, 0x20002000, - 0xc0016900, - 0x0000008a, 0x00000000, - 0xc0016900, - 0x0000008b, 0x20002000, - 0xc0016900, - 0x0000008c, - 0x00000000, - 0xc0016900, + 0x00000000, /* PA_SC_EDGERULE */ + + 0xc0406900, 0x00000094, - 0x80000000, - 0xc0016900, - 0x00000095, + 0x80000000, /* PA_SC_VPORT_SCISSOR_0_TL */ + 0x20002000, /* PA_SC_VPORT_SCISSOR_0_BR */ + 0x80000000, /* PA_SC_VPORT_SCISSOR_1_TL */ 0x20002000, - 0xc0026900, - 0x000000b4, - 0x00000000, - 0x3f800000, - 0xc0016900, - 0x00000096, 0x80000000, - 0xc0016900, - 0x00000097, 0x20002000, - 0xc0026900, - 0x000000b6, - 0x00000000, - 0x3f800000, - 0xc0016900, - 0x00000098, 0x80000000, - 0xc0016900, - 0x00000099, 0x20002000, - 0xc0026900, - 0x000000b8, - 0x00000000, - 0x3f800000, - 0xc0016900, - 0x0000009a, 0x80000000, - 0xc0016900, - 0x0000009b, 0x20002000, - 0xc0026900, - 0x000000ba, - 0x00000000, - 0x3f800000, - 0xc0016900, - 0x0000009c, 0x80000000, - 0xc0016900, - 0x0000009d, 0x20002000, - 0xc0026900, - 0x000000bc, - 0x00000000, - 0x3f800000, - 0xc0016900, - 0x0000009e, 0x80000000, - 0xc0016900, - 0x0000009f, 0x20002000, - 0xc0026900, - 0x000000be, - 0x00000000, - 0x3f800000, - 0xc0016900, - 0x000000a0, 0x80000000, - 0xc0016900, - 0x000000a1, 0x20002000, - 0xc0026900, - 0x000000c0, - 0x00000000, - 0x3f800000, - 0xc0016900, - 0x000000a2, 0x80000000, - 0xc0016900, - 0x000000a3, 0x20002000, - 0xc0026900, - 0x000000c2, - 0x00000000, - 0x3f800000, - 0xc0016900, - 0x000000a4, 0x80000000, - 0xc0016900, - 0x000000a5, 0x20002000, - 0xc0026900, - 0x000000c4, - 0x00000000, - 0x3f800000, - 0xc0016900, - 0x000000a6, 0x80000000, - 0xc0016900, - 0x000000a7, 0x20002000, - 0xc0026900, - 0x000000c6, - 0x00000000, - 0x3f800000, - 0xc0016900, - 0x000000a8, 0x80000000, - 0xc0016900, - 0x000000a9, 0x20002000, - 0xc0026900, - 0x000000c8, - 0x00000000, - 0x3f800000, - 0xc0016900, - 0x000000aa, 0x80000000, - 0xc0016900, - 0x000000ab, 0x20002000, - 0xc0026900, - 0x000000ca, - 0x00000000, - 0x3f800000, - 0xc0016900, - 0x000000ac, 0x80000000, - 0xc0016900, - 0x000000ad, 0x20002000, - 0xc0026900, - 0x000000cc, - 0x00000000, - 0x3f800000, - 0xc0016900, - 0x000000ae, 0x80000000, - 0xc0016900, - 0x000000af, 0x20002000, - 0xc0026900, - 0x000000ce, - 0x00000000, - 0x3f800000, - 0xc0016900, - 0x000000b0, 0x80000000, - 0xc0016900, - 0x000000b1, 0x20002000, - 0xc0026900, - 0x000000d0, - 0x00000000, + 0x00000000, /* PA_SC_VPORT_ZMIN_0 */ 0x3f800000, - 0xc0016900, - 0x000000b2, - 0x80000000, - 0xc0016900, - 0x000000b3, - 0x20002000, - 0xc0026900, - 0x000000d2, 0x00000000, 0x3f800000, - 0xc0016900, - 0x00000293, - 0x00004010, - 0xc0016900, - 0x00000300, 0x00000000, - 0xc0016900, - 0x00000301, - 0x00000000, - 0xc0016900, - 0x00000312, - 0xffffffff, - 0xc0016900, - 0x00000307, + 0x3f800000, 0x00000000, - 0xc0016900, - 0x00000308, + 0x3f800000, 0x00000000, - 0xc0016900, - 0x00000283, + 0x3f800000, 0x00000000, - 0xc0016900, - 0x00000292, + 0x3f800000, 0x00000000, - 0xc0066900, - 0x0000010f, + 0x3f800000, 0x00000000, + 0x3f800000, 0x00000000, + 0x3f800000, 0x00000000, + 0x3f800000, 0x00000000, + 0x3f800000, 0x00000000, + 0x3f800000, 0x00000000, - 0xc0016900, - 0x00000206, + 0x3f800000, 0x00000000, - 0xc0016900, - 0x00000207, + 0x3f800000, 0x00000000, - 0xc0016900, - 0x00000208, + 0x3f800000, 0x00000000, - 0xc0046900, - 0x00000303, 0x3f800000, + + 0xc0026900, + 0x00000292, + 0x00000000, /* PA_SC_MPASS_PS_CNTL */ + 0x00004010, /* PA_SC_MODE_CNTL */ + + 0xc0096900, + 0x00000300, + 0x00000000, /* PA_SC_LINE_CNTL */ + 0x00000000, /* PA_SC_AA_CONFIG */ + 0x0000002d, /* PA_SU_VTX_CNTL */ + 0x3f800000, /* PA_CL_GB_VERT_CLIP_ADJ */ 0x3f800000, 0x3f800000, 0x3f800000, - 0xc0016900, - 0x00000205, - 0x00000004, - 0xc0016900, - 0x00000280, - 0x00000000, - 0xc0016900, - 0x00000281, + 0x00000000, /* PA_SC_SAMPLE_LOCS_MCTX */ 0x00000000, + 0xc0016900, + 0x00000312, + 0xffffffff, /* PA_SC_AA_MASK */ + + 0xc0066900, 0x0000037e, - 0x00000000, - 0xc0016900, - 0x00000382, - 0x00000000, - 0xc0016900, - 0x00000380, - 0x00000000, - 0xc0016900, - 0x00000383, - 0x00000000, - 0xc0016900, - 0x00000381, - 0x00000000, - 0xc0016900, - 0x00000282, - 0x00000008, - 0xc0016900, - 0x00000302, - 0x0000002d, - 0xc0016900, - 0x0000037f, - 0x00000000, - 0xc0016900, - 0x000001b2, - 0x00000000, - 0xc0016900, + 0x00000000, /* PA_SU_POLY_OFFSET_DB_FMT_CNTL */ + 0x00000000, /* PA_SU_POLY_OFFSET_CLAMP */ + 0x00000000, /* PA_SU_POLY_OFFSET_FRONT_SCALE */ + 0x00000000, /* PA_SU_POLY_OFFSET_FRONT_OFFSET */ + 0x00000000, /* PA_SU_POLY_OFFSET_BACK_SCALE */ + 0x00000000, /* PA_SU_POLY_OFFSET_BACK_OFFSET */ + + 0xc0046900, 0x000001b6, - 0x00000000, - 0xc0016900, - 0x000001b7, - 0x00000000, - 0xc0016900, - 0x000001b8, - 0x00000000, - 0xc0016900, - 0x000001b9, - 0x00000000, + 0x00000000, /* SPI_INPUT_Z */ + 0x00000000, /* SPI_FOG_CNTL */ + 0x00000000, /* SPI_FOG_FUNC_SCALE */ + 0x00000000, /* SPI_FOG_FUNC_BIAS */ + 0xc0016900, 0x00000225, - 0x00000000, + 0x00000000, /* SQ_PGM_START_FS */ + 0xc0016900, 0x00000229, - 0x00000000, + 0x00000000, /* SQ_PGM_RESOURCES_FS */ + 0xc0016900, 0x00000237, - 0x00000000, - 0xc0016900, - 0x00000100, - 0x00000800, - 0xc0016900, - 0x00000101, - 0x00000000, - 0xc0016900, - 0x00000102, - 0x00000000, - 0xc0016900, + 0x00000000, /* SQ_PGM_CF_OFFSET_FS */ + + 0xc0026900, 0x000002a8, - 0x00000000, - 0xc0016900, - 0x000002a9, - 0x00000000, - 0xc0016900, - 0x00000103, - 0x00000000, - 0xc0016900, - 0x00000284, - 0x00000000, - 0xc0016900, - 0x00000290, - 0x00000000, - 0xc0016900, - 0x00000285, - 0x00000000, - 0xc0016900, - 0x00000286, - 0x00000000, - 0xc0016900, - 0x00000287, - 0x00000000, - 0xc0016900, - 0x00000288, - 0x00000000, - 0xc0016900, - 0x00000289, - 0x00000000, - 0xc0016900, - 0x0000028a, - 0x00000000, - 0xc0016900, - 0x0000028b, - 0x00000000, - 0xc0016900, - 0x0000028c, - 0x00000000, - 0xc0016900, - 0x0000028d, - 0x00000000, - 0xc0016900, - 0x0000028e, - 0x00000000, - 0xc0016900, - 0x0000028f, - 0x00000000, + 0x00000000, /* VGT_INSTANCE_STEP_RATE_0 */ + 0x00000000, /* VGT_INSTANCE_STEP_RATE_1 */ + + 0xc0116900, + 0x00000280, + 0x00000000, /* PA_SU_POINT_SIZE */ + 0x00000000, /* PA_SU_POINT_MINMAX */ + 0x00000008, /* PA_SU_LINE_CNTL */ + 0x00000000, /* PA_SC_LINE_STIPPLE */ + 0x00000000, /* VGT_OUTPUT_PATH_CNTL */ + 0x00000000, /* VGT_HOS_CNTL */ + 0x00000000, /* VGT_HOS_MAX_TESS_LEVEL */ + 0x00000000, /* VGT_HOS_MIN_TESS_LEVEL */ + 0x00000000, /* VGT_HOS_REUSE_DEPTH */ + 0x00000000, /* VGT_GROUP_PRIM_TYPE */ + 0x00000000, /* VGT_GROUP_FIRST_DECR */ + 0x00000000, /* VGT_GROUP_DECR */ + 0x00000000, /* VGT_GROUP_VECT_0_CNTL */ + 0x00000000, /* VGT_GROUP_VECT_1_CNTL */ + 0x00000000, /* VGT_GROUP_VECT_0_FMT_CNTL */ + 0x00000000, /* VGT_GROUP_VECT_1_FMT_CNTL */ + 0x00000000, /* VGT_GS_MODE */ + 0xc0016900, 0x000002a1, - 0x00000000, + 0x00000000, /* VGT_PRIMITIVEID_EN */ + 0xc0016900, 0x000002a5, - 0x00000000, - 0xc0016900, + 0x00000000, /* VGT_MULTI_PRIM_ID_RESET_EN */ + + 0xc0036900, 0x000002ac, - 0x00000000, - 0xc0016900, - 0x000002ad, - 0x00000000, - 0xc0016900, - 0x000002ae, - 0x00000000, + 0x00000000, /* VGT_STRMOUT_EN */ + 0x00000000, /* VGT_REUSE_OFF */ + 0x00000000, /* VGT_VTX_CNT_EN */ + 0xc0016900, 0x000002c8, - 0x00000000, - 0xc0016900, - 0x00000206, - 0x00000100, - 0xc0016900, - 0x00000204, - 0x00010000, - 0xc0036e00, - 0x00000000, - 0x00000012, - 0x00000000, - 0x00000000, - 0xc0016900, - 0x0000008f, - 0x0000000f, - 0xc0016900, - 0x000001e8, - 0x00000001, - 0xc0016900, + 0x00000000, /* VGT_STRMOUT_BUFFER_EN */ + + 0xc0076900, 0x00000202, - 0x00cc0000, + 0x00cc0000, /* CB_COLOR_CONTROL */ + 0x00000210, /* DB_SHADER_CNTL */ + 0x00010000, /* PA_CL_CLIP_CNTL */ + 0x00000244, /* PA_SU_SC_MODE_CNTL */ + 0x00000100, /* PA_CL_VTE_CNTL */ + 0x00000000, /* PA_CL_VS_OUT_CNTL */ + 0x00000000, /* PA_CL_NANINF_CNTL */ + + 0xc0026900, + 0x0000008e, + 0x0000000f, /* CB_TARGET_MASK */ + 0x0000000f, /* CB_SHADER_MASK */ + 0xc0016900, - 0x00000205, - 0x00000244, + 0x000001e8, + 0x00000001, /* CB_SHADER_CONTROL */ + 0xc0016900, - 0x00000203, - 0x00000210, + 0x00000185, + 0x00000000, /* SPI_VS_OUT_ID_0 */ + 0xc0016900, + 0x00000191, + 0x00000b00, /* SPI_PS_INPUT_CNTL_0 */ + + 0xc0056900, 0x000001b1, + 0x00000000, /* SPI_VS_OUT_CONFIG */ + 0x00000000, /* SPI_THREAD_GROUPING */ + 0x00000001, /* SPI_PS_IN_CONTROL_0 */ + 0x00000000, /* SPI_PS_IN_CONTROL_1 */ + 0x00000000, /* SPI_INTERP_CONTROL_0 */ + + 0xc0036e00, /* SET_SAMPLER */ 0x00000000, - 0xc0016900, - 0x00000185, - 0x00000000, - 0xc0016900, - 0x000001b3, - 0x00000001, - 0xc0016900, - 0x000001b4, + 0x00000012, 0x00000000, - 0xc0016900, - 0x00000191, - 0x00000b00, - 0xc0016900, - 0x000001b5, 0x00000000, }; const u32 r7xx_default_state[] = { - 0xc0012800, + 0xc0012800, /* CONTEXT_CONTROL */ 0x80000000, 0x80000000, + 0xc0016800, 0x00000010, - 0x00008000, + 0x00008000, /* WAIT_UNTIL */ + 0xc0016800, 0x00000542, - 0x07000002, + 0x07000002, /* TA_CNTL_AUX */ + 0xc0016800, 0x000005c5, - 0x00000000, + 0x00000000, /* VC_ENHANCE */ + 0xc0016800, 0x00000363, - 0x00004000, + 0x00004000, /* SQ_DYN_GPR_CNTL_PS_FLUSH_REQ */ + 0xc0016800, 0x0000060c, - 0x00000000, + 0x00000000, /* DB_DEBUG */ + 0xc0016800, 0x0000060e, - 0x00420204, - 0xc0016f00, - 0x00000000, - 0x00000000, - 0xc0016f00, - 0x00000001, + 0x00420204, /* DB_WATERMARKS */ + + 0xc0026f00, 0x00000000, + 0x00000000, /* SQ_VTX_BASE_VTX_LOC */ + 0x00000000, /* SQ_VTX_START_INST_LOC */ + 0xc0096900, 0x0000022a, + 0x00000000, /* SQ_ESGS_RING_ITEMSIZE */ 0x00000000, 0x00000000, 0x00000000, @@ -595,470 +405,269 @@ const u32 r7xx_default_state[] = 0x00000000, 0x00000000, 0x00000000, - 0x00000000, + 0xc0016900, 0x00000004, - 0x00000000, - 0xc0016900, + 0x00000000, /* DB_DEPTH_INFO */ + + 0xc0026900, 0x0000000a, - 0x00000000, - 0xc0016900, - 0x0000000b, - 0x00000000, - 0xc0016900, - 0x0000010c, - 0x00000000, - 0xc0016900, - 0x0000010d, - 0x00000000, + 0x00000000, /* DB_STENCIL_CLEAR */ + 0x00000000, /* DB_DEPTH_CLEAR */ + 0xc0016900, 0x00000200, - 0x00000000, - 0xc0016900, + 0x00000000, /* DB_DEPTH_CONTROL */ + + 0xc0026900, 0x00000343, - 0x00000060, - 0xc0016900, - 0x00000344, - 0x00000000, + 0x00000060, /* DB_RENDER_CONTROL */ + 0x00000000, /* DB_RENDER_OVERRIDE */ + 0xc0016900, 0x00000351, - 0x0000aa00, - 0xc0016900, - 0x00000104, - 0x00000000, - 0xc0016900, - 0x0000010e, - 0x00000000, - 0xc0046900, - 0x00000105, - 0x00000000, + 0x0000aa00, /* DB_ALPHA_TO_MASK */ + + 0xc0096900, + 0x00000100, + 0x00000800, /* VGT_MAX_VTX_INDX */ + 0x00000000, /* VGT_MIN_VTX_INDX */ + 0x00000000, /* VGT_INDX_OFFSET */ + 0x00000000, /* VGT_MULTI_PRIM_IB_RESET_INDX */ + 0x00000000, /* SX_ALPHA_TEST_CONTROL */ + 0x00000000, /* CB_BLEND_RED */ 0x00000000, 0x00000000, 0x00000000, + + 0xc0036900, + 0x0000010c, + 0x00000000, /* DB_STENCILREFMASK */ + 0x00000000, /* DB_STENCILREFMASK_BF */ + 0x00000000, /* SX_ALPHA_REF */ + 0xc0046900, - 0x0000030c, + 0x0000030c, /* CB_CLRCMP_CNTL */ 0x01000000, 0x00000000, 0x00000000, 0x00000000, - 0xc0016900, - 0x0000008e, - 0x0000000f, + 0xc0016900, 0x00000080, - 0x00000000, - 0xc0016900, + 0x00000000, /* PA_SC_WINDOW_OFFSET */ + + 0xc00a6900, 0x00000083, - 0x0000ffff, - 0xc0016900, - 0x00000084, - 0x00000000, - 0xc0016900, - 0x00000085, + 0x0000ffff, /* PA_SC_CLIP_RECT_RULE */ + 0x00000000, /* PA_SC_CLIPRECT_0_TL */ 0x20002000, - 0xc0016900, - 0x00000086, 0x00000000, - 0xc0016900, - 0x00000087, 0x20002000, - 0xc0016900, - 0x00000088, 0x00000000, - 0xc0016900, - 0x00000089, 0x20002000, - 0xc0016900, - 0x0000008a, 0x00000000, - 0xc0016900, - 0x0000008b, 0x20002000, - 0xc0016900, - 0x0000008c, - 0xaaaaaaaa, - 0xc0016900, + 0xaaaaaaaa, /* PA_SC_EDGERULE */ + + 0xc0406900, 0x00000094, - 0x80000000, - 0xc0016900, - 0x00000095, + 0x80000000, /* PA_SC_VPORT_SCISSOR_0_TL */ + 0x20002000, /* PA_SC_VPORT_SCISSOR_0_BR */ + 0x80000000, /* PA_SC_VPORT_SCISSOR_1_TL */ 0x20002000, - 0xc0026900, - 0x000000b4, - 0x00000000, - 0x3f800000, - 0xc0016900, - 0x00000096, 0x80000000, - 0xc0016900, - 0x00000097, 0x20002000, - 0xc0026900, - 0x000000b6, - 0x00000000, - 0x3f800000, - 0xc0016900, - 0x00000098, 0x80000000, - 0xc0016900, - 0x00000099, 0x20002000, - 0xc0026900, - 0x000000b8, - 0x00000000, - 0x3f800000, - 0xc0016900, - 0x0000009a, 0x80000000, - 0xc0016900, - 0x0000009b, 0x20002000, - 0xc0026900, - 0x000000ba, - 0x00000000, - 0x3f800000, - 0xc0016900, - 0x0000009c, 0x80000000, - 0xc0016900, - 0x0000009d, 0x20002000, - 0xc0026900, - 0x000000bc, - 0x00000000, - 0x3f800000, - 0xc0016900, - 0x0000009e, 0x80000000, - 0xc0016900, - 0x0000009f, 0x20002000, - 0xc0026900, - 0x000000be, - 0x00000000, - 0x3f800000, - 0xc0016900, - 0x000000a0, 0x80000000, - 0xc0016900, - 0x000000a1, 0x20002000, - 0xc0026900, - 0x000000c0, - 0x00000000, - 0x3f800000, - 0xc0016900, - 0x000000a2, 0x80000000, - 0xc0016900, - 0x000000a3, 0x20002000, - 0xc0026900, - 0x000000c2, - 0x00000000, - 0x3f800000, - 0xc0016900, - 0x000000a4, 0x80000000, - 0xc0016900, - 0x000000a5, 0x20002000, - 0xc0026900, - 0x000000c4, - 0x00000000, - 0x3f800000, - 0xc0016900, - 0x000000a6, 0x80000000, - 0xc0016900, - 0x000000a7, 0x20002000, - 0xc0026900, - 0x000000c6, - 0x00000000, - 0x3f800000, - 0xc0016900, - 0x000000a8, 0x80000000, - 0xc0016900, - 0x000000a9, 0x20002000, - 0xc0026900, - 0x000000c8, - 0x00000000, - 0x3f800000, - 0xc0016900, - 0x000000aa, 0x80000000, - 0xc0016900, - 0x000000ab, 0x20002000, - 0xc0026900, - 0x000000ca, - 0x00000000, - 0x3f800000, - 0xc0016900, - 0x000000ac, 0x80000000, - 0xc0016900, - 0x000000ad, 0x20002000, - 0xc0026900, - 0x000000cc, - 0x00000000, - 0x3f800000, - 0xc0016900, - 0x000000ae, 0x80000000, - 0xc0016900, - 0x000000af, 0x20002000, - 0xc0026900, - 0x000000ce, - 0x00000000, - 0x3f800000, - 0xc0016900, - 0x000000b0, 0x80000000, - 0xc0016900, - 0x000000b1, 0x20002000, - 0xc0026900, - 0x000000d0, - 0x00000000, + 0x00000000, /* PA_SC_VPORT_ZMIN_0 */ 0x3f800000, - 0xc0016900, - 0x000000b2, - 0x80000000, - 0xc0016900, - 0x000000b3, - 0x20002000, - 0xc0026900, - 0x000000d2, 0x00000000, 0x3f800000, - 0xc0016900, - 0x00000293, - 0x00514000, - 0xc0016900, - 0x00000300, - 0x00000000, - 0xc0016900, - 0x00000301, 0x00000000, - 0xc0016900, - 0x00000312, - 0xffffffff, - 0xc0016900, - 0x00000307, + 0x3f800000, 0x00000000, - 0xc0016900, - 0x00000308, + 0x3f800000, 0x00000000, - 0xc0016900, - 0x00000283, + 0x3f800000, 0x00000000, - 0xc0016900, - 0x00000292, + 0x3f800000, 0x00000000, - 0xc0066900, - 0x0000010f, + 0x3f800000, 0x00000000, + 0x3f800000, 0x00000000, + 0x3f800000, 0x00000000, + 0x3f800000, 0x00000000, + 0x3f800000, 0x00000000, + 0x3f800000, 0x00000000, - 0xc0016900, - 0x00000206, + 0x3f800000, 0x00000000, - 0xc0016900, - 0x00000207, + 0x3f800000, 0x00000000, - 0xc0016900, - 0x00000208, + 0x3f800000, 0x00000000, - 0xc0046900, - 0x00000303, 0x3f800000, + + 0xc0026900, + 0x00000292, + 0x00000000, /* PA_SC_MPASS_PS_CNTL */ + 0x00514000, /* PA_SC_MODE_CNTL */ + + 0xc0096900, + 0x00000300, + 0x00000000, /* PA_SC_LINE_CNTL */ + 0x00000000, /* PA_SC_AA_CONFIG */ + 0x0000002d, /* PA_SU_VTX_CNTL */ + 0x3f800000, /* PA_CL_GB_VERT_CLIP_ADJ */ 0x3f800000, 0x3f800000, 0x3f800000, - 0xc0016900, - 0x00000205, - 0x00000004, - 0xc0016900, - 0x00000280, - 0x00000000, - 0xc0016900, - 0x00000281, + 0x00000000, /* PA_SC_SAMPLE_LOCS_MCTX */ 0x00000000, + 0xc0016900, + 0x00000312, + 0xffffffff, /* PA_SC_AA_MASK */ + + 0xc0066900, 0x0000037e, - 0x00000000, - 0xc0016900, - 0x00000382, - 0x00000000, - 0xc0016900, - 0x00000380, - 0x00000000, - 0xc0016900, - 0x00000383, - 0x00000000, - 0xc0016900, - 0x00000381, - 0x00000000, - 0xc0016900, - 0x00000282, - 0x00000008, - 0xc0016900, - 0x00000302, - 0x0000002d, - 0xc0016900, - 0x0000037f, - 0x00000000, - 0xc0016900, - 0x000001b2, - 0x00000001, - 0xc0016900, + 0x00000000, /* PA_SU_POLY_OFFSET_DB_FMT_CNTL */ + 0x00000000, /* PA_SU_POLY_OFFSET_CLAMP */ + 0x00000000, /* PA_SU_POLY_OFFSET_FRONT_SCALE */ + 0x00000000, /* PA_SU_POLY_OFFSET_FRONT_OFFSET */ + 0x00000000, /* PA_SU_POLY_OFFSET_BACK_SCALE */ + 0x00000000, /* PA_SU_POLY_OFFSET_BACK_OFFSET */ + + 0xc0046900, 0x000001b6, - 0x00000000, - 0xc0016900, - 0x000001b7, - 0x00000000, - 0xc0016900, - 0x000001b8, - 0x00000000, - 0xc0016900, - 0x000001b9, - 0x00000000, + 0x00000000, /* SPI_INPUT_Z */ + 0x00000000, /* SPI_FOG_CNTL */ + 0x00000000, /* SPI_FOG_FUNC_SCALE */ + 0x00000000, /* SPI_FOG_FUNC_BIAS */ + 0xc0016900, 0x00000225, - 0x00000000, + 0x00000000, /* SQ_PGM_START_FS */ + 0xc0016900, 0x00000229, - 0x00000000, + 0x00000000, /* SQ_PGM_RESOURCES_FS */ + 0xc0016900, 0x00000237, - 0x00000000, - 0xc0016900, - 0x00000100, - 0x00000800, - 0xc0016900, - 0x00000101, - 0x00000000, - 0xc0016900, - 0x00000102, - 0x00000000, - 0xc0016900, + 0x00000000, /* SQ_PGM_CF_OFFSET_FS */ + + 0xc0026900, 0x000002a8, - 0x00000000, - 0xc0016900, - 0x000002a9, - 0x00000000, - 0xc0016900, - 0x00000103, - 0x00000000, - 0xc0016900, - 0x00000284, - 0x00000000, - 0xc0016900, - 0x00000290, - 0x00000000, - 0xc0016900, - 0x00000285, - 0x00000000, - 0xc0016900, - 0x00000286, - 0x00000000, - 0xc0016900, - 0x00000287, - 0x00000000, - 0xc0016900, - 0x00000288, - 0x00000000, - 0xc0016900, - 0x00000289, - 0x00000000, - 0xc0016900, - 0x0000028a, - 0x00000000, - 0xc0016900, - 0x0000028b, - 0x00000000, - 0xc0016900, - 0x0000028c, - 0x00000000, - 0xc0016900, - 0x0000028d, - 0x00000000, - 0xc0016900, - 0x0000028e, - 0x00000000, - 0xc0016900, - 0x0000028f, - 0x00000000, + 0x00000000, /* VGT_INSTANCE_STEP_RATE_0 */ + 0x00000000, /* VGT_INSTANCE_STEP_RATE_1 */ + + 0xc0116900, + 0x00000280, + 0x00000000, /* PA_SU_POINT_SIZE */ + 0x00000000, /* PA_SU_POINT_MINMAX */ + 0x00000008, /* PA_SU_LINE_CNTL */ + 0x00000000, /* PA_SC_LINE_STIPPLE */ + 0x00000000, /* VGT_OUTPUT_PATH_CNTL */ + 0x00000000, /* VGT_HOS_CNTL */ + 0x00000000, /* VGT_HOS_MAX_TESS_LEVEL */ + 0x00000000, /* VGT_HOS_MIN_TESS_LEVEL */ + 0x00000000, /* VGT_HOS_REUSE_DEPTH */ + 0x00000000, /* VGT_GROUP_PRIM_TYPE */ + 0x00000000, /* VGT_GROUP_FIRST_DECR */ + 0x00000000, /* VGT_GROUP_DECR */ + 0x00000000, /* VGT_GROUP_VECT_0_CNTL */ + 0x00000000, /* VGT_GROUP_VECT_1_CNTL */ + 0x00000000, /* VGT_GROUP_VECT_0_FMT_CNTL */ + 0x00000000, /* VGT_GROUP_VECT_1_FMT_CNTL */ + 0x00000000, /* VGT_GS_MODE */ + 0xc0016900, 0x000002a1, - 0x00000000, + 0x00000000, /* VGT_PRIMITIVEID_EN */ + 0xc0016900, 0x000002a5, - 0x00000000, - 0xc0016900, + 0x00000000, /* VGT_MULTI_PRIM_ID_RESET_EN */ + + 0xc0036900, 0x000002ac, - 0x00000000, - 0xc0016900, - 0x000002ad, - 0x00000000, - 0xc0016900, - 0x000002ae, - 0x00000000, + 0x00000000, /* VGT_STRMOUT_EN */ + 0x00000000, /* VGT_REUSE_OFF */ + 0x00000000, /* VGT_VTX_CNT_EN */ + 0xc0016900, 0x000002c8, - 0x00000000, - 0xc0016900, - 0x00000206, - 0x00000100, - 0xc0016900, - 0x00000204, - 0x00010000, - 0xc0036e00, - 0x00000000, - 0x00000012, - 0x00000000, - 0x00000000, - 0xc0016900, - 0x0000008f, - 0x0000000f, - 0xc0016900, - 0x000001e8, - 0x00000001, - 0xc0016900, + 0x00000000, /* VGT_STRMOUT_BUFFER_EN */ + + 0xc0076900, 0x00000202, - 0x00cc0000, + 0x00cc0000, /* CB_COLOR_CONTROL */ + 0x00000210, /* DB_SHADER_CNTL */ + 0x00010000, /* PA_CL_CLIP_CNTL */ + 0x00000244, /* PA_SU_SC_MODE_CNTL */ + 0x00000100, /* PA_CL_VTE_CNTL */ + 0x00000000, /* PA_CL_VS_OUT_CNTL */ + 0x00000000, /* PA_CL_NANINF_CNTL */ + + 0xc0026900, + 0x0000008e, + 0x0000000f, /* CB_TARGET_MASK */ + 0x0000000f, /* CB_SHADER_MASK */ + 0xc0016900, - 0x00000205, - 0x00000244, + 0x000001e8, + 0x00000001, /* CB_SHADER_CONTROL */ + 0xc0016900, - 0x00000203, - 0x00000210, + 0x00000185, + 0x00000000, /* SPI_VS_OUT_ID_0 */ + 0xc0016900, + 0x00000191, + 0x00000b00, /* SPI_PS_INPUT_CNTL_0 */ + + 0xc0056900, 0x000001b1, + 0x00000000, /* SPI_VS_OUT_CONFIG */ + 0x00000001, /* SPI_THREAD_GROUPING */ + 0x00000001, /* SPI_PS_IN_CONTROL_0 */ + 0x00000000, /* SPI_PS_IN_CONTROL_1 */ + 0x00000000, /* SPI_INTERP_CONTROL_0 */ + + 0xc0036e00, /* SET_SAMPLER */ 0x00000000, - 0xc0016900, - 0x00000185, - 0x00000000, - 0xc0016900, - 0x000001b3, - 0x00000001, - 0xc0016900, - 0x000001b4, + 0x00000012, 0x00000000, - 0xc0016900, - 0x00000191, - 0x00000b00, - 0xc0016900, - 0x000001b5, 0x00000000, }; diff --git a/drivers/gpu/drm/radeon/r600_cs.c b/drivers/gpu/drm/radeon/r600_cs.c index 144c32d..c3ea212 100644 --- a/drivers/gpu/drm/radeon/r600_cs.c +++ b/drivers/gpu/drm/radeon/r600_cs.c @@ -25,6 +25,7 @@ * Alex Deucher * Jerome Glisse */ +#include <linux/kernel.h> #include "drmP.h" #include "radeon.h" #include "r600d.h" @@ -166,7 +167,7 @@ static void r600_cs_track_init(struct r600_cs_track *track) static inline int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int i) { struct r600_cs_track *track = p->track; - u32 bpe = 0, pitch, slice_tile_max, size, tmp, height; + u32 bpe = 0, pitch, slice_tile_max, size, tmp, height, pitch_align; volatile u32 *ib = p->ib->ptr; if (G_0280A0_TILE_MODE(track->cb_color_info[i])) { @@ -180,56 +181,57 @@ static inline int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int i) i, track->cb_color_info[i]); return -EINVAL; } - pitch = (G_028060_PITCH_TILE_MAX(track->cb_color_size[i]) + 1) << 3; + /* pitch is the number of 8x8 tiles per row */ + pitch = G_028060_PITCH_TILE_MAX(track->cb_color_size[i]) + 1; slice_tile_max = G_028060_SLICE_TILE_MAX(track->cb_color_size[i]) + 1; - if (!pitch) { - dev_warn(p->dev, "%s:%d cb pitch (%d) for %d invalid (0x%08X)\n", - __func__, __LINE__, pitch, i, track->cb_color_size[i]); - return -EINVAL; - } - height = size / (pitch * bpe); + height = size / (pitch * 8 * bpe); if (height > 8192) height = 8192; + if (height > 7) + height &= ~0x7; switch (G_0280A0_ARRAY_MODE(track->cb_color_info[i])) { case V_0280A0_ARRAY_LINEAR_GENERAL: + /* technically height & 0x7 */ + break; case V_0280A0_ARRAY_LINEAR_ALIGNED: - if (pitch & 0x3f) { - dev_warn(p->dev, "%s:%d cb pitch (%d x %d = %d) invalid\n", - __func__, __LINE__, pitch, bpe, pitch * bpe); + pitch_align = max((u32)64, (u32)(track->group_size / bpe)) / 8; + if (!IS_ALIGNED(pitch, pitch_align)) { + dev_warn(p->dev, "%s:%d cb pitch (%d) invalid\n", + __func__, __LINE__, pitch); return -EINVAL; } - if ((pitch * bpe) & (track->group_size - 1)) { - dev_warn(p->dev, "%s:%d cb pitch (%d) invalid\n", - __func__, __LINE__, pitch); + if (!IS_ALIGNED(height, 8)) { + dev_warn(p->dev, "%s:%d cb height (%d) invalid\n", + __func__, __LINE__, height); return -EINVAL; } break; case V_0280A0_ARRAY_1D_TILED_THIN1: - if ((pitch * 8 * bpe * track->nsamples) & (track->group_size - 1)) { + pitch_align = max((u32)8, (u32)(track->group_size / (8 * bpe * track->nsamples))) / 8; + if (!IS_ALIGNED(pitch, pitch_align)) { dev_warn(p->dev, "%s:%d cb pitch (%d) invalid\n", - __func__, __LINE__, pitch); + __func__, __LINE__, pitch); + return -EINVAL; + } + if (!IS_ALIGNED(height, 8)) { + dev_warn(p->dev, "%s:%d cb height (%d) invalid\n", + __func__, __LINE__, height); return -EINVAL; } - height &= ~0x7; - if (!height) - height = 8; break; case V_0280A0_ARRAY_2D_TILED_THIN1: - if (pitch & ((8 * track->nbanks) - 1)) { + pitch_align = max((u32)track->nbanks, + (u32)(((track->group_size / 8) / (bpe * track->nsamples)) * track->nbanks)); + if (!IS_ALIGNED(pitch, pitch_align)) { dev_warn(p->dev, "%s:%d cb pitch (%d) invalid\n", __func__, __LINE__, pitch); return -EINVAL; } - tmp = pitch * 8 * bpe * track->nsamples; - tmp = tmp / track->nbanks; - if (tmp & (track->group_size - 1)) { - dev_warn(p->dev, "%s:%d cb pitch (%d) invalid\n", - __func__, __LINE__, pitch); + if (!IS_ALIGNED((height / 8), track->nbanks)) { + dev_warn(p->dev, "%s:%d cb height (%d) invalid\n", + __func__, __LINE__, height); return -EINVAL; } - height &= ~((16 * track->npipes) - 1); - if (!height) - height = 16 * track->npipes; break; default: dev_warn(p->dev, "%s invalid tiling %d for %d (0x%08X)\n", __func__, @@ -238,16 +240,20 @@ static inline int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int i) return -EINVAL; } /* check offset */ - tmp = height * pitch; + tmp = height * pitch * 8 * bpe; if ((tmp + track->cb_color_bo_offset[i]) > radeon_bo_size(track->cb_color_bo[i])) { - dev_warn(p->dev, "%s offset[%d] %d to big\n", __func__, i, track->cb_color_bo_offset[i]); + dev_warn(p->dev, "%s offset[%d] %d too big\n", __func__, i, track->cb_color_bo_offset[i]); + return -EINVAL; + } + if (!IS_ALIGNED(track->cb_color_bo_offset[i], track->group_size)) { + dev_warn(p->dev, "%s offset[%d] %d not aligned\n", __func__, i, track->cb_color_bo_offset[i]); return -EINVAL; } /* limit max tile */ - tmp = (height * pitch) >> 6; + tmp = (height * pitch * 8) >> 6; if (tmp < slice_tile_max) slice_tile_max = tmp; - tmp = S_028060_PITCH_TILE_MAX((pitch >> 3) - 1) | + tmp = S_028060_PITCH_TILE_MAX(pitch - 1) | S_028060_SLICE_TILE_MAX(slice_tile_max - 1); ib[track->cb_color_size_idx[i]] = tmp; return 0; @@ -289,7 +295,7 @@ static int r600_cs_track_check(struct radeon_cs_parser *p) /* Check depth buffer */ if (G_028800_STENCIL_ENABLE(track->db_depth_control) || G_028800_Z_ENABLE(track->db_depth_control)) { - u32 nviews, bpe, ntiles; + u32 nviews, bpe, ntiles, pitch, pitch_align, height, size; if (track->db_bo == NULL) { dev_warn(p->dev, "z/stencil with no depth buffer\n"); return -EINVAL; @@ -332,6 +338,51 @@ static int r600_cs_track_check(struct radeon_cs_parser *p) } ib[track->db_depth_size_idx] = S_028000_SLICE_TILE_MAX(tmp - 1) | (track->db_depth_size & 0x3FF); } else { + size = radeon_bo_size(track->db_bo); + pitch = G_028000_PITCH_TILE_MAX(track->db_depth_size) + 1; + height = size / (pitch * 8 * bpe); + height &= ~0x7; + if (!height) + height = 8; + + switch (G_028010_ARRAY_MODE(track->db_depth_info)) { + case V_028010_ARRAY_1D_TILED_THIN1: + pitch_align = (max((u32)8, (u32)(track->group_size / (8 * bpe))) / 8); + if (!IS_ALIGNED(pitch, pitch_align)) { + dev_warn(p->dev, "%s:%d db pitch (%d) invalid\n", + __func__, __LINE__, pitch); + return -EINVAL; + } + if (!IS_ALIGNED(height, 8)) { + dev_warn(p->dev, "%s:%d db height (%d) invalid\n", + __func__, __LINE__, height); + return -EINVAL; + } + break; + case V_028010_ARRAY_2D_TILED_THIN1: + pitch_align = max((u32)track->nbanks, + (u32)(((track->group_size / 8) / bpe) * track->nbanks)); + if (!IS_ALIGNED(pitch, pitch_align)) { + dev_warn(p->dev, "%s:%d db pitch (%d) invalid\n", + __func__, __LINE__, pitch); + return -EINVAL; + } + if ((height / 8) & (track->nbanks - 1)) { + dev_warn(p->dev, "%s:%d db height (%d) invalid\n", + __func__, __LINE__, height); + return -EINVAL; + } + break; + default: + dev_warn(p->dev, "%s invalid tiling %d (0x%08X)\n", __func__, + G_028010_ARRAY_MODE(track->db_depth_info), + track->db_depth_info); + return -EINVAL; + } + if (!IS_ALIGNED(track->db_offset, track->group_size)) { + dev_warn(p->dev, "%s offset[%d] %d not aligned\n", __func__, i, track->db_offset); + return -EINVAL; + } ntiles = G_028000_SLICE_TILE_MAX(track->db_depth_size) + 1; nviews = G_028004_SLICE_MAX(track->db_depth_view) + 1; tmp = ntiles * bpe * 64 * nviews; @@ -724,7 +775,25 @@ static inline int r600_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx track->db_depth_control = radeon_get_ib_value(p, idx); break; case R_028010_DB_DEPTH_INFO: - track->db_depth_info = radeon_get_ib_value(p, idx); + if (r600_cs_packet_next_is_pkt3_nop(p)) { + r = r600_cs_packet_next_reloc(p, &reloc); + if (r) { + dev_warn(p->dev, "bad SET_CONTEXT_REG " + "0x%04X\n", reg); + return -EINVAL; + } + track->db_depth_info = radeon_get_ib_value(p, idx); + ib[idx] &= C_028010_ARRAY_MODE; + track->db_depth_info &= C_028010_ARRAY_MODE; + if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO) { + ib[idx] |= S_028010_ARRAY_MODE(V_028010_ARRAY_2D_TILED_THIN1); + track->db_depth_info |= S_028010_ARRAY_MODE(V_028010_ARRAY_2D_TILED_THIN1); + } else { + ib[idx] |= S_028010_ARRAY_MODE(V_028010_ARRAY_1D_TILED_THIN1); + track->db_depth_info |= S_028010_ARRAY_MODE(V_028010_ARRAY_1D_TILED_THIN1); + } + } else + track->db_depth_info = radeon_get_ib_value(p, idx); break; case R_028004_DB_DEPTH_VIEW: track->db_depth_view = radeon_get_ib_value(p, idx); @@ -757,8 +826,25 @@ static inline int r600_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx case R_0280B4_CB_COLOR5_INFO: case R_0280B8_CB_COLOR6_INFO: case R_0280BC_CB_COLOR7_INFO: - tmp = (reg - R_0280A0_CB_COLOR0_INFO) / 4; - track->cb_color_info[tmp] = radeon_get_ib_value(p, idx); + if (r600_cs_packet_next_is_pkt3_nop(p)) { + r = r600_cs_packet_next_reloc(p, &reloc); + if (r) { + dev_err(p->dev, "bad SET_CONTEXT_REG 0x%04X\n", reg); + return -EINVAL; + } + tmp = (reg - R_0280A0_CB_COLOR0_INFO) / 4; + track->cb_color_info[tmp] = radeon_get_ib_value(p, idx); + if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO) { + ib[idx] |= S_0280A0_ARRAY_MODE(V_0280A0_ARRAY_2D_TILED_THIN1); + track->cb_color_info[tmp] |= S_0280A0_ARRAY_MODE(V_0280A0_ARRAY_2D_TILED_THIN1); + } else if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO) { + ib[idx] |= S_0280A0_ARRAY_MODE(V_0280A0_ARRAY_1D_TILED_THIN1); + track->cb_color_info[tmp] |= S_0280A0_ARRAY_MODE(V_0280A0_ARRAY_1D_TILED_THIN1); + } + } else { + tmp = (reg - R_0280A0_CB_COLOR0_INFO) / 4; + track->cb_color_info[tmp] = radeon_get_ib_value(p, idx); + } break; case R_028060_CB_COLOR0_SIZE: case R_028064_CB_COLOR1_SIZE: @@ -946,8 +1032,9 @@ static inline unsigned minify(unsigned size, unsigned levels) } static void r600_texture_size(unsigned nfaces, unsigned blevel, unsigned nlevels, - unsigned w0, unsigned h0, unsigned d0, unsigned bpe, - unsigned *l0_size, unsigned *mipmap_size) + unsigned w0, unsigned h0, unsigned d0, unsigned bpe, + unsigned pitch_align, + unsigned *l0_size, unsigned *mipmap_size) { unsigned offset, i, level, face; unsigned width, height, depth, rowstride, size; @@ -960,13 +1047,13 @@ static void r600_texture_size(unsigned nfaces, unsigned blevel, unsigned nlevels height = minify(h0, i); depth = minify(d0, i); for(face = 0; face < nfaces; face++) { - rowstride = ((width * bpe) + 255) & ~255; + rowstride = ALIGN((width * bpe), pitch_align); size = height * rowstride * depth; offset += size; offset = (offset + 0x1f) & ~0x1f; } } - *l0_size = (((w0 * bpe) + 255) & ~255) * h0 * d0; + *l0_size = ALIGN((w0 * bpe), pitch_align) * h0 * d0; *mipmap_size = offset; if (!blevel) *mipmap_size -= *l0_size; @@ -985,16 +1072,23 @@ static void r600_texture_size(unsigned nfaces, unsigned blevel, unsigned nlevels * the texture and mipmap bo object are big enough to cover this resource. */ static inline int r600_check_texture_resource(struct radeon_cs_parser *p, u32 idx, - struct radeon_bo *texture, - struct radeon_bo *mipmap) + struct radeon_bo *texture, + struct radeon_bo *mipmap, + u32 tiling_flags) { + struct r600_cs_track *track = p->track; u32 nfaces, nlevels, blevel, w0, h0, d0, bpe = 0; - u32 word0, word1, l0_size, mipmap_size; + u32 word0, word1, l0_size, mipmap_size, pitch, pitch_align; /* on legacy kernel we don't perform advanced check */ if (p->rdev == NULL) return 0; + word0 = radeon_get_ib_value(p, idx + 0); + if (tiling_flags & RADEON_TILING_MACRO) + word0 |= S_038000_TILE_MODE(V_038000_ARRAY_2D_TILED_THIN1); + else if (tiling_flags & RADEON_TILING_MICRO) + word0 |= S_038000_TILE_MODE(V_038000_ARRAY_1D_TILED_THIN1); word1 = radeon_get_ib_value(p, idx + 1); w0 = G_038000_TEX_WIDTH(word0) + 1; h0 = G_038004_TEX_HEIGHT(word1) + 1; @@ -1021,11 +1115,55 @@ static inline int r600_check_texture_resource(struct radeon_cs_parser *p, u32 i __func__, __LINE__, G_038004_DATA_FORMAT(word1)); return -EINVAL; } + + pitch = G_038000_PITCH(word0) + 1; + switch (G_038000_TILE_MODE(word0)) { + case V_038000_ARRAY_LINEAR_GENERAL: + pitch_align = 1; + /* XXX check height align */ + break; + case V_038000_ARRAY_LINEAR_ALIGNED: + pitch_align = max((u32)64, (u32)(track->group_size / bpe)) / 8; + if (!IS_ALIGNED(pitch, pitch_align)) { + dev_warn(p->dev, "%s:%d tex pitch (%d) invalid\n", + __func__, __LINE__, pitch); + return -EINVAL; + } + /* XXX check height align */ + break; + case V_038000_ARRAY_1D_TILED_THIN1: + pitch_align = max((u32)8, (u32)(track->group_size / (8 * bpe))) / 8; + if (!IS_ALIGNED(pitch, pitch_align)) { + dev_warn(p->dev, "%s:%d tex pitch (%d) invalid\n", + __func__, __LINE__, pitch); + return -EINVAL; + } + /* XXX check height align */ + break; + case V_038000_ARRAY_2D_TILED_THIN1: + pitch_align = max((u32)track->nbanks, + (u32)(((track->group_size / 8) / bpe) * track->nbanks)); + if (!IS_ALIGNED(pitch, pitch_align)) { + dev_warn(p->dev, "%s:%d tex pitch (%d) invalid\n", + __func__, __LINE__, pitch); + return -EINVAL; + } + /* XXX check height align */ + break; + default: + dev_warn(p->dev, "%s invalid tiling %d (0x%08X)\n", __func__, + G_038000_TILE_MODE(word0), word0); + return -EINVAL; + } + /* XXX check offset align */ + word0 = radeon_get_ib_value(p, idx + 4); word1 = radeon_get_ib_value(p, idx + 5); blevel = G_038010_BASE_LEVEL(word0); nlevels = G_038014_LAST_LEVEL(word1); - r600_texture_size(nfaces, blevel, nlevels, w0, h0, d0, bpe, &l0_size, &mipmap_size); + r600_texture_size(nfaces, blevel, nlevels, w0, h0, d0, bpe, + (pitch_align * bpe), + &l0_size, &mipmap_size); /* using get ib will give us the offset into the texture bo */ word0 = radeon_get_ib_value(p, idx + 2); if ((l0_size + word0) > radeon_bo_size(texture)) { @@ -1239,6 +1377,10 @@ static int r600_packet3_check(struct radeon_cs_parser *p, return -EINVAL; } ib[idx+1+(i*7)+2] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); + if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO) + ib[idx+1+(i*7)+0] |= S_038000_TILE_MODE(V_038000_ARRAY_2D_TILED_THIN1); + else if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO) + ib[idx+1+(i*7)+0] |= S_038000_TILE_MODE(V_038000_ARRAY_1D_TILED_THIN1); texture = reloc->robj; /* tex mip base */ r = r600_cs_packet_next_reloc(p, &reloc); @@ -1249,7 +1391,7 @@ static int r600_packet3_check(struct radeon_cs_parser *p, ib[idx+1+(i*7)+3] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); mipmap = reloc->robj; r = r600_check_texture_resource(p, idx+(i*7)+1, - texture, mipmap); + texture, mipmap, reloc->lobj.tiling_flags); if (r) return r; break; diff --git a/drivers/gpu/drm/radeon/r600_hdmi.c b/drivers/gpu/drm/radeon/r600_hdmi.c index 26b4bc9..e6a58ed 100644 --- a/drivers/gpu/drm/radeon/r600_hdmi.c +++ b/drivers/gpu/drm/radeon/r600_hdmi.c @@ -435,7 +435,8 @@ static int r600_hdmi_find_free_block(struct drm_device *dev) } } - if (rdev->family == CHIP_RS600 || rdev->family == CHIP_RS690) { + if (rdev->family == CHIP_RS600 || rdev->family == CHIP_RS690 || + rdev->family == CHIP_RS740) { return free_blocks[0] ? R600_HDMI_BLOCK1 : 0; } else if (rdev->family >= CHIP_R600) { if (free_blocks[0]) @@ -466,7 +467,8 @@ static void r600_hdmi_assign_block(struct drm_encoder *encoder) if (ASIC_IS_DCE32(rdev)) radeon_encoder->hdmi_config_offset = dig->dig_encoder ? R600_HDMI_CONFIG2 : R600_HDMI_CONFIG1; - } else if (rdev->family >= CHIP_R600) { + } else if (rdev->family >= CHIP_R600 || rdev->family == CHIP_RS600 || + rdev->family == CHIP_RS690 || rdev->family == CHIP_RS740) { radeon_encoder->hdmi_offset = r600_hdmi_find_free_block(dev); } } diff --git a/drivers/gpu/drm/radeon/r600d.h b/drivers/gpu/drm/radeon/r600d.h index 59c1f87..858a192 100644 --- a/drivers/gpu/drm/radeon/r600d.h +++ b/drivers/gpu/drm/radeon/r600d.h @@ -239,12 +239,18 @@ #define GRBM_SOFT_RESET 0x8020 #define SOFT_RESET_CP (1<<0) +#define CG_THERMAL_STATUS 0x7F4 +#define ASIC_T(x) ((x) << 0) +#define ASIC_T_MASK 0x1FF +#define ASIC_T_SHIFT 0 + #define HDP_HOST_PATH_CNTL 0x2C00 #define HDP_NONSURFACE_BASE 0x2C04 #define HDP_NONSURFACE_INFO 0x2C08 #define HDP_NONSURFACE_SIZE 0x2C0C #define HDP_REG_COHERENCY_FLUSH_CNTL 0x54A0 #define HDP_TILING_CONFIG 0x2F3C +#define HDP_DEBUG1 0x2F34 #define MC_VM_AGP_TOP 0x2184 #define MC_VM_AGP_BOT 0x2188 @@ -1154,6 +1160,10 @@ #define S_038000_TILE_MODE(x) (((x) & 0xF) << 3) #define G_038000_TILE_MODE(x) (((x) >> 3) & 0xF) #define C_038000_TILE_MODE 0xFFFFFF87 +#define V_038000_ARRAY_LINEAR_GENERAL 0x00000000 +#define V_038000_ARRAY_LINEAR_ALIGNED 0x00000001 +#define V_038000_ARRAY_1D_TILED_THIN1 0x00000002 +#define V_038000_ARRAY_2D_TILED_THIN1 0x00000004 #define S_038000_TILE_TYPE(x) (((x) & 0x1) << 7) #define G_038000_TILE_TYPE(x) (((x) >> 7) & 0x1) #define C_038000_TILE_TYPE 0xFFFFFF7F @@ -1357,6 +1367,8 @@ #define S_028010_ARRAY_MODE(x) (((x) & 0xF) << 15) #define G_028010_ARRAY_MODE(x) (((x) >> 15) & 0xF) #define C_028010_ARRAY_MODE 0xFFF87FFF +#define V_028010_ARRAY_1D_TILED_THIN1 0x00000002 +#define V_028010_ARRAY_2D_TILED_THIN1 0x00000004 #define S_028010_TILE_SURFACE_ENABLE(x) (((x) & 0x1) << 25) #define G_028010_TILE_SURFACE_ENABLE(x) (((x) >> 25) & 0x1) #define C_028010_TILE_SURFACE_ENABLE 0xFDFFFFFF diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 2f94dc6..3cd1c47 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -178,6 +178,9 @@ void radeon_combios_get_power_modes(struct radeon_device *rdev); void radeon_atombios_get_power_modes(struct radeon_device *rdev); void radeon_atom_set_voltage(struct radeon_device *rdev, u16 level); void rs690_pm_info(struct radeon_device *rdev); +extern u32 rv6xx_get_temp(struct radeon_device *rdev); +extern u32 rv770_get_temp(struct radeon_device *rdev); +extern u32 evergreen_get_temp(struct radeon_device *rdev); /* * Fences. @@ -232,7 +235,7 @@ struct radeon_surface_reg { */ struct radeon_mman { struct ttm_bo_global_ref bo_global_ref; - struct ttm_global_reference mem_global_ref; + struct drm_global_reference mem_global_ref; struct ttm_bo_device bdev; bool mem_global_referenced; bool initialized; @@ -671,6 +674,13 @@ struct radeon_pm_profile { int dpms_on_cm_idx; }; +enum radeon_int_thermal_type { + THERMAL_TYPE_NONE, + THERMAL_TYPE_RV6XX, + THERMAL_TYPE_RV770, + THERMAL_TYPE_EVERGREEN, +}; + struct radeon_voltage { enum radeon_voltage_type type; /* gpio voltage */ @@ -766,6 +776,9 @@ struct radeon_pm { enum radeon_pm_profile_type profile; int profile_index; struct radeon_pm_profile profiles[PM_PROFILE_MAX]; + /* internal thermal controller on rv6xx+ */ + enum radeon_int_thermal_type int_thermal_type; + struct device *int_hwmon_dev; }; @@ -902,6 +915,7 @@ struct r600_asic { unsigned tiling_nbanks; unsigned tiling_npipes; unsigned tiling_group_size; + unsigned tile_config; struct r100_gpu_lockup lockup; }; @@ -926,6 +940,7 @@ struct rv770_asic { unsigned tiling_nbanks; unsigned tiling_npipes; unsigned tiling_group_size; + unsigned tile_config; struct r100_gpu_lockup lockup; }; @@ -951,6 +966,7 @@ struct evergreen_asic { unsigned tiling_nbanks; unsigned tiling_npipes; unsigned tiling_group_size; + unsigned tile_config; }; union radeon_asic_config { @@ -1033,6 +1049,9 @@ struct radeon_device { uint32_t pcie_reg_mask; radeon_rreg_t pciep_rreg; radeon_wreg_t pciep_wreg; + /* io port */ + void __iomem *rio_mem; + resource_size_t rio_mem_size; struct radeon_clock clock; struct radeon_mc mc; struct radeon_gart gart; @@ -1069,6 +1088,7 @@ struct radeon_device { struct mutex vram_mutex; /* audio stuff */ + bool audio_enabled; struct timer_list audio_timer; int audio_channels; int audio_rate; @@ -1078,6 +1098,8 @@ struct radeon_device { bool powered_down; struct notifier_block acpi_nb; + /* only one userspace can use Hyperz features at a time */ + struct drm_file *hyperz_filp; }; int radeon_device_init(struct radeon_device *rdev, @@ -1114,6 +1136,26 @@ static inline void r100_mm_wreg(struct radeon_device *rdev, uint32_t reg, uint32 } } +static inline u32 r100_io_rreg(struct radeon_device *rdev, u32 reg) +{ + if (reg < rdev->rio_mem_size) + return ioread32(rdev->rio_mem + reg); + else { + iowrite32(reg, rdev->rio_mem + RADEON_MM_INDEX); + return ioread32(rdev->rio_mem + RADEON_MM_DATA); + } +} + +static inline void r100_io_wreg(struct radeon_device *rdev, u32 reg, u32 v) +{ + if (reg < rdev->rio_mem_size) + iowrite32(v, rdev->rio_mem + reg); + else { + iowrite32(reg, rdev->rio_mem + RADEON_MM_INDEX); + iowrite32(v, rdev->rio_mem + RADEON_MM_DATA); + } +} + /* * Cast helper */ @@ -1152,6 +1194,8 @@ static inline void r100_mm_wreg(struct radeon_device *rdev, uint32_t reg, uint32 WREG32_PLL(reg, tmp_); \ } while (0) #define DREG32_SYS(sqf, rdev, reg) seq_printf((sqf), #reg " : 0x%08X\n", r100_mm_rreg((rdev), (reg))) +#define RREG32_IO(reg) r100_io_rreg(rdev, (reg)) +#define WREG32_IO(reg, v) r100_io_wreg(rdev, (reg), (v)) /* * Indirect registers accessor @@ -1415,6 +1459,13 @@ extern void r700_cp_fini(struct radeon_device *rdev); extern void evergreen_disable_interrupt_state(struct radeon_device *rdev); extern int evergreen_irq_set(struct radeon_device *rdev); +/* radeon_acpi.c */ +#if defined(CONFIG_ACPI) +extern int radeon_acpi_init(struct radeon_device *rdev); +#else +static inline int radeon_acpi_init(struct radeon_device *rdev) { return 0; } +#endif + /* evergreen */ struct evergreen_mc_save { u32 vga_control[6]; diff --git a/drivers/gpu/drm/radeon/radeon_acpi.c b/drivers/gpu/drm/radeon/radeon_acpi.c new file mode 100644 index 0000000..3f6636b --- /dev/null +++ b/drivers/gpu/drm/radeon/radeon_acpi.c @@ -0,0 +1,67 @@ +#include <linux/pci.h> +#include <linux/acpi.h> +#include <linux/slab.h> +#include <acpi/acpi_drivers.h> +#include <acpi/acpi_bus.h> + +#include "drmP.h" +#include "drm.h" +#include "drm_sarea.h" +#include "drm_crtc_helper.h" +#include "radeon.h" + +#include <linux/vga_switcheroo.h> + +/* Call the ATIF method + * + * Note: currently we discard the output + */ +static int radeon_atif_call(acpi_handle handle) +{ + acpi_status status; + union acpi_object atif_arg_elements[2]; + struct acpi_object_list atif_arg; + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL}; + + atif_arg.count = 2; + atif_arg.pointer = &atif_arg_elements[0]; + + atif_arg_elements[0].type = ACPI_TYPE_INTEGER; + atif_arg_elements[0].integer.value = 0; + atif_arg_elements[1].type = ACPI_TYPE_INTEGER; + atif_arg_elements[1].integer.value = 0; + + status = acpi_evaluate_object(handle, "ATIF", &atif_arg, &buffer); + + /* Fail only if calling the method fails and ATIF is supported */ + if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { + printk(KERN_DEBUG "failed to evaluate ATIF got %s\n", acpi_format_exception(status)); + kfree(buffer.pointer); + return 1; + } + + kfree(buffer.pointer); + return 0; +} + +/* Call all ACPI methods here */ +int radeon_acpi_init(struct radeon_device *rdev) +{ + acpi_handle handle; + int ret; + + /* No need to proceed if we're sure that ATIF is not supported */ + if (!ASIC_IS_AVIVO(rdev) || !rdev->bios) + return 0; + + /* Get the device handle */ + handle = DEVICE_ACPI_HANDLE(&rdev->pdev->dev); + + /* Call the ATIF method */ + ret = radeon_atif_call(handle); + if (ret) + return ret; + + return 0; +} + diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h index c0bbaa6..a5aff75 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.h +++ b/drivers/gpu/drm/radeon/radeon_asic.h @@ -113,6 +113,7 @@ void r100_wb_fini(struct radeon_device *rdev); int r100_wb_init(struct radeon_device *rdev); int r100_cp_reset(struct radeon_device *rdev); void r100_vga_render_disable(struct radeon_device *rdev); +void r100_restore_sanity(struct radeon_device *rdev); int r100_cs_track_check_pkt3_indx_buffer(struct radeon_cs_parser *p, struct radeon_cs_packet *pkt, struct radeon_bo *robj); diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index 10673ae..3bc2bcd 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -723,7 +723,7 @@ bool radeon_get_atom_connector_info_from_supported_devices_table(struct } if (i == ATOM_DEVICE_CV_INDEX) { - DRM_DEBUG("Skipping Component Video\n"); + DRM_DEBUG_KMS("Skipping Component Video\n"); continue; } @@ -1032,21 +1032,18 @@ bool radeon_atombios_sideport_present(struct radeon_device *rdev) u8 frev, crev; u16 data_offset; + /* sideport is AMD only */ + if (rdev->family == CHIP_RS600) + return false; + if (atom_parse_data_header(mode_info->atom_context, index, NULL, &frev, &crev, &data_offset)) { igp_info = (union igp_info *)(mode_info->atom_context->bios + data_offset); switch (crev) { case 1: - /* AMD IGPS */ - if ((rdev->family == CHIP_RS690) || - (rdev->family == CHIP_RS740)) { - if (igp_info->info.ulBootUpMemoryClock) - return true; - } else { - if (igp_info->info.ucMemoryType & 0xf0) - return true; - } + if (igp_info->info.ulBootUpMemoryClock) + return true; break; case 2: if (igp_info->info_2.ucMemoryType & 0x0f) @@ -1095,7 +1092,7 @@ bool radeon_atombios_get_tmds_info(struct radeon_encoder *encoder, (tmds_info->asMiscInfo[i]. ucPLL_VoltageSwing & 0xf) << 16; - DRM_DEBUG("TMDS PLL From ATOMBIOS %u %x\n", + DRM_DEBUG_KMS("TMDS PLL From ATOMBIOS %u %x\n", tmds->tmds_pll[i].freq, tmds->tmds_pll[i].value); @@ -1789,14 +1786,22 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) } /* add the i2c bus for thermal/fan chip */ - /* no support for internal controller yet */ if (controller->ucType > 0) { - if ((controller->ucType == ATOM_PP_THERMALCONTROLLER_RV6xx) || - (controller->ucType == ATOM_PP_THERMALCONTROLLER_RV770) || - (controller->ucType == ATOM_PP_THERMALCONTROLLER_EVERGREEN)) { + if (controller->ucType == ATOM_PP_THERMALCONTROLLER_RV6xx) { + DRM_INFO("Internal thermal controller %s fan control\n", + (controller->ucFanParameters & + ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); + rdev->pm.int_thermal_type = THERMAL_TYPE_RV6XX; + } else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_RV770) { + DRM_INFO("Internal thermal controller %s fan control\n", + (controller->ucFanParameters & + ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); + rdev->pm.int_thermal_type = THERMAL_TYPE_RV770; + } else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_EVERGREEN) { DRM_INFO("Internal thermal controller %s fan control\n", (controller->ucFanParameters & ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); + rdev->pm.int_thermal_type = THERMAL_TYPE_EVERGREEN; } else if ((controller->ucType == ATOM_PP_THERMALCONTROLLER_EXTERNAL_GPIO) || (controller->ucType == @@ -2179,11 +2184,11 @@ radeon_atombios_connected_scratch_regs(struct drm_connector *connector, if ((radeon_encoder->devices & ATOM_DEVICE_TV1_SUPPORT) && (radeon_connector->devices & ATOM_DEVICE_TV1_SUPPORT)) { if (connected) { - DRM_DEBUG("TV1 connected\n"); + DRM_DEBUG_KMS("TV1 connected\n"); bios_3_scratch |= ATOM_S3_TV1_ACTIVE; bios_6_scratch |= ATOM_S6_ACC_REQ_TV1; } else { - DRM_DEBUG("TV1 disconnected\n"); + DRM_DEBUG_KMS("TV1 disconnected\n"); bios_0_scratch &= ~ATOM_S0_TV1_MASK; bios_3_scratch &= ~ATOM_S3_TV1_ACTIVE; bios_6_scratch &= ~ATOM_S6_ACC_REQ_TV1; @@ -2192,11 +2197,11 @@ radeon_atombios_connected_scratch_regs(struct drm_connector *connector, if ((radeon_encoder->devices & ATOM_DEVICE_CV_SUPPORT) && (radeon_connector->devices & ATOM_DEVICE_CV_SUPPORT)) { if (connected) { - DRM_DEBUG("CV connected\n"); + DRM_DEBUG_KMS("CV connected\n"); bios_3_scratch |= ATOM_S3_CV_ACTIVE; bios_6_scratch |= ATOM_S6_ACC_REQ_CV; } else { - DRM_DEBUG("CV disconnected\n"); + DRM_DEBUG_KMS("CV disconnected\n"); bios_0_scratch &= ~ATOM_S0_CV_MASK; bios_3_scratch &= ~ATOM_S3_CV_ACTIVE; bios_6_scratch &= ~ATOM_S6_ACC_REQ_CV; @@ -2205,12 +2210,12 @@ radeon_atombios_connected_scratch_regs(struct drm_connector *connector, if ((radeon_encoder->devices & ATOM_DEVICE_LCD1_SUPPORT) && (radeon_connector->devices & ATOM_DEVICE_LCD1_SUPPORT)) { if (connected) { - DRM_DEBUG("LCD1 connected\n"); + DRM_DEBUG_KMS("LCD1 connected\n"); bios_0_scratch |= ATOM_S0_LCD1; bios_3_scratch |= ATOM_S3_LCD1_ACTIVE; bios_6_scratch |= ATOM_S6_ACC_REQ_LCD1; } else { - DRM_DEBUG("LCD1 disconnected\n"); + DRM_DEBUG_KMS("LCD1 disconnected\n"); bios_0_scratch &= ~ATOM_S0_LCD1; bios_3_scratch &= ~ATOM_S3_LCD1_ACTIVE; bios_6_scratch &= ~ATOM_S6_ACC_REQ_LCD1; @@ -2219,12 +2224,12 @@ radeon_atombios_connected_scratch_regs(struct drm_connector *connector, if ((radeon_encoder->devices & ATOM_DEVICE_CRT1_SUPPORT) && (radeon_connector->devices & ATOM_DEVICE_CRT1_SUPPORT)) { if (connected) { - DRM_DEBUG("CRT1 connected\n"); + DRM_DEBUG_KMS("CRT1 connected\n"); bios_0_scratch |= ATOM_S0_CRT1_COLOR; bios_3_scratch |= ATOM_S3_CRT1_ACTIVE; bios_6_scratch |= ATOM_S6_ACC_REQ_CRT1; } else { - DRM_DEBUG("CRT1 disconnected\n"); + DRM_DEBUG_KMS("CRT1 disconnected\n"); bios_0_scratch &= ~ATOM_S0_CRT1_MASK; bios_3_scratch &= ~ATOM_S3_CRT1_ACTIVE; bios_6_scratch &= ~ATOM_S6_ACC_REQ_CRT1; @@ -2233,12 +2238,12 @@ radeon_atombios_connected_scratch_regs(struct drm_connector *connector, if ((radeon_encoder->devices & ATOM_DEVICE_CRT2_SUPPORT) && (radeon_connector->devices & ATOM_DEVICE_CRT2_SUPPORT)) { if (connected) { - DRM_DEBUG("CRT2 connected\n"); + DRM_DEBUG_KMS("CRT2 connected\n"); bios_0_scratch |= ATOM_S0_CRT2_COLOR; bios_3_scratch |= ATOM_S3_CRT2_ACTIVE; bios_6_scratch |= ATOM_S6_ACC_REQ_CRT2; } else { - DRM_DEBUG("CRT2 disconnected\n"); + DRM_DEBUG_KMS("CRT2 disconnected\n"); bios_0_scratch &= ~ATOM_S0_CRT2_MASK; bios_3_scratch &= ~ATOM_S3_CRT2_ACTIVE; bios_6_scratch &= ~ATOM_S6_ACC_REQ_CRT2; @@ -2247,12 +2252,12 @@ radeon_atombios_connected_scratch_regs(struct drm_connector *connector, if ((radeon_encoder->devices & ATOM_DEVICE_DFP1_SUPPORT) && (radeon_connector->devices & ATOM_DEVICE_DFP1_SUPPORT)) { if (connected) { - DRM_DEBUG("DFP1 connected\n"); + DRM_DEBUG_KMS("DFP1 connected\n"); bios_0_scratch |= ATOM_S0_DFP1; bios_3_scratch |= ATOM_S3_DFP1_ACTIVE; bios_6_scratch |= ATOM_S6_ACC_REQ_DFP1; } else { - DRM_DEBUG("DFP1 disconnected\n"); + DRM_DEBUG_KMS("DFP1 disconnected\n"); bios_0_scratch &= ~ATOM_S0_DFP1; bios_3_scratch &= ~ATOM_S3_DFP1_ACTIVE; bios_6_scratch &= ~ATOM_S6_ACC_REQ_DFP1; @@ -2261,12 +2266,12 @@ radeon_atombios_connected_scratch_regs(struct drm_connector *connector, if ((radeon_encoder->devices & ATOM_DEVICE_DFP2_SUPPORT) && (radeon_connector->devices & ATOM_DEVICE_DFP2_SUPPORT)) { if (connected) { - DRM_DEBUG("DFP2 connected\n"); + DRM_DEBUG_KMS("DFP2 connected\n"); bios_0_scratch |= ATOM_S0_DFP2; bios_3_scratch |= ATOM_S3_DFP2_ACTIVE; bios_6_scratch |= ATOM_S6_ACC_REQ_DFP2; } else { - DRM_DEBUG("DFP2 disconnected\n"); + DRM_DEBUG_KMS("DFP2 disconnected\n"); bios_0_scratch &= ~ATOM_S0_DFP2; bios_3_scratch &= ~ATOM_S3_DFP2_ACTIVE; bios_6_scratch &= ~ATOM_S6_ACC_REQ_DFP2; @@ -2275,12 +2280,12 @@ radeon_atombios_connected_scratch_regs(struct drm_connector *connector, if ((radeon_encoder->devices & ATOM_DEVICE_DFP3_SUPPORT) && (radeon_connector->devices & ATOM_DEVICE_DFP3_SUPPORT)) { if (connected) { - DRM_DEBUG("DFP3 connected\n"); + DRM_DEBUG_KMS("DFP3 connected\n"); bios_0_scratch |= ATOM_S0_DFP3; bios_3_scratch |= ATOM_S3_DFP3_ACTIVE; bios_6_scratch |= ATOM_S6_ACC_REQ_DFP3; } else { - DRM_DEBUG("DFP3 disconnected\n"); + DRM_DEBUG_KMS("DFP3 disconnected\n"); bios_0_scratch &= ~ATOM_S0_DFP3; bios_3_scratch &= ~ATOM_S3_DFP3_ACTIVE; bios_6_scratch &= ~ATOM_S6_ACC_REQ_DFP3; @@ -2289,12 +2294,12 @@ radeon_atombios_connected_scratch_regs(struct drm_connector *connector, if ((radeon_encoder->devices & ATOM_DEVICE_DFP4_SUPPORT) && (radeon_connector->devices & ATOM_DEVICE_DFP4_SUPPORT)) { if (connected) { - DRM_DEBUG("DFP4 connected\n"); + DRM_DEBUG_KMS("DFP4 connected\n"); bios_0_scratch |= ATOM_S0_DFP4; bios_3_scratch |= ATOM_S3_DFP4_ACTIVE; bios_6_scratch |= ATOM_S6_ACC_REQ_DFP4; } else { - DRM_DEBUG("DFP4 disconnected\n"); + DRM_DEBUG_KMS("DFP4 disconnected\n"); bios_0_scratch &= ~ATOM_S0_DFP4; bios_3_scratch &= ~ATOM_S3_DFP4_ACTIVE; bios_6_scratch &= ~ATOM_S6_ACC_REQ_DFP4; @@ -2303,12 +2308,12 @@ radeon_atombios_connected_scratch_regs(struct drm_connector *connector, if ((radeon_encoder->devices & ATOM_DEVICE_DFP5_SUPPORT) && (radeon_connector->devices & ATOM_DEVICE_DFP5_SUPPORT)) { if (connected) { - DRM_DEBUG("DFP5 connected\n"); + DRM_DEBUG_KMS("DFP5 connected\n"); bios_0_scratch |= ATOM_S0_DFP5; bios_3_scratch |= ATOM_S3_DFP5_ACTIVE; bios_6_scratch |= ATOM_S6_ACC_REQ_DFP5; } else { - DRM_DEBUG("DFP5 disconnected\n"); + DRM_DEBUG_KMS("DFP5 disconnected\n"); bios_0_scratch &= ~ATOM_S0_DFP5; bios_3_scratch &= ~ATOM_S3_DFP5_ACTIVE; bios_6_scratch &= ~ATOM_S6_ACC_REQ_DFP5; diff --git a/drivers/gpu/drm/radeon/radeon_bios.c b/drivers/gpu/drm/radeon/radeon_bios.c index 2c92137..654787e 100644 --- a/drivers/gpu/drm/radeon/radeon_bios.c +++ b/drivers/gpu/drm/radeon/radeon_bios.c @@ -53,7 +53,7 @@ static bool igp_read_bios_from_vram(struct radeon_device *rdev) return false; rdev->bios = NULL; - vram_base = drm_get_resource_start(rdev->ddev, 0); + vram_base = pci_resource_start(rdev->pdev, 0); bios = ioremap(vram_base, size); if (!bios) { return false; diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c index 2417d7b..5e1474c 100644 --- a/drivers/gpu/drm/radeon/radeon_combios.c +++ b/drivers/gpu/drm/radeon/radeon_combios.c @@ -693,6 +693,10 @@ bool radeon_combios_sideport_present(struct radeon_device *rdev) struct drm_device *dev = rdev->ddev; u16 igp_info; + /* sideport is AMD only */ + if (rdev->family == CHIP_RS400) + return false; + igp_info = combios_get_table_offset(dev, COMBIOS_INTEGRATED_SYSTEM_INFO_TABLE); if (igp_info) { @@ -1205,7 +1209,7 @@ bool radeon_legacy_get_tmds_info_from_combios(struct radeon_encoder *encoder, RBIOS32(tmds_info + i * 10 + 0x08); tmds->tmds_pll[i].freq = RBIOS16(tmds_info + i * 10 + 0x10); - DRM_DEBUG("TMDS PLL From COMBIOS %u %x\n", + DRM_DEBUG_KMS("TMDS PLL From COMBIOS %u %x\n", tmds->tmds_pll[i].freq, tmds->tmds_pll[i].value); } @@ -1223,7 +1227,7 @@ bool radeon_legacy_get_tmds_info_from_combios(struct radeon_encoder *encoder, stride += 10; else stride += 6; - DRM_DEBUG("TMDS PLL From COMBIOS %u %x\n", + DRM_DEBUG_KMS("TMDS PLL From COMBIOS %u %x\n", tmds->tmds_pll[i].freq, tmds->tmds_pll[i].value); } @@ -2208,7 +2212,7 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev) uint16_t tmds_info = combios_get_table_offset(dev, COMBIOS_DFP_INFO_TABLE); if (tmds_info) { - DRM_DEBUG("Found DFP table, assuming DVI connector\n"); + DRM_DEBUG_KMS("Found DFP table, assuming DVI connector\n"); radeon_add_legacy_encoder(dev, radeon_get_encoder_id(dev, @@ -2234,7 +2238,7 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev) } else { uint16_t crt_info = combios_get_table_offset(dev, COMBIOS_CRT_INFO_TABLE); - DRM_DEBUG("Found CRT table, assuming VGA connector\n"); + DRM_DEBUG_KMS("Found CRT table, assuming VGA connector\n"); if (crt_info) { radeon_add_legacy_encoder(dev, radeon_get_encoder_id(dev, @@ -2251,7 +2255,7 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev) CONNECTOR_OBJECT_ID_VGA, &hpd); } else { - DRM_DEBUG("No connector info found\n"); + DRM_DEBUG_KMS("No connector info found\n"); return false; } } @@ -2340,7 +2344,7 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev) ddc_i2c.valid = false; break; } - DRM_DEBUG("LCD DDC Info Table found!\n"); + DRM_DEBUG_KMS("LCD DDC Info Table found!\n"); } else ddc_i2c.valid = false; @@ -2941,9 +2945,8 @@ static void combios_write_ram_size(struct drm_device *dev) if (rev < 3) { mem_cntl = RBIOS32(offset + 1); mem_size = RBIOS16(offset + 5); - if (((rdev->flags & RADEON_FAMILY_MASK) < CHIP_R200) && - ((dev->pdev->device != 0x515e) - && (dev->pdev->device != 0x5969))) + if ((rdev->family < CHIP_R200) && + !ASIC_IS_RN50(rdev)) WREG32(RADEON_MEM_CNTL, mem_cntl); } } @@ -2954,10 +2957,8 @@ static void combios_write_ram_size(struct drm_device *dev) if (offset) { rev = RBIOS8(offset - 1); if (rev < 1) { - if (((rdev->flags & RADEON_FAMILY_MASK) < - CHIP_R200) - && ((dev->pdev->device != 0x515e) - && (dev->pdev->device != 0x5969))) { + if ((rdev->family < CHIP_R200) + && !ASIC_IS_RN50(rdev)) { int ram = 0; int mem_addr_mapping = 0; @@ -3121,14 +3122,14 @@ radeon_combios_connected_scratch_regs(struct drm_connector *connector, if ((radeon_encoder->devices & ATOM_DEVICE_TV1_SUPPORT) && (radeon_connector->devices & ATOM_DEVICE_TV1_SUPPORT)) { if (connected) { - DRM_DEBUG("TV1 connected\n"); + DRM_DEBUG_KMS("TV1 connected\n"); /* fix me */ bios_4_scratch |= RADEON_TV1_ATTACHED_SVIDEO; /*save->bios_4_scratch |= RADEON_TV1_ATTACHED_COMP; */ bios_5_scratch |= RADEON_TV1_ON; bios_5_scratch |= RADEON_ACC_REQ_TV1; } else { - DRM_DEBUG("TV1 disconnected\n"); + DRM_DEBUG_KMS("TV1 disconnected\n"); bios_4_scratch &= ~RADEON_TV1_ATTACHED_MASK; bios_5_scratch &= ~RADEON_TV1_ON; bios_5_scratch &= ~RADEON_ACC_REQ_TV1; @@ -3137,12 +3138,12 @@ radeon_combios_connected_scratch_regs(struct drm_connector *connector, if ((radeon_encoder->devices & ATOM_DEVICE_LCD1_SUPPORT) && (radeon_connector->devices & ATOM_DEVICE_LCD1_SUPPORT)) { if (connected) { - DRM_DEBUG("LCD1 connected\n"); + DRM_DEBUG_KMS("LCD1 connected\n"); bios_4_scratch |= RADEON_LCD1_ATTACHED; bios_5_scratch |= RADEON_LCD1_ON; bios_5_scratch |= RADEON_ACC_REQ_LCD1; } else { - DRM_DEBUG("LCD1 disconnected\n"); + DRM_DEBUG_KMS("LCD1 disconnected\n"); bios_4_scratch &= ~RADEON_LCD1_ATTACHED; bios_5_scratch &= ~RADEON_LCD1_ON; bios_5_scratch &= ~RADEON_ACC_REQ_LCD1; @@ -3151,12 +3152,12 @@ radeon_combios_connected_scratch_regs(struct drm_connector *connector, if ((radeon_encoder->devices & ATOM_DEVICE_CRT1_SUPPORT) && (radeon_connector->devices & ATOM_DEVICE_CRT1_SUPPORT)) { if (connected) { - DRM_DEBUG("CRT1 connected\n"); + DRM_DEBUG_KMS("CRT1 connected\n"); bios_4_scratch |= RADEON_CRT1_ATTACHED_COLOR; bios_5_scratch |= RADEON_CRT1_ON; bios_5_scratch |= RADEON_ACC_REQ_CRT1; } else { - DRM_DEBUG("CRT1 disconnected\n"); + DRM_DEBUG_KMS("CRT1 disconnected\n"); bios_4_scratch &= ~RADEON_CRT1_ATTACHED_MASK; bios_5_scratch &= ~RADEON_CRT1_ON; bios_5_scratch &= ~RADEON_ACC_REQ_CRT1; @@ -3165,12 +3166,12 @@ radeon_combios_connected_scratch_regs(struct drm_connector *connector, if ((radeon_encoder->devices & ATOM_DEVICE_CRT2_SUPPORT) && (radeon_connector->devices & ATOM_DEVICE_CRT2_SUPPORT)) { if (connected) { - DRM_DEBUG("CRT2 connected\n"); + DRM_DEBUG_KMS("CRT2 connected\n"); bios_4_scratch |= RADEON_CRT2_ATTACHED_COLOR; bios_5_scratch |= RADEON_CRT2_ON; bios_5_scratch |= RADEON_ACC_REQ_CRT2; } else { - DRM_DEBUG("CRT2 disconnected\n"); + DRM_DEBUG_KMS("CRT2 disconnected\n"); bios_4_scratch &= ~RADEON_CRT2_ATTACHED_MASK; bios_5_scratch &= ~RADEON_CRT2_ON; bios_5_scratch &= ~RADEON_ACC_REQ_CRT2; @@ -3179,12 +3180,12 @@ radeon_combios_connected_scratch_regs(struct drm_connector *connector, if ((radeon_encoder->devices & ATOM_DEVICE_DFP1_SUPPORT) && (radeon_connector->devices & ATOM_DEVICE_DFP1_SUPPORT)) { if (connected) { - DRM_DEBUG("DFP1 connected\n"); + DRM_DEBUG_KMS("DFP1 connected\n"); bios_4_scratch |= RADEON_DFP1_ATTACHED; bios_5_scratch |= RADEON_DFP1_ON; bios_5_scratch |= RADEON_ACC_REQ_DFP1; } else { - DRM_DEBUG("DFP1 disconnected\n"); + DRM_DEBUG_KMS("DFP1 disconnected\n"); bios_4_scratch &= ~RADEON_DFP1_ATTACHED; bios_5_scratch &= ~RADEON_DFP1_ON; bios_5_scratch &= ~RADEON_ACC_REQ_DFP1; @@ -3193,12 +3194,12 @@ radeon_combios_connected_scratch_regs(struct drm_connector *connector, if ((radeon_encoder->devices & ATOM_DEVICE_DFP2_SUPPORT) && (radeon_connector->devices & ATOM_DEVICE_DFP2_SUPPORT)) { if (connected) { - DRM_DEBUG("DFP2 connected\n"); + DRM_DEBUG_KMS("DFP2 connected\n"); bios_4_scratch |= RADEON_DFP2_ATTACHED; bios_5_scratch |= RADEON_DFP2_ON; bios_5_scratch |= RADEON_ACC_REQ_DFP2; } else { - DRM_DEBUG("DFP2 disconnected\n"); + DRM_DEBUG_KMS("DFP2 disconnected\n"); bios_4_scratch &= ~RADEON_DFP2_ATTACHED; bios_5_scratch &= ~RADEON_DFP2_ON; bios_5_scratch &= ~RADEON_ACC_REQ_DFP2; diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index adccbc2..2395c86 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -214,7 +214,7 @@ static struct drm_display_mode *radeon_fp_native_mode(struct drm_encoder *encode mode->type = DRM_MODE_TYPE_PREFERRED | DRM_MODE_TYPE_DRIVER; drm_mode_set_name(mode); - DRM_DEBUG("Adding native panel mode %s\n", mode->name); + DRM_DEBUG_KMS("Adding native panel mode %s\n", mode->name); } else if (native_mode->hdisplay != 0 && native_mode->vdisplay != 0) { /* mac laptops without an edid */ @@ -226,7 +226,7 @@ static struct drm_display_mode *radeon_fp_native_mode(struct drm_encoder *encode */ mode = drm_cvt_mode(dev, native_mode->hdisplay, native_mode->vdisplay, 60, true, false, false); mode->type = DRM_MODE_TYPE_PREFERRED | DRM_MODE_TYPE_DRIVER; - DRM_DEBUG("Adding cvt approximation of native panel mode %s\n", mode->name); + DRM_DEBUG_KMS("Adding cvt approximation of native panel mode %s\n", mode->name); } return mode; } @@ -312,6 +312,20 @@ int radeon_connector_set_property(struct drm_connector *connector, struct drm_pr } } + if (property == rdev->mode_info.underscan_property) { + /* need to find digital encoder on connector */ + encoder = radeon_find_encoder(connector, DRM_MODE_ENCODER_TMDS); + if (!encoder) + return 0; + + radeon_encoder = to_radeon_encoder(encoder); + + if (radeon_encoder->underscan_type != val) { + radeon_encoder->underscan_type = val; + radeon_property_change_mode(&radeon_encoder->base); + } + } + if (property == rdev->mode_info.tv_std_property) { encoder = radeon_find_encoder(connector, DRM_MODE_ENCODER_TVDAC); if (!encoder) { @@ -522,7 +536,7 @@ static int radeon_lvds_set_property(struct drm_connector *connector, struct radeon_encoder *radeon_encoder; enum radeon_rmx_type rmx_type; - DRM_DEBUG("\n"); + DRM_DEBUG_KMS("\n"); if (property != dev->mode_config.scaling_mode_property) return 0; @@ -1082,6 +1096,8 @@ radeon_add_atom_connector(struct drm_device *dev, drm_connector_attach_property(&radeon_connector->base, rdev->mode_info.load_detect_property, 1); + /* no HPD on analog connectors */ + radeon_connector->hpd.hpd = RADEON_HPD_NONE; connector->polled = DRM_CONNECTOR_POLL_CONNECT; break; case DRM_MODE_CONNECTOR_DVIA: @@ -1096,6 +1112,8 @@ radeon_add_atom_connector(struct drm_device *dev, drm_connector_attach_property(&radeon_connector->base, rdev->mode_info.load_detect_property, 1); + /* no HPD on analog connectors */ + radeon_connector->hpd.hpd = RADEON_HPD_NONE; break; case DRM_MODE_CONNECTOR_DVII: case DRM_MODE_CONNECTOR_DVID: @@ -1116,6 +1134,10 @@ radeon_add_atom_connector(struct drm_device *dev, drm_connector_attach_property(&radeon_connector->base, rdev->mode_info.coherent_mode_property, 1); + if (ASIC_IS_AVIVO(rdev)) + drm_connector_attach_property(&radeon_connector->base, + rdev->mode_info.underscan_property, + UNDERSCAN_AUTO); if (connector_type == DRM_MODE_CONNECTOR_DVII) { radeon_connector->dac_load_detect = true; drm_connector_attach_property(&radeon_connector->base, @@ -1141,6 +1163,10 @@ radeon_add_atom_connector(struct drm_device *dev, drm_connector_attach_property(&radeon_connector->base, rdev->mode_info.coherent_mode_property, 1); + if (ASIC_IS_AVIVO(rdev)) + drm_connector_attach_property(&radeon_connector->base, + rdev->mode_info.underscan_property, + UNDERSCAN_AUTO); subpixel_order = SubPixelHorizontalRGB; break; case DRM_MODE_CONNECTOR_DisplayPort: @@ -1172,6 +1198,10 @@ radeon_add_atom_connector(struct drm_device *dev, drm_connector_attach_property(&radeon_connector->base, rdev->mode_info.coherent_mode_property, 1); + if (ASIC_IS_AVIVO(rdev)) + drm_connector_attach_property(&radeon_connector->base, + rdev->mode_info.underscan_property, + UNDERSCAN_AUTO); break; case DRM_MODE_CONNECTOR_SVIDEO: case DRM_MODE_CONNECTOR_Composite: @@ -1186,6 +1216,8 @@ radeon_add_atom_connector(struct drm_device *dev, drm_connector_attach_property(&radeon_connector->base, rdev->mode_info.tv_std_property, radeon_atombios_get_tv_info(rdev)); + /* no HPD on analog connectors */ + radeon_connector->hpd.hpd = RADEON_HPD_NONE; } break; case DRM_MODE_CONNECTOR_LVDS: @@ -1209,7 +1241,7 @@ radeon_add_atom_connector(struct drm_device *dev, break; } - if (hpd->hpd == RADEON_HPD_NONE) { + if (radeon_connector->hpd.hpd == RADEON_HPD_NONE) { if (i2c_bus->valid) connector->polled = DRM_CONNECTOR_POLL_CONNECT; } else @@ -1276,6 +1308,8 @@ radeon_add_legacy_connector(struct drm_device *dev, drm_connector_attach_property(&radeon_connector->base, rdev->mode_info.load_detect_property, 1); + /* no HPD on analog connectors */ + radeon_connector->hpd.hpd = RADEON_HPD_NONE; connector->polled = DRM_CONNECTOR_POLL_CONNECT; break; case DRM_MODE_CONNECTOR_DVIA: @@ -1290,6 +1324,8 @@ radeon_add_legacy_connector(struct drm_device *dev, drm_connector_attach_property(&radeon_connector->base, rdev->mode_info.load_detect_property, 1); + /* no HPD on analog connectors */ + radeon_connector->hpd.hpd = RADEON_HPD_NONE; break; case DRM_MODE_CONNECTOR_DVII: case DRM_MODE_CONNECTOR_DVID: @@ -1328,6 +1364,8 @@ radeon_add_legacy_connector(struct drm_device *dev, drm_connector_attach_property(&radeon_connector->base, rdev->mode_info.tv_std_property, radeon_combios_get_tv_info(rdev)); + /* no HPD on analog connectors */ + radeon_connector->hpd.hpd = RADEON_HPD_NONE; } break; case DRM_MODE_CONNECTOR_LVDS: @@ -1345,7 +1383,7 @@ radeon_add_legacy_connector(struct drm_device *dev, break; } - if (hpd->hpd == RADEON_HPD_NONE) { + if (radeon_connector->hpd.hpd == RADEON_HPD_NONE) { if (i2c_bus->valid) connector->polled = DRM_CONNECTOR_POLL_CONNECT; } else diff --git a/drivers/gpu/drm/radeon/radeon_cp.c b/drivers/gpu/drm/radeon/radeon_cp.c index 2f042a3..eb6b9ee 100644 --- a/drivers/gpu/drm/radeon/radeon_cp.c +++ b/drivers/gpu/drm/radeon/radeon_cp.c @@ -2120,8 +2120,8 @@ int radeon_driver_load(struct drm_device *dev, unsigned long flags) else dev_priv->flags |= RADEON_IS_PCI; - ret = drm_addmap(dev, drm_get_resource_start(dev, 2), - drm_get_resource_len(dev, 2), _DRM_REGISTERS, + ret = drm_addmap(dev, pci_resource_start(dev->pdev, 2), + pci_resource_len(dev->pdev, 2), _DRM_REGISTERS, _DRM_READ_ONLY | _DRM_DRIVER, &dev_priv->mmio); if (ret != 0) return ret; @@ -2194,9 +2194,9 @@ int radeon_driver_firstopen(struct drm_device *dev) dev_priv->gart_info.table_size = RADEON_PCIGART_TABLE_SIZE; - dev_priv->fb_aper_offset = drm_get_resource_start(dev, 0); + dev_priv->fb_aper_offset = pci_resource_start(dev->pdev, 0); ret = drm_addmap(dev, dev_priv->fb_aper_offset, - drm_get_resource_len(dev, 0), _DRM_FRAME_BUFFER, + pci_resource_len(dev->pdev, 0), _DRM_FRAME_BUFFER, _DRM_WRITE_COMBINING, &map); if (ret != 0) return ret; diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index dd279da..a64811a 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -415,6 +415,22 @@ static uint32_t cail_reg_read(struct card_info *info, uint32_t reg) return r; } +static void cail_ioreg_write(struct card_info *info, uint32_t reg, uint32_t val) +{ + struct radeon_device *rdev = info->dev->dev_private; + + WREG32_IO(reg*4, val); +} + +static uint32_t cail_ioreg_read(struct card_info *info, uint32_t reg) +{ + struct radeon_device *rdev = info->dev->dev_private; + uint32_t r; + + r = RREG32_IO(reg*4); + return r; +} + int radeon_atombios_init(struct radeon_device *rdev) { struct card_info *atom_card_info = @@ -427,6 +443,15 @@ int radeon_atombios_init(struct radeon_device *rdev) atom_card_info->dev = rdev->ddev; atom_card_info->reg_read = cail_reg_read; atom_card_info->reg_write = cail_reg_write; + /* needed for iio ops */ + if (rdev->rio_mem) { + atom_card_info->ioreg_read = cail_ioreg_read; + atom_card_info->ioreg_write = cail_ioreg_write; + } else { + DRM_ERROR("Unable to find PCI I/O BAR; using MMIO for ATOM IIO\n"); + atom_card_info->ioreg_read = cail_reg_read; + atom_card_info->ioreg_write = cail_reg_write; + } atom_card_info->mc_read = cail_mc_read; atom_card_info->mc_write = cail_mc_write; atom_card_info->pll_read = cail_pll_read; @@ -573,7 +598,7 @@ int radeon_device_init(struct radeon_device *rdev, struct pci_dev *pdev, uint32_t flags) { - int r; + int r, i; int dma_bits; rdev->shutdown = false; @@ -650,8 +675,8 @@ int radeon_device_init(struct radeon_device *rdev, /* Registers mapping */ /* TODO: block userspace mapping of io register */ - rdev->rmmio_base = drm_get_resource_start(rdev->ddev, 2); - rdev->rmmio_size = drm_get_resource_len(rdev->ddev, 2); + rdev->rmmio_base = pci_resource_start(rdev->pdev, 2); + rdev->rmmio_size = pci_resource_len(rdev->pdev, 2); rdev->rmmio = ioremap(rdev->rmmio_base, rdev->rmmio_size); if (rdev->rmmio == NULL) { return -ENOMEM; @@ -659,6 +684,17 @@ int radeon_device_init(struct radeon_device *rdev, DRM_INFO("register mmio base: 0x%08X\n", (uint32_t)rdev->rmmio_base); DRM_INFO("register mmio size: %u\n", (unsigned)rdev->rmmio_size); + /* io port mapping */ + for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { + if (pci_resource_flags(rdev->pdev, i) & IORESOURCE_IO) { + rdev->rio_mem_size = pci_resource_len(rdev->pdev, i); + rdev->rio_mem = pci_iomap(rdev->pdev, i, rdev->rio_mem_size); + break; + } + } + if (rdev->rio_mem == NULL) + DRM_ERROR("Unable to find PCI I/O BAR\n"); + /* if we have > 1 VGA cards, then disable the radeon VGA resources */ /* this will fail for cards that aren't VGA class devices, just * ignore it */ @@ -701,6 +737,9 @@ void radeon_device_fini(struct radeon_device *rdev) destroy_workqueue(rdev->wq); vga_switcheroo_unregister_client(rdev->pdev); vga_client_register(rdev->pdev, NULL, NULL, NULL); + if (rdev->rio_mem) + pci_iounmap(rdev->pdev, rdev->rio_mem); + rdev->rio_mem = NULL; iounmap(rdev->rmmio); rdev->rmmio = NULL; } diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index 8154cdf..74dac96 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -42,7 +42,7 @@ static void avivo_crtc_load_lut(struct drm_crtc *crtc) struct radeon_device *rdev = dev->dev_private; int i; - DRM_DEBUG("%d\n", radeon_crtc->crtc_id); + DRM_DEBUG_KMS("%d\n", radeon_crtc->crtc_id); WREG32(AVIVO_DC_LUTA_CONTROL + radeon_crtc->crtc_offset, 0); WREG32(AVIVO_DC_LUTA_BLACK_OFFSET_BLUE + radeon_crtc->crtc_offset, 0); @@ -75,7 +75,7 @@ static void evergreen_crtc_load_lut(struct drm_crtc *crtc) struct radeon_device *rdev = dev->dev_private; int i; - DRM_DEBUG("%d\n", radeon_crtc->crtc_id); + DRM_DEBUG_KMS("%d\n", radeon_crtc->crtc_id); WREG32(EVERGREEN_DC_LUT_CONTROL + radeon_crtc->crtc_offset, 0); WREG32(EVERGREEN_DC_LUT_BLACK_OFFSET_BLUE + radeon_crtc->crtc_offset, 0); @@ -469,7 +469,7 @@ static void radeon_compute_pll_legacy(struct radeon_pll *pll, uint32_t post_div; u32 pll_out_min, pll_out_max; - DRM_DEBUG("PLL freq %llu %u %u\n", freq, pll->min_ref_div, pll->max_ref_div); + DRM_DEBUG_KMS("PLL freq %llu %u %u\n", freq, pll->min_ref_div, pll->max_ref_div); freq = freq * 1000; if (pll->flags & RADEON_PLL_IS_LCD) { @@ -558,15 +558,17 @@ static void radeon_compute_pll_legacy(struct radeon_pll *pll, current_freq = radeon_div(tmp, ref_div * post_div); if (pll->flags & RADEON_PLL_PREFER_CLOSEST_LOWER) { - error = freq - current_freq; - error = error < 0 ? 0xffffffff : error; + if (freq < current_freq) + error = 0xffffffff; + else + error = freq - current_freq; } else error = abs(current_freq - freq); vco_diff = abs(vco - best_vco); if ((best_vco == 0 && error < best_error) || (best_vco != 0 && - (error < best_error - 100 || + ((best_error > 100 && error < best_error - 100) || (abs(error - best_error) < 100 && vco_diff < best_vco_diff)))) { best_post_div = post_div; best_ref_div = ref_div; @@ -803,7 +805,7 @@ done: *ref_div_p = ref_div; *post_div_p = post_div; - DRM_DEBUG("%u %d.%d, %d, %d\n", *dot_clock_p, *fb_div_p, *frac_fb_div_p, *ref_div_p, *post_div_p); + DRM_DEBUG_KMS("%u %d.%d, %d, %d\n", *dot_clock_p, *fb_div_p, *frac_fb_div_p, *ref_div_p, *post_div_p); } void radeon_compute_pll(struct radeon_pll *pll, @@ -919,6 +921,12 @@ static struct drm_prop_enum_list radeon_tv_std_enum_list[] = { TV_STD_SECAM, "secam" }, }; +static struct drm_prop_enum_list radeon_underscan_enum_list[] = +{ { UNDERSCAN_OFF, "off" }, + { UNDERSCAN_ON, "on" }, + { UNDERSCAN_AUTO, "auto" }, +}; + static int radeon_modeset_create_props(struct radeon_device *rdev) { int i, sz; @@ -972,6 +980,18 @@ static int radeon_modeset_create_props(struct radeon_device *rdev) radeon_tv_std_enum_list[i].name); } + sz = ARRAY_SIZE(radeon_underscan_enum_list); + rdev->mode_info.underscan_property = + drm_property_create(rdev->ddev, + DRM_MODE_PROP_ENUM, + "underscan", sz); + for (i = 0; i < sz; i++) { + drm_property_add_enum(rdev->mode_info.underscan_property, + i, + radeon_underscan_enum_list[i].type, + radeon_underscan_enum_list[i].name); + } + return 0; } @@ -1067,15 +1087,26 @@ bool radeon_crtc_scaling_mode_fixup(struct drm_crtc *crtc, struct drm_display_mode *adjusted_mode) { struct drm_device *dev = crtc->dev; + struct radeon_device *rdev = dev->dev_private; struct drm_encoder *encoder; struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); struct radeon_encoder *radeon_encoder; + struct drm_connector *connector; + struct radeon_connector *radeon_connector; bool first = true; + u32 src_v = 1, dst_v = 1; + u32 src_h = 1, dst_h = 1; + + radeon_crtc->h_border = 0; + radeon_crtc->v_border = 0; list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { - radeon_encoder = to_radeon_encoder(encoder); if (encoder->crtc != crtc) continue; + radeon_encoder = to_radeon_encoder(encoder); + connector = radeon_get_connector_for_encoder(encoder); + radeon_connector = to_radeon_connector(connector); + if (first) { /* set scaling */ if (radeon_encoder->rmx_type == RMX_OFF) @@ -1085,31 +1116,49 @@ bool radeon_crtc_scaling_mode_fixup(struct drm_crtc *crtc, radeon_crtc->rmx_type = radeon_encoder->rmx_type; else radeon_crtc->rmx_type = RMX_OFF; + src_v = crtc->mode.vdisplay; + dst_v = radeon_crtc->native_mode.vdisplay; + src_h = crtc->mode.hdisplay; + dst_h = radeon_crtc->native_mode.vdisplay; /* copy native mode */ memcpy(&radeon_crtc->native_mode, &radeon_encoder->native_mode, sizeof(struct drm_display_mode)); + + /* fix up for overscan on hdmi */ + if (ASIC_IS_AVIVO(rdev) && + ((radeon_encoder->underscan_type == UNDERSCAN_ON) || + ((radeon_encoder->underscan_type == UNDERSCAN_AUTO) && + drm_detect_hdmi_monitor(radeon_connector->edid)))) { + radeon_crtc->h_border = (mode->hdisplay >> 5) + 16; + radeon_crtc->v_border = (mode->vdisplay >> 5) + 16; + radeon_crtc->rmx_type = RMX_FULL; + src_v = crtc->mode.vdisplay; + dst_v = crtc->mode.vdisplay - (radeon_crtc->v_border * 2); + src_h = crtc->mode.hdisplay; + dst_h = crtc->mode.hdisplay - (radeon_crtc->h_border * 2); + } first = false; } else { if (radeon_crtc->rmx_type != radeon_encoder->rmx_type) { /* WARNING: Right now this can't happen but * in the future we need to check that scaling - * are consistent accross different encoder + * are consistent across different encoder * (ie all encoder can work with the same * scaling). */ - DRM_ERROR("Scaling not consistent accross encoder.\n"); + DRM_ERROR("Scaling not consistent across encoder.\n"); return false; } } } if (radeon_crtc->rmx_type != RMX_OFF) { fixed20_12 a, b; - a.full = dfixed_const(crtc->mode.vdisplay); - b.full = dfixed_const(radeon_crtc->native_mode.hdisplay); + a.full = dfixed_const(src_v); + b.full = dfixed_const(dst_v); radeon_crtc->vsc.full = dfixed_div(a, b); - a.full = dfixed_const(crtc->mode.hdisplay); - b.full = dfixed_const(radeon_crtc->native_mode.vdisplay); + a.full = dfixed_const(src_h); + b.full = dfixed_const(dst_h); radeon_crtc->hsc.full = dfixed_div(a, b); } else { radeon_crtc->vsc.full = dfixed_const(1); diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c index e166fe4..795403b 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.c +++ b/drivers/gpu/drm/radeon/radeon_drv.c @@ -46,9 +46,10 @@ * - 2.3.0 - add MSPOS + 3D texture + r500 VAP regs * - 2.4.0 - add crtc id query * - 2.5.0 - add get accel 2 to work around ddx breakage for evergreen + * - 2.6.0 - add tiling config query (r6xx+), add initial HiZ support (r300->r500) */ #define KMS_DRIVER_MAJOR 2 -#define KMS_DRIVER_MINOR 5 +#define KMS_DRIVER_MINOR 6 #define KMS_DRIVER_PATCHLEVEL 0 int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags); int radeon_driver_unload_kms(struct drm_device *dev); @@ -238,7 +239,7 @@ static struct drm_driver kms_driver; static int __devinit radeon_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { - return drm_get_dev(pdev, ent, &kms_driver); + return drm_get_pci_dev(pdev, ent, &kms_driver); } static void diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c index e0b30b2..263c809 100644 --- a/drivers/gpu/drm/radeon/radeon_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_encoders.c @@ -205,14 +205,14 @@ void radeon_encoder_set_active_device(struct drm_encoder *encoder) if (connector->encoder == encoder) { struct radeon_connector *radeon_connector = to_radeon_connector(connector); radeon_encoder->active_device = radeon_encoder->devices & radeon_connector->devices; - DRM_DEBUG("setting active device to %08x from %08x %08x for encoder %d\n", + DRM_DEBUG_KMS("setting active device to %08x from %08x %08x for encoder %d\n", radeon_encoder->active_device, radeon_encoder->devices, radeon_connector->devices, encoder->encoder_type); } } } -static struct drm_connector * +struct drm_connector * radeon_get_connector_for_encoder(struct drm_encoder *encoder) { struct drm_device *dev = encoder->dev; @@ -1021,7 +1021,7 @@ radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode) memset(&args, 0, sizeof(args)); - DRM_DEBUG("encoder dpms %d to mode %d, devices %08x, active_devices %08x\n", + DRM_DEBUG_KMS("encoder dpms %d to mode %d, devices %08x, active_devices %08x\n", radeon_encoder->encoder_id, mode, radeon_encoder->devices, radeon_encoder->active_device); switch (radeon_encoder->encoder_id) { @@ -1484,7 +1484,7 @@ radeon_atom_dac_detect(struct drm_encoder *encoder, struct drm_connector *connec uint32_t bios_0_scratch; if (!atombios_dac_load_detect(encoder, connector)) { - DRM_DEBUG("detect returned false \n"); + DRM_DEBUG_KMS("detect returned false \n"); return connector_status_unknown; } @@ -1493,7 +1493,7 @@ radeon_atom_dac_detect(struct drm_encoder *encoder, struct drm_connector *connec else bios_0_scratch = RREG32(RADEON_BIOS_0_SCRATCH); - DRM_DEBUG("Bios 0 scratch %x %08x\n", bios_0_scratch, radeon_encoder->devices); + DRM_DEBUG_KMS("Bios 0 scratch %x %08x\n", bios_0_scratch, radeon_encoder->devices); if (radeon_connector->devices & ATOM_DEVICE_CRT1_SUPPORT) { if (bios_0_scratch & ATOM_S0_CRT1_MASK) return connector_status_connected; @@ -1694,6 +1694,7 @@ radeon_add_atom_encoder(struct drm_device *dev, uint32_t encoder_id, uint32_t su radeon_encoder->encoder_id = encoder_id; radeon_encoder->devices = supported_device; radeon_encoder->rmx_type = RMX_OFF; + radeon_encoder->underscan_type = UNDERSCAN_OFF; switch (radeon_encoder->encoder_id) { case ENCODER_OBJECT_ID_INTERNAL_LVDS: @@ -1707,6 +1708,8 @@ radeon_add_atom_encoder(struct drm_device *dev, uint32_t encoder_id, uint32_t su } else { drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_TMDS); radeon_encoder->enc_priv = radeon_atombios_set_dig_info(radeon_encoder); + if (ASIC_IS_AVIVO(rdev)) + radeon_encoder->underscan_type = UNDERSCAN_AUTO; } drm_encoder_helper_add(encoder, &radeon_atom_dig_helper_funcs); break; @@ -1736,6 +1739,8 @@ radeon_add_atom_encoder(struct drm_device *dev, uint32_t encoder_id, uint32_t su } else { drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_TMDS); radeon_encoder->enc_priv = radeon_atombios_set_dig_info(radeon_encoder); + if (ASIC_IS_AVIVO(rdev)) + radeon_encoder->underscan_type = UNDERSCAN_AUTO; } drm_encoder_helper_add(encoder, &radeon_atom_dig_helper_funcs); break; diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c index ab389f8..ddcd3b1 100644 --- a/drivers/gpu/drm/radeon/radeon_kms.c +++ b/drivers/gpu/drm/radeon/radeon_kms.c @@ -49,7 +49,7 @@ int radeon_driver_unload_kms(struct drm_device *dev) int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags) { struct radeon_device *rdev; - int r; + int r, acpi_status; rdev = kzalloc(sizeof(struct radeon_device), GFP_KERNEL); if (rdev == NULL) { @@ -77,6 +77,12 @@ int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags) dev_err(&dev->pdev->dev, "Fatal error during GPU init\n"); goto out; } + + /* Call ACPI methods */ + acpi_status = radeon_acpi_init(rdev); + if (acpi_status) + dev_dbg(&dev->pdev->dev, "Error during ACPI methods call\n"); + /* Again modeset_init should fail only on fatal error * otherwise it should provide enough functionalities * for shadowfb to run @@ -135,15 +141,36 @@ int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) } } if (!found) { - DRM_DEBUG("unknown crtc id %d\n", value); + DRM_DEBUG_KMS("unknown crtc id %d\n", value); return -EINVAL; } break; case RADEON_INFO_ACCEL_WORKING2: value = rdev->accel_working; break; + case RADEON_INFO_TILING_CONFIG: + if (rdev->family >= CHIP_CEDAR) + value = rdev->config.evergreen.tile_config; + else if (rdev->family >= CHIP_RV770) + value = rdev->config.rv770.tile_config; + else if (rdev->family >= CHIP_R600) + value = rdev->config.r600.tile_config; + else { + DRM_DEBUG_KMS("tiling config is r6xx+ only!\n"); + return -EINVAL; + } + case RADEON_INFO_WANT_HYPERZ: + mutex_lock(&dev->struct_mutex); + if (rdev->hyperz_filp) + value = 0; + else { + rdev->hyperz_filp = filp; + value = 1; + } + mutex_unlock(&dev->struct_mutex); + break; default: - DRM_DEBUG("Invalid request %d\n", info->request); + DRM_DEBUG_KMS("Invalid request %d\n", info->request); return -EINVAL; } if (DRM_COPY_TO_USER(value_ptr, &value, sizeof(uint32_t))) { @@ -181,9 +208,11 @@ void radeon_driver_postclose_kms(struct drm_device *dev, void radeon_driver_preclose_kms(struct drm_device *dev, struct drm_file *file_priv) { + struct radeon_device *rdev = dev->dev_private; + if (rdev->hyperz_filp == file_priv) + rdev->hyperz_filp = NULL; } - /* * VBlank related functions. */ diff --git a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c index e1e5255..989df51 100644 --- a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c +++ b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c @@ -362,10 +362,10 @@ int radeon_crtc_set_base(struct drm_crtc *crtc, int x, int y, uint32_t gen_cntl_reg, gen_cntl_val; int r; - DRM_DEBUG("\n"); + DRM_DEBUG_KMS("\n"); /* no fb bound */ if (!crtc->fb) { - DRM_DEBUG("No FB bound\n"); + DRM_DEBUG_KMS("No FB bound\n"); return 0; } @@ -528,7 +528,7 @@ static bool radeon_set_crtc_timing(struct drm_crtc *crtc, struct drm_display_mod uint32_t crtc_v_sync_strt_wid; bool is_tv = false; - DRM_DEBUG("\n"); + DRM_DEBUG_KMS("\n"); list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { if (encoder->crtc == crtc) { struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); @@ -757,7 +757,7 @@ static void radeon_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) } } - DRM_DEBUG("\n"); + DRM_DEBUG_KMS("\n"); if (!use_bios_divs) { radeon_compute_pll(pll, mode->clock, @@ -772,7 +772,7 @@ static void radeon_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) if (!post_div->divider) post_div = &post_divs[0]; - DRM_DEBUG("dc=%u, fd=%d, rd=%d, pd=%d\n", + DRM_DEBUG_KMS("dc=%u, fd=%d, rd=%d, pd=%d\n", (unsigned)freq, feedback_div, reference_div, @@ -841,12 +841,12 @@ static void radeon_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) | RADEON_P2PLL_SLEEP | RADEON_P2PLL_ATOMIC_UPDATE_EN)); - DRM_DEBUG("Wrote2: 0x%08x 0x%08x 0x%08x (0x%08x)\n", + DRM_DEBUG_KMS("Wrote2: 0x%08x 0x%08x 0x%08x (0x%08x)\n", (unsigned)pll_ref_div, (unsigned)pll_fb_post_div, (unsigned)htotal_cntl, RREG32_PLL(RADEON_P2PLL_CNTL)); - DRM_DEBUG("Wrote2: rd=%u, fd=%u, pd=%u\n", + DRM_DEBUG_KMS("Wrote2: rd=%u, fd=%u, pd=%u\n", (unsigned)pll_ref_div & RADEON_P2PLL_REF_DIV_MASK, (unsigned)pll_fb_post_div & RADEON_P2PLL_FB0_DIV_MASK, (unsigned)((pll_fb_post_div & @@ -947,12 +947,12 @@ static void radeon_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode) | RADEON_PPLL_ATOMIC_UPDATE_EN | RADEON_PPLL_VGA_ATOMIC_UPDATE_EN)); - DRM_DEBUG("Wrote: 0x%08x 0x%08x 0x%08x (0x%08x)\n", + DRM_DEBUG_KMS("Wrote: 0x%08x 0x%08x 0x%08x (0x%08x)\n", pll_ref_div, pll_fb_post_div, (unsigned)htotal_cntl, RREG32_PLL(RADEON_PPLL_CNTL)); - DRM_DEBUG("Wrote: rd=%d, fd=%d, pd=%d\n", + DRM_DEBUG_KMS("Wrote: rd=%d, fd=%d, pd=%d\n", pll_ref_div & RADEON_PPLL_REF_DIV_MASK, pll_fb_post_div & RADEON_PPLL_FB3_DIV_MASK, (pll_fb_post_div & RADEON_PPLL_POST3_DIV_MASK) >> 16); diff --git a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c index 5688a0c..b8149cb 100644 --- a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c @@ -47,7 +47,7 @@ static void radeon_legacy_lvds_dpms(struct drm_encoder *encoder, int mode) uint32_t lvds_gen_cntl, lvds_pll_cntl, pixclks_cntl, disp_pwr_man; int panel_pwr_delay = 2000; bool is_mac = false; - DRM_DEBUG("\n"); + DRM_DEBUG_KMS("\n"); if (radeon_encoder->enc_priv) { if (rdev->is_atom_bios) { @@ -151,7 +151,7 @@ static void radeon_legacy_lvds_mode_set(struct drm_encoder *encoder, struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); uint32_t lvds_pll_cntl, lvds_gen_cntl, lvds_ss_gen_cntl; - DRM_DEBUG("\n"); + DRM_DEBUG_KMS("\n"); lvds_pll_cntl = RREG32(RADEON_LVDS_PLL_CNTL); lvds_pll_cntl &= ~RADEON_LVDS_PLL_EN; @@ -167,7 +167,7 @@ static void radeon_legacy_lvds_mode_set(struct drm_encoder *encoder, } else { struct radeon_encoder_lvds *lvds = (struct radeon_encoder_lvds *)radeon_encoder->enc_priv; if (lvds) { - DRM_DEBUG("bios LVDS_GEN_CNTL: 0x%x\n", lvds->lvds_gen_cntl); + DRM_DEBUG_KMS("bios LVDS_GEN_CNTL: 0x%x\n", lvds->lvds_gen_cntl); lvds_gen_cntl = lvds->lvds_gen_cntl; lvds_ss_gen_cntl &= ~((0xf << RADEON_LVDS_PWRSEQ_DELAY1_SHIFT) | (0xf << RADEON_LVDS_PWRSEQ_DELAY2_SHIFT)); @@ -250,7 +250,7 @@ static void radeon_legacy_primary_dac_dpms(struct drm_encoder *encoder, int mode uint32_t dac_cntl = RREG32(RADEON_DAC_CNTL); uint32_t dac_macro_cntl = RREG32(RADEON_DAC_MACRO_CNTL); - DRM_DEBUG("\n"); + DRM_DEBUG_KMS("\n"); switch (mode) { case DRM_MODE_DPMS_ON: @@ -315,7 +315,7 @@ static void radeon_legacy_primary_dac_mode_set(struct drm_encoder *encoder, struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); uint32_t disp_output_cntl, dac_cntl, dac2_cntl, dac_macro_cntl; - DRM_DEBUG("\n"); + DRM_DEBUG_KMS("\n"); if (radeon_crtc->crtc_id == 0) { if (rdev->family == CHIP_R200 || ASIC_IS_R300(rdev)) { @@ -446,7 +446,7 @@ static void radeon_legacy_tmds_int_dpms(struct drm_encoder *encoder, int mode) struct drm_device *dev = encoder->dev; struct radeon_device *rdev = dev->dev_private; uint32_t fp_gen_cntl = RREG32(RADEON_FP_GEN_CNTL); - DRM_DEBUG("\n"); + DRM_DEBUG_KMS("\n"); switch (mode) { case DRM_MODE_DPMS_ON: @@ -502,7 +502,7 @@ static void radeon_legacy_tmds_int_mode_set(struct drm_encoder *encoder, uint32_t tmp, tmds_pll_cntl, tmds_transmitter_cntl, fp_gen_cntl; int i; - DRM_DEBUG("\n"); + DRM_DEBUG_KMS("\n"); tmp = tmds_pll_cntl = RREG32(RADEON_TMDS_PLL_CNTL); tmp &= 0xfffff; @@ -610,7 +610,7 @@ static void radeon_legacy_tmds_ext_dpms(struct drm_encoder *encoder, int mode) struct drm_device *dev = encoder->dev; struct radeon_device *rdev = dev->dev_private; uint32_t fp2_gen_cntl = RREG32(RADEON_FP2_GEN_CNTL); - DRM_DEBUG("\n"); + DRM_DEBUG_KMS("\n"); switch (mode) { case DRM_MODE_DPMS_ON: @@ -666,7 +666,7 @@ static void radeon_legacy_tmds_ext_mode_set(struct drm_encoder *encoder, struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); uint32_t fp2_gen_cntl; - DRM_DEBUG("\n"); + DRM_DEBUG_KMS("\n"); if (rdev->is_atom_bios) { radeon_encoder->pixel_clock = adjusted_mode->clock; @@ -760,7 +760,7 @@ static void radeon_legacy_tv_dac_dpms(struct drm_encoder *encoder, int mode) uint32_t fp2_gen_cntl = 0, crtc2_gen_cntl = 0, tv_dac_cntl = 0; uint32_t tv_master_cntl = 0; bool is_tv; - DRM_DEBUG("\n"); + DRM_DEBUG_KMS("\n"); is_tv = radeon_encoder->active_device & ATOM_DEVICE_TV_SUPPORT ? true : false; @@ -878,7 +878,7 @@ static void radeon_legacy_tv_dac_mode_set(struct drm_encoder *encoder, uint32_t disp_hw_debug = 0, fp2_gen_cntl = 0, disp_tv_out_cntl = 0; bool is_tv = false; - DRM_DEBUG("\n"); + DRM_DEBUG_KMS("\n"); is_tv = radeon_encoder->active_device & ATOM_DEVICE_TV_SUPPORT ? true : false; @@ -1075,10 +1075,10 @@ static bool r300_legacy_tv_detect(struct drm_encoder *encoder, tmp = RREG32(RADEON_TV_DAC_CNTL); if ((tmp & RADEON_TV_DAC_GDACDET) != 0) { found = true; - DRM_DEBUG("S-video TV connection detected\n"); + DRM_DEBUG_KMS("S-video TV connection detected\n"); } else if ((tmp & RADEON_TV_DAC_BDACDET) != 0) { found = true; - DRM_DEBUG("Composite TV connection detected\n"); + DRM_DEBUG_KMS("Composite TV connection detected\n"); } WREG32(RADEON_TV_DAC_CNTL, tv_dac_cntl); @@ -1141,10 +1141,10 @@ static bool radeon_legacy_tv_detect(struct drm_encoder *encoder, tmp = RREG32(RADEON_TV_DAC_CNTL); if (tmp & RADEON_TV_DAC_GDACDET) { found = true; - DRM_DEBUG("S-video TV connection detected\n"); + DRM_DEBUG_KMS("S-video TV connection detected\n"); } else if ((tmp & RADEON_TV_DAC_BDACDET) != 0) { found = true; - DRM_DEBUG("Composite TV connection detected\n"); + DRM_DEBUG_KMS("Composite TV connection detected\n"); } WREG32(RADEON_TV_PRE_DAC_MUX_CNTL, tv_pre_dac_mux_cntl); diff --git a/drivers/gpu/drm/radeon/radeon_legacy_tv.c b/drivers/gpu/drm/radeon/radeon_legacy_tv.c index 0320403..c7b6cb4 100644 --- a/drivers/gpu/drm/radeon/radeon_legacy_tv.c +++ b/drivers/gpu/drm/radeon/radeon_legacy_tv.c @@ -496,7 +496,7 @@ static bool radeon_legacy_tv_init_restarts(struct drm_encoder *encoder) restart -= v_offset + h_offset; - DRM_DEBUG("compute_restarts: def = %u h = %d v = %d, p1 = %04x, p2 = %04x, restart = %d\n", + DRM_DEBUG_KMS("compute_restarts: def = %u h = %d v = %d, p1 = %04x, p2 = %04x, restart = %d\n", const_ptr->def_restart, tv_dac->h_pos, tv_dac->v_pos, p1, p2, restart); tv_dac->tv.hrestart = restart % h_total; @@ -505,7 +505,7 @@ static bool radeon_legacy_tv_init_restarts(struct drm_encoder *encoder) restart /= v_total; tv_dac->tv.frestart = restart % f_total; - DRM_DEBUG("compute_restart: F/H/V=%u,%u,%u\n", + DRM_DEBUG_KMS("compute_restart: F/H/V=%u,%u,%u\n", (unsigned)tv_dac->tv.frestart, (unsigned)tv_dac->tv.vrestart, (unsigned)tv_dac->tv.hrestart); @@ -523,7 +523,7 @@ static bool radeon_legacy_tv_init_restarts(struct drm_encoder *encoder) tv_dac->tv.timing_cntl = (tv_dac->tv.timing_cntl & ~RADEON_H_INC_MASK) | ((u32)h_inc << RADEON_H_INC_SHIFT); - DRM_DEBUG("compute_restart: h_size = %d h_inc = %d\n", tv_dac->h_size, h_inc); + DRM_DEBUG_KMS("compute_restart: h_size = %d h_inc = %d\n", tv_dac->h_size, h_inc); return h_changed; } diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index 95696aa..71aea40 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -66,6 +66,12 @@ enum radeon_tv_std { TV_STD_PAL_N, }; +enum radeon_underscan_type { + UNDERSCAN_OFF, + UNDERSCAN_ON, + UNDERSCAN_AUTO, +}; + enum radeon_hpd_id { RADEON_HPD_1 = 0, RADEON_HPD_2, @@ -226,10 +232,12 @@ struct radeon_mode_info { struct drm_property *coherent_mode_property; /* DAC enable load detect */ struct drm_property *load_detect_property; - /* TV standard load detect */ + /* TV standard */ struct drm_property *tv_std_property; /* legacy TMDS PLL detect */ struct drm_property *tmds_pll_property; + /* underscan */ + struct drm_property *underscan_property; /* hardcoded DFP edid from BIOS */ struct edid *bios_hardcoded_edid; @@ -266,6 +274,8 @@ struct radeon_crtc { uint32_t legacy_display_base_addr; uint32_t legacy_cursor_offset; enum radeon_rmx_type rmx_type; + u8 h_border; + u8 v_border; fixed20_12 vsc; fixed20_12 hsc; struct drm_display_mode native_mode; @@ -354,6 +364,7 @@ struct radeon_encoder { uint32_t flags; uint32_t pixel_clock; enum radeon_rmx_type rmx_type; + enum radeon_underscan_type underscan_type; struct drm_display_mode native_mode; void *enc_priv; int audio_polling_active; @@ -392,7 +403,7 @@ struct radeon_connector { uint32_t connector_id; uint32_t devices; struct radeon_i2c_chan *ddc_bus; - /* some systems have a an hdmi and vga port with a shared ddc line */ + /* some systems have an hdmi and vga port with a shared ddc line */ bool shared_ddc; bool use_digital; /* we need to mind the EDID between detect @@ -414,6 +425,9 @@ radeon_combios_get_tv_info(struct radeon_device *rdev); extern enum radeon_tv_std radeon_atombios_get_tv_info(struct radeon_device *rdev); +extern struct drm_connector * +radeon_get_connector_for_encoder(struct drm_encoder *encoder); + extern void radeon_connector_hotplug(struct drm_connector *connector); extern bool radeon_dp_needs_link_train(struct radeon_connector *radeon_connector); extern int radeon_dp_mode_valid_helper(struct radeon_connector *radeon_connector, diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c index d5b9373..0afd1e6 100644 --- a/drivers/gpu/drm/radeon/radeon_object.c +++ b/drivers/gpu/drm/radeon/radeon_object.c @@ -110,6 +110,7 @@ int radeon_bo_create(struct radeon_device *rdev, struct drm_gem_object *gobj, bo->surface_reg = -1; INIT_LIST_HEAD(&bo->list); +retry: radeon_ttm_placement_from_domain(bo, domain); /* Kernel allocation are uninterruptible */ mutex_lock(&rdev->vram_mutex); @@ -118,10 +119,15 @@ int radeon_bo_create(struct radeon_device *rdev, struct drm_gem_object *gobj, &radeon_ttm_bo_destroy); mutex_unlock(&rdev->vram_mutex); if (unlikely(r != 0)) { - if (r != -ERESTARTSYS) + if (r != -ERESTARTSYS) { + if (domain == RADEON_GEM_DOMAIN_VRAM) { + domain |= RADEON_GEM_DOMAIN_GTT; + goto retry; + } dev_err(rdev->dev, "object_init failed for (%lu, 0x%08X)\n", size, domain); + } return r; } *bo_ptr = bo; @@ -321,6 +327,7 @@ int radeon_bo_list_validate(struct list_head *head) { struct radeon_bo_list *lobj; struct radeon_bo *bo; + u32 domain; int r; list_for_each_entry(lobj, head, list) { @@ -333,17 +340,19 @@ int radeon_bo_list_validate(struct list_head *head) list_for_each_entry(lobj, head, list) { bo = lobj->bo; if (!bo->pin_count) { - if (lobj->wdomain) { - radeon_ttm_placement_from_domain(bo, - lobj->wdomain); - } else { - radeon_ttm_placement_from_domain(bo, - lobj->rdomain); - } + domain = lobj->wdomain ? lobj->wdomain : lobj->rdomain; + + retry: + radeon_ttm_placement_from_domain(bo, domain); r = ttm_bo_validate(&bo->tbo, &bo->placement, true, false, false); - if (unlikely(r)) + if (unlikely(r)) { + if (r != -ERESTARTSYS && domain == RADEON_GEM_DOMAIN_VRAM) { + domain |= RADEON_GEM_DOMAIN_GTT; + goto retry; + } return r; + } } lobj->gpu_offset = radeon_bo_gpu_offset(bo); lobj->tiling_flags = bo->tiling_flags; diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index 3fa6984..95f8b3a 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -27,6 +27,8 @@ #include <linux/acpi.h> #endif #include <linux/power_supply.h> +#include <linux/hwmon.h> +#include <linux/hwmon-sysfs.h> #define RADEON_IDLE_LOOP_MS 100 #define RADEON_RECLOCK_DELAY_MS 200 @@ -60,9 +62,9 @@ static int radeon_acpi_event(struct notifier_block *nb, if (strcmp(entry->device_class, ACPI_AC_CLASS) == 0) { if (power_supply_is_system_supplied() > 0) - DRM_DEBUG("pm: AC\n"); + DRM_DEBUG_DRIVER("pm: AC\n"); else - DRM_DEBUG("pm: DC\n"); + DRM_DEBUG_DRIVER("pm: DC\n"); if (rdev->pm.pm_method == PM_METHOD_PROFILE) { if (rdev->pm.profile == PM_PROFILE_AUTO) { @@ -196,7 +198,7 @@ static void radeon_set_power_state(struct radeon_device *rdev) radeon_set_engine_clock(rdev, sclk); radeon_pm_debug_check_in_vbl(rdev, true); rdev->pm.current_sclk = sclk; - DRM_DEBUG("Setting: e: %d\n", sclk); + DRM_DEBUG_DRIVER("Setting: e: %d\n", sclk); } /* set memory clock */ @@ -205,7 +207,7 @@ static void radeon_set_power_state(struct radeon_device *rdev) radeon_set_memory_clock(rdev, mclk); radeon_pm_debug_check_in_vbl(rdev, true); rdev->pm.current_mclk = mclk; - DRM_DEBUG("Setting: m: %d\n", mclk); + DRM_DEBUG_DRIVER("Setting: m: %d\n", mclk); } if (misc_after) @@ -217,7 +219,7 @@ static void radeon_set_power_state(struct radeon_device *rdev) rdev->pm.current_power_state_index = rdev->pm.requested_power_state_index; rdev->pm.current_clock_mode_index = rdev->pm.requested_clock_mode_index; } else - DRM_DEBUG("pm: GUI not idle!!!\n"); + DRM_DEBUG_DRIVER("pm: GUI not idle!!!\n"); } static void radeon_pm_set_clocks(struct radeon_device *rdev) @@ -292,27 +294,27 @@ static void radeon_pm_print_states(struct radeon_device *rdev) struct radeon_power_state *power_state; struct radeon_pm_clock_info *clock_info; - DRM_DEBUG("%d Power State(s)\n", rdev->pm.num_power_states); + DRM_DEBUG_DRIVER("%d Power State(s)\n", rdev->pm.num_power_states); for (i = 0; i < rdev->pm.num_power_states; i++) { power_state = &rdev->pm.power_state[i]; - DRM_DEBUG("State %d: %s\n", i, + DRM_DEBUG_DRIVER("State %d: %s\n", i, radeon_pm_state_type_name[power_state->type]); if (i == rdev->pm.default_power_state_index) - DRM_DEBUG("\tDefault"); + DRM_DEBUG_DRIVER("\tDefault"); if ((rdev->flags & RADEON_IS_PCIE) && !(rdev->flags & RADEON_IS_IGP)) - DRM_DEBUG("\t%d PCIE Lanes\n", power_state->pcie_lanes); + DRM_DEBUG_DRIVER("\t%d PCIE Lanes\n", power_state->pcie_lanes); if (power_state->flags & RADEON_PM_STATE_SINGLE_DISPLAY_ONLY) - DRM_DEBUG("\tSingle display only\n"); - DRM_DEBUG("\t%d Clock Mode(s)\n", power_state->num_clock_modes); + DRM_DEBUG_DRIVER("\tSingle display only\n"); + DRM_DEBUG_DRIVER("\t%d Clock Mode(s)\n", power_state->num_clock_modes); for (j = 0; j < power_state->num_clock_modes; j++) { clock_info = &(power_state->clock_info[j]); if (rdev->flags & RADEON_IS_IGP) - DRM_DEBUG("\t\t%d e: %d%s\n", + DRM_DEBUG_DRIVER("\t\t%d e: %d%s\n", j, clock_info->sclk * 10, clock_info->flags & RADEON_PM_MODE_NO_DISPLAY ? "\tNo display only" : ""); else - DRM_DEBUG("\t\t%d e: %d\tm: %d\tv: %d%s\n", + DRM_DEBUG_DRIVER("\t\t%d e: %d\tm: %d\tv: %d%s\n", j, clock_info->sclk * 10, clock_info->mclk * 10, @@ -424,6 +426,82 @@ fail: static DEVICE_ATTR(power_profile, S_IRUGO | S_IWUSR, radeon_get_pm_profile, radeon_set_pm_profile); static DEVICE_ATTR(power_method, S_IRUGO | S_IWUSR, radeon_get_pm_method, radeon_set_pm_method); +static ssize_t radeon_hwmon_show_temp(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev)); + struct radeon_device *rdev = ddev->dev_private; + u32 temp; + + switch (rdev->pm.int_thermal_type) { + case THERMAL_TYPE_RV6XX: + temp = rv6xx_get_temp(rdev); + break; + case THERMAL_TYPE_RV770: + temp = rv770_get_temp(rdev); + break; + case THERMAL_TYPE_EVERGREEN: + temp = evergreen_get_temp(rdev); + break; + default: + temp = 0; + break; + } + + return snprintf(buf, PAGE_SIZE, "%d\n", temp); +} + +static ssize_t radeon_hwmon_show_name(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "radeon\n"); +} + +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, radeon_hwmon_show_temp, NULL, 0); +static SENSOR_DEVICE_ATTR(name, S_IRUGO, radeon_hwmon_show_name, NULL, 0); + +static struct attribute *hwmon_attributes[] = { + &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_name.dev_attr.attr, + NULL +}; + +static const struct attribute_group hwmon_attrgroup = { + .attrs = hwmon_attributes, +}; + +static void radeon_hwmon_init(struct radeon_device *rdev) +{ + int err; + + rdev->pm.int_hwmon_dev = NULL; + + switch (rdev->pm.int_thermal_type) { + case THERMAL_TYPE_RV6XX: + case THERMAL_TYPE_RV770: + case THERMAL_TYPE_EVERGREEN: + rdev->pm.int_hwmon_dev = hwmon_device_register(rdev->dev); + dev_set_drvdata(rdev->pm.int_hwmon_dev, rdev->ddev); + err = sysfs_create_group(&rdev->pm.int_hwmon_dev->kobj, + &hwmon_attrgroup); + if (err) + DRM_ERROR("Unable to create hwmon sysfs file: %d\n", err); + break; + default: + break; + } +} + +static void radeon_hwmon_fini(struct radeon_device *rdev) +{ + if (rdev->pm.int_hwmon_dev) { + sysfs_remove_group(&rdev->pm.int_hwmon_dev->kobj, &hwmon_attrgroup); + hwmon_device_unregister(rdev->pm.int_hwmon_dev); + } +} + void radeon_pm_suspend(struct radeon_device *rdev) { bool flush_wq = false; @@ -471,6 +549,7 @@ int radeon_pm_init(struct radeon_device *rdev) rdev->pm.dynpm_can_downclock = true; rdev->pm.current_sclk = rdev->clock.default_sclk; rdev->pm.current_mclk = rdev->clock.default_mclk; + rdev->pm.int_thermal_type = THERMAL_TYPE_NONE; if (rdev->bios) { if (rdev->is_atom_bios) @@ -481,6 +560,8 @@ int radeon_pm_init(struct radeon_device *rdev) radeon_pm_init_profile(rdev); } + /* set up the internal thermal sensor if applicable */ + radeon_hwmon_init(rdev); if (rdev->pm.num_power_states > 1) { /* where's the best place to put these? */ ret = device_create_file(rdev->dev, &dev_attr_power_profile); @@ -536,6 +617,7 @@ void radeon_pm_fini(struct radeon_device *rdev) #endif } + radeon_hwmon_fini(rdev); if (rdev->pm.i2c_bus) radeon_i2c_destroy(rdev->pm.i2c_bus); } @@ -576,7 +658,7 @@ void radeon_pm_compute_clocks(struct radeon_device *rdev) radeon_pm_get_dynpm_state(rdev); radeon_pm_set_clocks(rdev); - DRM_DEBUG("radeon: dynamic power management deactivated\n"); + DRM_DEBUG_DRIVER("radeon: dynamic power management deactivated\n"); } } else if (rdev->pm.active_crtc_count == 1) { /* TODO: Increase clocks if needed for current mode */ @@ -593,7 +675,7 @@ void radeon_pm_compute_clocks(struct radeon_device *rdev) rdev->pm.dynpm_state = DYNPM_STATE_ACTIVE; queue_delayed_work(rdev->wq, &rdev->pm.dynpm_idle_work, msecs_to_jiffies(RADEON_IDLE_LOOP_MS)); - DRM_DEBUG("radeon: dynamic power management activated\n"); + DRM_DEBUG_DRIVER("radeon: dynamic power management activated\n"); } } else { /* count == 0 */ if (rdev->pm.dynpm_state != DYNPM_STATE_MINIMUM) { @@ -689,7 +771,7 @@ static bool radeon_pm_debug_check_in_vbl(struct radeon_device *rdev, bool finish bool in_vbl = radeon_pm_in_vbl(rdev); if (in_vbl == false) - DRM_DEBUG("not in vbl for pm change %08x at %s\n", stat_crtc, + DRM_DEBUG_DRIVER("not in vbl for pm change %08x at %s\n", stat_crtc, finish ? "exit" : "entry"); return in_vbl; } diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c index e9918d8..84c53e4 100644 --- a/drivers/gpu/drm/radeon/radeon_ttm.c +++ b/drivers/gpu/drm/radeon/radeon_ttm.c @@ -59,28 +59,28 @@ static struct radeon_device *radeon_get_rdev(struct ttm_bo_device *bdev) /* * Global memory. */ -static int radeon_ttm_mem_global_init(struct ttm_global_reference *ref) +static int radeon_ttm_mem_global_init(struct drm_global_reference *ref) { return ttm_mem_global_init(ref->object); } -static void radeon_ttm_mem_global_release(struct ttm_global_reference *ref) +static void radeon_ttm_mem_global_release(struct drm_global_reference *ref) { ttm_mem_global_release(ref->object); } static int radeon_ttm_global_init(struct radeon_device *rdev) { - struct ttm_global_reference *global_ref; + struct drm_global_reference *global_ref; int r; rdev->mman.mem_global_referenced = false; global_ref = &rdev->mman.mem_global_ref; - global_ref->global_type = TTM_GLOBAL_TTM_MEM; + global_ref->global_type = DRM_GLOBAL_TTM_MEM; global_ref->size = sizeof(struct ttm_mem_global); global_ref->init = &radeon_ttm_mem_global_init; global_ref->release = &radeon_ttm_mem_global_release; - r = ttm_global_item_ref(global_ref); + r = drm_global_item_ref(global_ref); if (r != 0) { DRM_ERROR("Failed setting up TTM memory accounting " "subsystem.\n"); @@ -90,14 +90,14 @@ static int radeon_ttm_global_init(struct radeon_device *rdev) rdev->mman.bo_global_ref.mem_glob = rdev->mman.mem_global_ref.object; global_ref = &rdev->mman.bo_global_ref.ref; - global_ref->global_type = TTM_GLOBAL_TTM_BO; + global_ref->global_type = DRM_GLOBAL_TTM_BO; global_ref->size = sizeof(struct ttm_bo_global); global_ref->init = &ttm_bo_global_init; global_ref->release = &ttm_bo_global_release; - r = ttm_global_item_ref(global_ref); + r = drm_global_item_ref(global_ref); if (r != 0) { DRM_ERROR("Failed setting up TTM BO subsystem.\n"); - ttm_global_item_unref(&rdev->mman.mem_global_ref); + drm_global_item_unref(&rdev->mman.mem_global_ref); return r; } @@ -108,8 +108,8 @@ static int radeon_ttm_global_init(struct radeon_device *rdev) static void radeon_ttm_global_fini(struct radeon_device *rdev) { if (rdev->mman.mem_global_referenced) { - ttm_global_item_unref(&rdev->mman.bo_global_ref.ref); - ttm_global_item_unref(&rdev->mman.mem_global_ref); + drm_global_item_unref(&rdev->mman.bo_global_ref.ref); + drm_global_item_unref(&rdev->mman.mem_global_ref); rdev->mman.mem_global_referenced = false; } } diff --git a/drivers/gpu/drm/radeon/reg_srcs/r300 b/drivers/gpu/drm/radeon/reg_srcs/r300 index 1e97b2d..b506ec1 100644 --- a/drivers/gpu/drm/radeon/reg_srcs/r300 +++ b/drivers/gpu/drm/radeon/reg_srcs/r300 @@ -187,7 +187,6 @@ r300 0x4f60 0x4364 RS_INST_13 0x4368 RS_INST_14 0x436C RS_INST_15 -0x43A4 SC_HYPERZ_EN 0x43A8 SC_EDGERULE 0x43B0 SC_CLIP_0_A 0x43B4 SC_CLIP_0_B @@ -716,16 +715,4 @@ r300 0x4f60 0x4F08 ZB_STENCILREFMASK 0x4F14 ZB_ZTOP 0x4F18 ZB_ZCACHE_CTLSTAT -0x4F1C ZB_BW_CNTL -0x4F28 ZB_DEPTHCLEARVALUE -0x4F30 ZB_ZMASK_OFFSET -0x4F34 ZB_ZMASK_PITCH -0x4F38 ZB_ZMASK_WRINDEX -0x4F3C ZB_ZMASK_DWORD -0x4F40 ZB_ZMASK_RDINDEX -0x4F44 ZB_HIZ_OFFSET -0x4F48 ZB_HIZ_WRINDEX -0x4F4C ZB_HIZ_DWORD -0x4F50 ZB_HIZ_RDINDEX -0x4F54 ZB_HIZ_PITCH 0x4F58 ZB_ZPASS_DATA diff --git a/drivers/gpu/drm/radeon/reg_srcs/r420 b/drivers/gpu/drm/radeon/reg_srcs/r420 index e958980..8c1214c 100644 --- a/drivers/gpu/drm/radeon/reg_srcs/r420 +++ b/drivers/gpu/drm/radeon/reg_srcs/r420 @@ -130,6 +130,7 @@ r420 0x4f60 0x401C GB_SELECT 0x4020 GB_AA_CONFIG 0x4024 GB_FIFO_SIZE +0x4028 GB_Z_PEQ_CONFIG 0x4100 TX_INVALTAGS 0x4200 GA_POINT_S0 0x4204 GA_POINT_T0 @@ -187,7 +188,6 @@ r420 0x4f60 0x4364 RS_INST_13 0x4368 RS_INST_14 0x436C RS_INST_15 -0x43A4 SC_HYPERZ_EN 0x43A8 SC_EDGERULE 0x43B0 SC_CLIP_0_A 0x43B4 SC_CLIP_0_B @@ -782,16 +782,4 @@ r420 0x4f60 0x4F08 ZB_STENCILREFMASK 0x4F14 ZB_ZTOP 0x4F18 ZB_ZCACHE_CTLSTAT -0x4F1C ZB_BW_CNTL -0x4F28 ZB_DEPTHCLEARVALUE -0x4F30 ZB_ZMASK_OFFSET -0x4F34 ZB_ZMASK_PITCH -0x4F38 ZB_ZMASK_WRINDEX -0x4F3C ZB_ZMASK_DWORD -0x4F40 ZB_ZMASK_RDINDEX -0x4F44 ZB_HIZ_OFFSET -0x4F48 ZB_HIZ_WRINDEX -0x4F4C ZB_HIZ_DWORD -0x4F50 ZB_HIZ_RDINDEX -0x4F54 ZB_HIZ_PITCH 0x4F58 ZB_ZPASS_DATA diff --git a/drivers/gpu/drm/radeon/reg_srcs/rs600 b/drivers/gpu/drm/radeon/reg_srcs/rs600 index 83e8bc0..0828d80 100644 --- a/drivers/gpu/drm/radeon/reg_srcs/rs600 +++ b/drivers/gpu/drm/radeon/reg_srcs/rs600 @@ -187,7 +187,6 @@ rs600 0x6d40 0x4364 RS_INST_13 0x4368 RS_INST_14 0x436C RS_INST_15 -0x43A4 SC_HYPERZ_EN 0x43A8 SC_EDGERULE 0x43B0 SC_CLIP_0_A 0x43B4 SC_CLIP_0_B @@ -782,16 +781,4 @@ rs600 0x6d40 0x4F08 ZB_STENCILREFMASK 0x4F14 ZB_ZTOP 0x4F18 ZB_ZCACHE_CTLSTAT -0x4F1C ZB_BW_CNTL -0x4F28 ZB_DEPTHCLEARVALUE -0x4F30 ZB_ZMASK_OFFSET -0x4F34 ZB_ZMASK_PITCH -0x4F38 ZB_ZMASK_WRINDEX -0x4F3C ZB_ZMASK_DWORD -0x4F40 ZB_ZMASK_RDINDEX -0x4F44 ZB_HIZ_OFFSET -0x4F48 ZB_HIZ_WRINDEX -0x4F4C ZB_HIZ_DWORD -0x4F50 ZB_HIZ_RDINDEX -0x4F54 ZB_HIZ_PITCH 0x4F58 ZB_ZPASS_DATA diff --git a/drivers/gpu/drm/radeon/reg_srcs/rv515 b/drivers/gpu/drm/radeon/reg_srcs/rv515 index 1e46233..8293855 100644 --- a/drivers/gpu/drm/radeon/reg_srcs/rv515 +++ b/drivers/gpu/drm/radeon/reg_srcs/rv515 @@ -235,7 +235,6 @@ rv515 0x6d40 0x4354 RS_INST_13 0x4358 RS_INST_14 0x435C RS_INST_15 -0x43A4 SC_HYPERZ_EN 0x43A8 SC_EDGERULE 0x43B0 SC_CLIP_0_A 0x43B4 SC_CLIP_0_B @@ -479,17 +478,5 @@ rv515 0x6d40 0x4F08 ZB_STENCILREFMASK 0x4F14 ZB_ZTOP 0x4F18 ZB_ZCACHE_CTLSTAT -0x4F1C ZB_BW_CNTL -0x4F28 ZB_DEPTHCLEARVALUE -0x4F30 ZB_ZMASK_OFFSET -0x4F34 ZB_ZMASK_PITCH -0x4F38 ZB_ZMASK_WRINDEX -0x4F3C ZB_ZMASK_DWORD -0x4F40 ZB_ZMASK_RDINDEX -0x4F44 ZB_HIZ_OFFSET -0x4F48 ZB_HIZ_WRINDEX -0x4F4C ZB_HIZ_DWORD -0x4F50 ZB_HIZ_RDINDEX -0x4F54 ZB_HIZ_PITCH 0x4F58 ZB_ZPASS_DATA 0x4FD4 ZB_STENCILREFMASK_BF diff --git a/drivers/gpu/drm/radeon/rs400.c b/drivers/gpu/drm/radeon/rs400.c index f454c9a..ae2b76b 100644 --- a/drivers/gpu/drm/radeon/rs400.c +++ b/drivers/gpu/drm/radeon/rs400.c @@ -55,14 +55,6 @@ void rs400_gart_adjust_size(struct radeon_device *rdev) rdev->mc.gtt_size = 32 * 1024 * 1024; return; } - if (rdev->family == CHIP_RS400 || rdev->family == CHIP_RS480) { - /* FIXME: RS400 & RS480 seems to have issue with GART size - * if 4G of system memory (needs more testing) - */ - /* XXX is this still an issue with proper alignment? */ - rdev->mc.gtt_size = 32 * 1024 * 1024; - DRM_ERROR("Forcing to 32M GART size (because of ASIC bug ?)\n"); - } } void rs400_gart_tlb_flush(struct radeon_device *rdev) @@ -483,6 +475,8 @@ int rs400_init(struct radeon_device *rdev) /* Initialize surface registers */ radeon_surface_init(rdev); /* TODO: disable VGA need to use VGA request */ + /* restore some register to sane defaults */ + r100_restore_sanity(rdev); /* BIOS*/ if (!radeon_get_bios(rdev)) { if (ASIC_IS_AVIVO(rdev)) diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c index 6dc15ea..cc05b23 100644 --- a/drivers/gpu/drm/radeon/rs600.c +++ b/drivers/gpu/drm/radeon/rs600.c @@ -686,8 +686,8 @@ void rs600_mc_init(struct radeon_device *rdev) { u64 base; - rdev->mc.aper_base = drm_get_resource_start(rdev->ddev, 0); - rdev->mc.aper_size = drm_get_resource_len(rdev->ddev, 0); + rdev->mc.aper_base = pci_resource_start(rdev->pdev, 0); + rdev->mc.aper_size = pci_resource_len(rdev->pdev, 0); rdev->mc.vram_is_ddr = true; rdev->mc.vram_width = 128; rdev->mc.real_vram_size = RREG32(RADEON_CONFIG_MEMSIZE); @@ -696,7 +696,6 @@ void rs600_mc_init(struct radeon_device *rdev) rdev->mc.igp_sideport_enabled = radeon_atombios_sideport_present(rdev); base = RREG32_MC(R_000004_MC_FB_LOCATION); base = G_000004_MC_FB_START(base) << 16; - rdev->mc.igp_sideport_enabled = radeon_atombios_sideport_present(rdev); radeon_vram_location(rdev, &rdev->mc, base); rdev->mc.gtt_base_align = 0; radeon_gtt_location(rdev, &rdev->mc); @@ -813,6 +812,13 @@ static int rs600_startup(struct radeon_device *rdev) dev_err(rdev->dev, "failled initializing IB (%d).\n", r); return r; } + + r = r600_audio_init(rdev); + if (r) { + dev_err(rdev->dev, "failed initializing audio\n"); + return r; + } + return 0; } @@ -839,6 +845,7 @@ int rs600_resume(struct radeon_device *rdev) int rs600_suspend(struct radeon_device *rdev) { + r600_audio_fini(rdev); r100_cp_disable(rdev); r100_wb_disable(rdev); rs600_irq_disable(rdev); @@ -848,6 +855,7 @@ int rs600_suspend(struct radeon_device *rdev) void rs600_fini(struct radeon_device *rdev) { + r600_audio_fini(rdev); r100_cp_fini(rdev); r100_wb_fini(rdev); r100_ib_fini(rdev); @@ -871,6 +879,8 @@ int rs600_init(struct radeon_device *rdev) radeon_scratch_init(rdev); /* Initialize surface registers */ radeon_surface_init(rdev); + /* restore some register to sane defaults */ + r100_restore_sanity(rdev); /* BIOS */ if (!radeon_get_bios(rdev)) { if (ASIC_IS_AVIVO(rdev)) diff --git a/drivers/gpu/drm/radeon/rs690.c b/drivers/gpu/drm/radeon/rs690.c index ce4ecbe..3e3f757 100644 --- a/drivers/gpu/drm/radeon/rs690.c +++ b/drivers/gpu/drm/radeon/rs690.c @@ -154,13 +154,13 @@ void rs690_mc_init(struct radeon_device *rdev) rdev->mc.vram_width = 128; rdev->mc.real_vram_size = RREG32(RADEON_CONFIG_MEMSIZE); rdev->mc.mc_vram_size = rdev->mc.real_vram_size; - rdev->mc.aper_base = drm_get_resource_start(rdev->ddev, 0); - rdev->mc.aper_size = drm_get_resource_len(rdev->ddev, 0); + rdev->mc.aper_base = pci_resource_start(rdev->pdev, 0); + rdev->mc.aper_size = pci_resource_len(rdev->pdev, 0); rdev->mc.visible_vram_size = rdev->mc.aper_size; base = RREG32_MC(R_000100_MCCFG_FB_LOCATION); base = G_000100_MC_FB_START(base) << 16; - rs690_pm_info(rdev); rdev->mc.igp_sideport_enabled = radeon_atombios_sideport_present(rdev); + rs690_pm_info(rdev); radeon_vram_location(rdev, &rdev->mc, base); rdev->mc.gtt_base_align = rdev->mc.gtt_size - 1; radeon_gtt_location(rdev, &rdev->mc); @@ -398,7 +398,9 @@ void rs690_bandwidth_update(struct radeon_device *rdev) struct drm_display_mode *mode1 = NULL; struct rs690_watermark wm0; struct rs690_watermark wm1; - u32 tmp, d1mode_priority_a_cnt, d2mode_priority_a_cnt; + u32 tmp; + u32 d1mode_priority_a_cnt = S_006548_D1MODE_PRIORITY_A_OFF(1); + u32 d2mode_priority_a_cnt = S_006548_D1MODE_PRIORITY_A_OFF(1); fixed20_12 priority_mark02, priority_mark12, fill_rate; fixed20_12 a, b; @@ -495,10 +497,6 @@ void rs690_bandwidth_update(struct radeon_device *rdev) d1mode_priority_a_cnt |= S_006548_D1MODE_PRIORITY_A_ALWAYS_ON(1); d2mode_priority_a_cnt |= S_006D48_D2MODE_PRIORITY_A_ALWAYS_ON(1); } - WREG32(R_006548_D1MODE_PRIORITY_A_CNT, d1mode_priority_a_cnt); - WREG32(R_00654C_D1MODE_PRIORITY_B_CNT, d1mode_priority_a_cnt); - WREG32(R_006D48_D2MODE_PRIORITY_A_CNT, d2mode_priority_a_cnt); - WREG32(R_006D4C_D2MODE_PRIORITY_B_CNT, d2mode_priority_a_cnt); } else if (mode0) { if (dfixed_trunc(wm0.dbpp) > 64) a.full = dfixed_mul(wm0.dbpp, wm0.num_line_pair); @@ -528,13 +526,7 @@ void rs690_bandwidth_update(struct radeon_device *rdev) d1mode_priority_a_cnt = dfixed_trunc(priority_mark02); if (rdev->disp_priority == 2) d1mode_priority_a_cnt |= S_006548_D1MODE_PRIORITY_A_ALWAYS_ON(1); - WREG32(R_006548_D1MODE_PRIORITY_A_CNT, d1mode_priority_a_cnt); - WREG32(R_00654C_D1MODE_PRIORITY_B_CNT, d1mode_priority_a_cnt); - WREG32(R_006D48_D2MODE_PRIORITY_A_CNT, - S_006D48_D2MODE_PRIORITY_A_OFF(1)); - WREG32(R_006D4C_D2MODE_PRIORITY_B_CNT, - S_006D4C_D2MODE_PRIORITY_B_OFF(1)); - } else { + } else if (mode1) { if (dfixed_trunc(wm1.dbpp) > 64) a.full = dfixed_mul(wm1.dbpp, wm1.num_line_pair); else @@ -563,13 +555,12 @@ void rs690_bandwidth_update(struct radeon_device *rdev) d2mode_priority_a_cnt = dfixed_trunc(priority_mark12); if (rdev->disp_priority == 2) d2mode_priority_a_cnt |= S_006D48_D2MODE_PRIORITY_A_ALWAYS_ON(1); - WREG32(R_006548_D1MODE_PRIORITY_A_CNT, - S_006548_D1MODE_PRIORITY_A_OFF(1)); - WREG32(R_00654C_D1MODE_PRIORITY_B_CNT, - S_00654C_D1MODE_PRIORITY_B_OFF(1)); - WREG32(R_006D48_D2MODE_PRIORITY_A_CNT, d2mode_priority_a_cnt); - WREG32(R_006D4C_D2MODE_PRIORITY_B_CNT, d2mode_priority_a_cnt); } + + WREG32(R_006548_D1MODE_PRIORITY_A_CNT, d1mode_priority_a_cnt); + WREG32(R_00654C_D1MODE_PRIORITY_B_CNT, d1mode_priority_a_cnt); + WREG32(R_006D48_D2MODE_PRIORITY_A_CNT, d2mode_priority_a_cnt); + WREG32(R_006D4C_D2MODE_PRIORITY_B_CNT, d2mode_priority_a_cnt); } uint32_t rs690_mc_rreg(struct radeon_device *rdev, uint32_t reg) @@ -641,6 +632,13 @@ static int rs690_startup(struct radeon_device *rdev) dev_err(rdev->dev, "failled initializing IB (%d).\n", r); return r; } + + r = r600_audio_init(rdev); + if (r) { + dev_err(rdev->dev, "failed initializing audio\n"); + return r; + } + return 0; } @@ -667,6 +665,7 @@ int rs690_resume(struct radeon_device *rdev) int rs690_suspend(struct radeon_device *rdev) { + r600_audio_fini(rdev); r100_cp_disable(rdev); r100_wb_disable(rdev); rs600_irq_disable(rdev); @@ -676,6 +675,7 @@ int rs690_suspend(struct radeon_device *rdev) void rs690_fini(struct radeon_device *rdev) { + r600_audio_fini(rdev); r100_cp_fini(rdev); r100_wb_fini(rdev); r100_ib_fini(rdev); @@ -699,6 +699,8 @@ int rs690_init(struct radeon_device *rdev) radeon_scratch_init(rdev); /* Initialize surface registers */ radeon_surface_init(rdev); + /* restore some register to sane defaults */ + r100_restore_sanity(rdev); /* TODO: disable VGA need to use VGA request */ /* BIOS*/ if (!radeon_get_bios(rdev)) { diff --git a/drivers/gpu/drm/radeon/rv515.c b/drivers/gpu/drm/radeon/rv515.c index 0c9c169..4d6e860 100644 --- a/drivers/gpu/drm/radeon/rv515.c +++ b/drivers/gpu/drm/radeon/rv515.c @@ -469,6 +469,8 @@ int rv515_init(struct radeon_device *rdev) /* Initialize surface registers */ radeon_surface_init(rdev); /* TODO: disable VGA need to use VGA request */ + /* restore some register to sane defaults */ + r100_restore_sanity(rdev); /* BIOS*/ if (!radeon_get_bios(rdev)) { if (ASIC_IS_AVIVO(rdev)) @@ -925,7 +927,9 @@ void rv515_bandwidth_avivo_update(struct radeon_device *rdev) struct drm_display_mode *mode1 = NULL; struct rv515_watermark wm0; struct rv515_watermark wm1; - u32 tmp, d1mode_priority_a_cnt, d2mode_priority_a_cnt; + u32 tmp; + u32 d1mode_priority_a_cnt = MODE_PRIORITY_OFF; + u32 d2mode_priority_a_cnt = MODE_PRIORITY_OFF; fixed20_12 priority_mark02, priority_mark12, fill_rate; fixed20_12 a, b; @@ -999,10 +1003,6 @@ void rv515_bandwidth_avivo_update(struct radeon_device *rdev) d1mode_priority_a_cnt |= MODE_PRIORITY_ALWAYS_ON; d2mode_priority_a_cnt |= MODE_PRIORITY_ALWAYS_ON; } - WREG32(D1MODE_PRIORITY_A_CNT, d1mode_priority_a_cnt); - WREG32(D1MODE_PRIORITY_B_CNT, d1mode_priority_a_cnt); - WREG32(D2MODE_PRIORITY_A_CNT, d2mode_priority_a_cnt); - WREG32(D2MODE_PRIORITY_B_CNT, d2mode_priority_a_cnt); } else if (mode0) { if (dfixed_trunc(wm0.dbpp) > 64) a.full = dfixed_div(wm0.dbpp, wm0.num_line_pair); @@ -1032,11 +1032,7 @@ void rv515_bandwidth_avivo_update(struct radeon_device *rdev) d1mode_priority_a_cnt = dfixed_trunc(priority_mark02); if (rdev->disp_priority == 2) d1mode_priority_a_cnt |= MODE_PRIORITY_ALWAYS_ON; - WREG32(D1MODE_PRIORITY_A_CNT, d1mode_priority_a_cnt); - WREG32(D1MODE_PRIORITY_B_CNT, d1mode_priority_a_cnt); - WREG32(D2MODE_PRIORITY_A_CNT, MODE_PRIORITY_OFF); - WREG32(D2MODE_PRIORITY_B_CNT, MODE_PRIORITY_OFF); - } else { + } else if (mode1) { if (dfixed_trunc(wm1.dbpp) > 64) a.full = dfixed_div(wm1.dbpp, wm1.num_line_pair); else @@ -1065,11 +1061,12 @@ void rv515_bandwidth_avivo_update(struct radeon_device *rdev) d2mode_priority_a_cnt = dfixed_trunc(priority_mark12); if (rdev->disp_priority == 2) d2mode_priority_a_cnt |= MODE_PRIORITY_ALWAYS_ON; - WREG32(D1MODE_PRIORITY_A_CNT, MODE_PRIORITY_OFF); - WREG32(D1MODE_PRIORITY_B_CNT, MODE_PRIORITY_OFF); - WREG32(D2MODE_PRIORITY_A_CNT, d2mode_priority_a_cnt); - WREG32(D2MODE_PRIORITY_B_CNT, d2mode_priority_a_cnt); } + + WREG32(D1MODE_PRIORITY_A_CNT, d1mode_priority_a_cnt); + WREG32(D1MODE_PRIORITY_B_CNT, d1mode_priority_a_cnt); + WREG32(D2MODE_PRIORITY_A_CNT, d2mode_priority_a_cnt); + WREG32(D2MODE_PRIORITY_B_CNT, d2mode_priority_a_cnt); } void rv515_bandwidth_update(struct radeon_device *rdev) diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index b7fd820..f1c79681 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -42,6 +42,21 @@ static void rv770_gpu_init(struct radeon_device *rdev); void rv770_fini(struct radeon_device *rdev); +/* get temperature in millidegrees */ +u32 rv770_get_temp(struct radeon_device *rdev) +{ + u32 temp = (RREG32(CG_MULT_THERMAL_STATUS) & ASIC_T_MASK) >> + ASIC_T_SHIFT; + u32 actual_temp = 0; + + if ((temp >> 9) & 1) + actual_temp = 0; + else + actual_temp = (temp >> 1) & 0xff; + + return actual_temp * 1000; +} + void rv770_pm_misc(struct radeon_device *rdev) { int req_ps_idx = rdev->pm.requested_power_state_index; @@ -189,7 +204,10 @@ static void rv770_mc_program(struct radeon_device *rdev) WREG32((0x2c20 + j), 0x00000000); WREG32((0x2c24 + j), 0x00000000); } - WREG32(HDP_REG_COHERENCY_FLUSH_CNTL, 0); + /* r7xx hw bug. Read from HDP_DEBUG1 rather + * than writing to HDP_REG_COHERENCY_FLUSH_CNTL + */ + tmp = RREG32(HDP_DEBUG1); rv515_mc_stop(rdev, &save); if (r600_mc_wait_for_idle(rdev)) { @@ -659,8 +677,9 @@ static void rv770_gpu_init(struct radeon_device *rdev) r600_count_pipe_bits((cc_rb_backend_disable & R7XX_MAX_BACKENDS_MASK) >> 16)), (cc_rb_backend_disable >> 16)); - gb_tiling_config |= BACKEND_MAP(backend_map); + rdev->config.rv770.tile_config = gb_tiling_config; + gb_tiling_config |= BACKEND_MAP(backend_map); WREG32(GB_TILING_CONFIG, gb_tiling_config); WREG32(DCP_TILING_CONFIG, (gb_tiling_config & 0xffff)); @@ -919,8 +938,8 @@ int rv770_mc_init(struct radeon_device *rdev) } rdev->mc.vram_width = numchan * chansize; /* Could aper size report 0 ? */ - rdev->mc.aper_base = drm_get_resource_start(rdev->ddev, 0); - rdev->mc.aper_size = drm_get_resource_len(rdev->ddev, 0); + rdev->mc.aper_base = pci_resource_start(rdev->pdev, 0); + rdev->mc.aper_size = pci_resource_len(rdev->pdev, 0); /* Setup GPU memory space */ rdev->mc.mc_vram_size = RREG32(CONFIG_MEMSIZE); rdev->mc.real_vram_size = RREG32(CONFIG_MEMSIZE); diff --git a/drivers/gpu/drm/radeon/rv770d.h b/drivers/gpu/drm/radeon/rv770d.h index 9506f8c..b7a5a20 100644 --- a/drivers/gpu/drm/radeon/rv770d.h +++ b/drivers/gpu/drm/radeon/rv770d.h @@ -122,12 +122,18 @@ #define GUI_ACTIVE (1<<31) #define GRBM_STATUS2 0x8014 +#define CG_MULT_THERMAL_STATUS 0x740 +#define ASIC_T(x) ((x) << 16) +#define ASIC_T_MASK 0x3FF0000 +#define ASIC_T_SHIFT 16 + #define HDP_HOST_PATH_CNTL 0x2C00 #define HDP_NONSURFACE_BASE 0x2C04 #define HDP_NONSURFACE_INFO 0x2C08 #define HDP_NONSURFACE_SIZE 0x2C0C #define HDP_REG_COHERENCY_FLUSH_CNTL 0x54A0 #define HDP_TILING_CONFIG 0x2F3C +#define HDP_DEBUG1 0x2F34 #define MC_SHARED_CHMAP 0x2004 #define NOOFCHAN_SHIFT 12 diff --git a/drivers/gpu/drm/savage/savage_bci.c b/drivers/gpu/drm/savage/savage_bci.c index fa05cda..976dc8d 100644 --- a/drivers/gpu/drm/savage/savage_bci.c +++ b/drivers/gpu/drm/savage/savage_bci.c @@ -573,13 +573,13 @@ int savage_driver_firstopen(struct drm_device *dev) dev_priv->mtrr[2].handle = -1; if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) { fb_rsrc = 0; - fb_base = drm_get_resource_start(dev, 0); + fb_base = pci_resource_start(dev->pdev, 0); fb_size = SAVAGE_FB_SIZE_S3; mmio_base = fb_base + SAVAGE_FB_SIZE_S3; aper_rsrc = 0; aperture_base = fb_base + SAVAGE_APERTURE_OFFSET; /* this should always be true */ - if (drm_get_resource_len(dev, 0) == 0x08000000) { + if (pci_resource_len(dev->pdev, 0) == 0x08000000) { /* Don't make MMIO write-cobining! We need 3 * MTRRs. */ dev_priv->mtrr[0].base = fb_base; @@ -599,18 +599,19 @@ int savage_driver_firstopen(struct drm_device *dev) dev_priv->mtrr[2].size, DRM_MTRR_WC); } else { DRM_ERROR("strange pci_resource_len %08llx\n", - (unsigned long long)drm_get_resource_len(dev, 0)); + (unsigned long long) + pci_resource_len(dev->pdev, 0)); } } else if (dev_priv->chipset != S3_SUPERSAVAGE && dev_priv->chipset != S3_SAVAGE2000) { - mmio_base = drm_get_resource_start(dev, 0); + mmio_base = pci_resource_start(dev->pdev, 0); fb_rsrc = 1; - fb_base = drm_get_resource_start(dev, 1); + fb_base = pci_resource_start(dev->pdev, 1); fb_size = SAVAGE_FB_SIZE_S4; aper_rsrc = 1; aperture_base = fb_base + SAVAGE_APERTURE_OFFSET; /* this should always be true */ - if (drm_get_resource_len(dev, 1) == 0x08000000) { + if (pci_resource_len(dev->pdev, 1) == 0x08000000) { /* Can use one MTRR to cover both fb and * aperture. */ dev_priv->mtrr[0].base = fb_base; @@ -620,15 +621,16 @@ int savage_driver_firstopen(struct drm_device *dev) dev_priv->mtrr[0].size, DRM_MTRR_WC); } else { DRM_ERROR("strange pci_resource_len %08llx\n", - (unsigned long long)drm_get_resource_len(dev, 1)); + (unsigned long long) + pci_resource_len(dev->pdev, 1)); } } else { - mmio_base = drm_get_resource_start(dev, 0); + mmio_base = pci_resource_start(dev->pdev, 0); fb_rsrc = 1; - fb_base = drm_get_resource_start(dev, 1); - fb_size = drm_get_resource_len(dev, 1); + fb_base = pci_resource_start(dev->pdev, 1); + fb_size = pci_resource_len(dev->pdev, 1); aper_rsrc = 2; - aperture_base = drm_get_resource_start(dev, 2); + aperture_base = pci_resource_start(dev->pdev, 2); /* Automatic MTRR setup will do the right thing. */ } diff --git a/drivers/gpu/drm/sis/sis_drv.c b/drivers/gpu/drm/sis/sis_drv.c index 4fd1f06..776bf9e 100644 --- a/drivers/gpu/drm/sis/sis_drv.c +++ b/drivers/gpu/drm/sis/sis_drv.c @@ -47,9 +47,8 @@ static int sis_driver_load(struct drm_device *dev, unsigned long chipset) dev->dev_private = (void *)dev_priv; dev_priv->chipset = chipset; ret = drm_sman_init(&dev_priv->sman, 2, 12, 8); - if (ret) { + if (ret) kfree(dev_priv); - } return ret; } diff --git a/drivers/gpu/drm/sis/sis_mm.c b/drivers/gpu/drm/sis/sis_mm.c index af22111..07d0f29 100644 --- a/drivers/gpu/drm/sis/sis_mm.c +++ b/drivers/gpu/drm/sis/sis_mm.c @@ -78,7 +78,7 @@ static unsigned long sis_sman_mm_offset(void *private, void *ref) #else /* CONFIG_FB_SIS[_MODULE] */ #define SIS_MM_ALIGN_SHIFT 4 -#define SIS_MM_ALIGN_MASK ( (1 << SIS_MM_ALIGN_SHIFT) - 1) +#define SIS_MM_ALIGN_MASK ((1 << SIS_MM_ALIGN_SHIFT) - 1) #endif /* CONFIG_FB_SIS[_MODULE] */ @@ -225,9 +225,8 @@ static drm_local_map_t *sis_reg_init(struct drm_device *dev) map = entry->map; if (!map) continue; - if (map->type == _DRM_REGISTERS) { + if (map->type == _DRM_REGISTERS) return map; - } } return NULL; } @@ -264,10 +263,10 @@ int sis_idle(struct drm_device *dev) end = jiffies + (DRM_HZ * 3); - for (i=0; i<4; ++i) { + for (i = 0; i < 4; ++i) { do { idle_reg = SIS_READ(0x85cc); - } while ( !time_after_eq(jiffies, end) && + } while (!time_after_eq(jiffies, end) && ((idle_reg & 0x80000000) != 0x80000000)); } @@ -301,7 +300,7 @@ void sis_lastclose(struct drm_device *dev) mutex_unlock(&dev->struct_mutex); } -void sis_reclaim_buffers_locked(struct drm_device * dev, +void sis_reclaim_buffers_locked(struct drm_device *dev, struct drm_file *file_priv) { drm_sis_private_t *dev_priv = dev->dev_private; @@ -312,9 +311,8 @@ void sis_reclaim_buffers_locked(struct drm_device * dev, return; } - if (dev->driver->dma_quiescent) { + if (dev->driver->dma_quiescent) dev->driver->dma_quiescent(dev); - } drm_sman_owner_cleanup(&dev_priv->sman, (unsigned long)file_priv); mutex_unlock(&dev->struct_mutex); diff --git a/drivers/gpu/drm/ttm/Makefile b/drivers/gpu/drm/ttm/Makefile index 4256e20..b256d4a 100644 --- a/drivers/gpu/drm/ttm/Makefile +++ b/drivers/gpu/drm/ttm/Makefile @@ -3,7 +3,7 @@ ccflags-y := -Iinclude/drm ttm-y := ttm_agp_backend.o ttm_memory.o ttm_tt.o ttm_bo.o \ - ttm_bo_util.o ttm_bo_vm.o ttm_module.o ttm_global.o \ + ttm_bo_util.o ttm_bo_vm.o ttm_module.o \ ttm_object.o ttm_lock.o ttm_execbuf_util.o ttm_page_alloc.o obj-$(CONFIG_DRM_TTM) += ttm.o diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c index 555ebb1..cb4cf7e 100644 --- a/drivers/gpu/drm/ttm/ttm_bo.c +++ b/drivers/gpu/drm/ttm/ttm_bo.c @@ -476,7 +476,6 @@ static int ttm_bo_cleanup_refs(struct ttm_buffer_object *bo, bool remove_all) ++put_count; } if (bo->mem.mm_node) { - bo->mem.mm_node->private = NULL; drm_mm_put_block(bo->mem.mm_node); bo->mem.mm_node = NULL; } @@ -670,7 +669,6 @@ static int ttm_bo_evict(struct ttm_buffer_object *bo, bool interruptible, printk(KERN_ERR TTM_PFX "Buffer eviction failed\n"); spin_lock(&glob->lru_lock); if (evict_mem.mm_node) { - evict_mem.mm_node->private = NULL; drm_mm_put_block(evict_mem.mm_node); evict_mem.mm_node = NULL; } @@ -929,8 +927,6 @@ int ttm_bo_mem_space(struct ttm_buffer_object *bo, mem->mm_node = node; mem->mem_type = mem_type; mem->placement = cur_flags; - if (node) - node->private = bo; return 0; } @@ -973,7 +969,6 @@ int ttm_bo_mem_space(struct ttm_buffer_object *bo, interruptible, no_wait_reserve, no_wait_gpu); if (ret == 0 && mem->mm_node) { mem->placement = cur_flags; - mem->mm_node->private = bo; return 0; } if (ret == -ERESTARTSYS) @@ -1029,7 +1024,6 @@ int ttm_bo_move_buffer(struct ttm_buffer_object *bo, out_unlock: if (ret && mem.mm_node) { spin_lock(&glob->lru_lock); - mem.mm_node->private = NULL; drm_mm_put_block(mem.mm_node); spin_unlock(&glob->lru_lock); } @@ -1401,7 +1395,7 @@ static void ttm_bo_global_kobj_release(struct kobject *kobj) kfree(glob); } -void ttm_bo_global_release(struct ttm_global_reference *ref) +void ttm_bo_global_release(struct drm_global_reference *ref) { struct ttm_bo_global *glob = ref->object; @@ -1410,7 +1404,7 @@ void ttm_bo_global_release(struct ttm_global_reference *ref) } EXPORT_SYMBOL(ttm_bo_global_release); -int ttm_bo_global_init(struct ttm_global_reference *ref) +int ttm_bo_global_init(struct drm_global_reference *ref) { struct ttm_bo_global_ref *bo_ref = container_of(ref, struct ttm_bo_global_ref, ref); diff --git a/drivers/gpu/drm/ttm/ttm_bo_util.c b/drivers/gpu/drm/ttm/ttm_bo_util.c index 13012a1..7cffb3e 100644 --- a/drivers/gpu/drm/ttm/ttm_bo_util.c +++ b/drivers/gpu/drm/ttm/ttm_bo_util.c @@ -353,8 +353,6 @@ static int ttm_buffer_object_transfer(struct ttm_buffer_object *bo, fbo->vm_node = NULL; fbo->sync_obj = driver->sync_obj_ref(bo->sync_obj); - if (fbo->mem.mm_node) - fbo->mem.mm_node->private = (void *)fbo; kref_init(&fbo->list_kref); kref_init(&fbo->kref); fbo->destroy = &ttm_transfered_destroy; diff --git a/drivers/gpu/drm/ttm/ttm_module.c b/drivers/gpu/drm/ttm/ttm_module.c index 9a6edbf..902d7cf 100644 --- a/drivers/gpu/drm/ttm/ttm_module.c +++ b/drivers/gpu/drm/ttm/ttm_module.c @@ -70,8 +70,6 @@ static int __init ttm_init(void) if (unlikely(ret != 0)) return ret; - ttm_global_init(); - atomic_set(&device_released, 0); ret = drm_class_device_register(&ttm_drm_class_device); if (unlikely(ret != 0)) @@ -81,7 +79,6 @@ static int __init ttm_init(void) out_no_dev_reg: atomic_set(&device_released, 1); wake_up_all(&exit_q); - ttm_global_release(); return ret; } @@ -95,7 +92,6 @@ static void __exit ttm_exit(void) */ wait_event(exit_q, atomic_read(&device_released) == 1); - ttm_global_release(); } module_init(ttm_init); diff --git a/drivers/gpu/drm/via/via_dma.c b/drivers/gpu/drm/via/via_dma.c index bfb92d2..68dda74 100644 --- a/drivers/gpu/drm/via/via_dma.c +++ b/drivers/gpu/drm/via/via_dma.c @@ -58,28 +58,29 @@ *((uint32_t *)(vb)) = ((nReg) >> 2) | HALCYON_HEADER1; \ *((uint32_t *)(vb) + 1) = (nData); \ vb = ((uint32_t *)vb) + 2; \ - dev_priv->dma_low +=8; \ + dev_priv->dma_low += 8; \ } #define via_flush_write_combine() DRM_MEMORYBARRIER() -#define VIA_OUT_RING_QW(w1,w2) \ +#define VIA_OUT_RING_QW(w1, w2) do { \ *vb++ = (w1); \ *vb++ = (w2); \ - dev_priv->dma_low += 8; + dev_priv->dma_low += 8; \ +} while (0) -static void via_cmdbuf_start(drm_via_private_t * dev_priv); -static void via_cmdbuf_pause(drm_via_private_t * dev_priv); -static void via_cmdbuf_reset(drm_via_private_t * dev_priv); -static void via_cmdbuf_rewind(drm_via_private_t * dev_priv); -static int via_wait_idle(drm_via_private_t * dev_priv); -static void via_pad_cache(drm_via_private_t * dev_priv, int qwords); +static void via_cmdbuf_start(drm_via_private_t *dev_priv); +static void via_cmdbuf_pause(drm_via_private_t *dev_priv); +static void via_cmdbuf_reset(drm_via_private_t *dev_priv); +static void via_cmdbuf_rewind(drm_via_private_t *dev_priv); +static int via_wait_idle(drm_via_private_t *dev_priv); +static void via_pad_cache(drm_via_private_t *dev_priv, int qwords); /* * Free space in command buffer. */ -static uint32_t via_cmdbuf_space(drm_via_private_t * dev_priv) +static uint32_t via_cmdbuf_space(drm_via_private_t *dev_priv) { uint32_t agp_base = dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr; uint32_t hw_addr = *(dev_priv->hw_addr_ptr) - agp_base; @@ -93,7 +94,7 @@ static uint32_t via_cmdbuf_space(drm_via_private_t * dev_priv) * How much does the command regulator lag behind? */ -static uint32_t via_cmdbuf_lag(drm_via_private_t * dev_priv) +static uint32_t via_cmdbuf_lag(drm_via_private_t *dev_priv) { uint32_t agp_base = dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr; uint32_t hw_addr = *(dev_priv->hw_addr_ptr) - agp_base; @@ -108,7 +109,7 @@ static uint32_t via_cmdbuf_lag(drm_via_private_t * dev_priv) */ static inline int -via_cmdbuf_wait(drm_via_private_t * dev_priv, unsigned int size) +via_cmdbuf_wait(drm_via_private_t *dev_priv, unsigned int size) { uint32_t agp_base = dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr; uint32_t cur_addr, hw_addr, next_addr; @@ -146,14 +147,13 @@ static inline uint32_t *via_check_dma(drm_via_private_t * dev_priv, dev_priv->dma_high) { via_cmdbuf_rewind(dev_priv); } - if (via_cmdbuf_wait(dev_priv, size) != 0) { + if (via_cmdbuf_wait(dev_priv, size) != 0) return NULL; - } return (uint32_t *) (dev_priv->dma_ptr + dev_priv->dma_low); } -int via_dma_cleanup(struct drm_device * dev) +int via_dma_cleanup(struct drm_device *dev) { if (dev->dev_private) { drm_via_private_t *dev_priv = @@ -171,9 +171,9 @@ int via_dma_cleanup(struct drm_device * dev) return 0; } -static int via_initialize(struct drm_device * dev, - drm_via_private_t * dev_priv, - drm_via_dma_init_t * init) +static int via_initialize(struct drm_device *dev, + drm_via_private_t *dev_priv, + drm_via_dma_init_t *init) { if (!dev_priv || !dev_priv->mmio) { DRM_ERROR("via_dma_init called before via_map_init\n"); @@ -258,7 +258,7 @@ static int via_dma_init(struct drm_device *dev, void *data, struct drm_file *fil return retcode; } -static int via_dispatch_cmdbuffer(struct drm_device * dev, drm_via_cmdbuffer_t * cmd) +static int via_dispatch_cmdbuffer(struct drm_device *dev, drm_via_cmdbuffer_t *cmd) { drm_via_private_t *dev_priv; uint32_t *vb; @@ -271,9 +271,8 @@ static int via_dispatch_cmdbuffer(struct drm_device * dev, drm_via_cmdbuffer_t * return -EFAULT; } - if (cmd->size > VIA_PCI_BUF_SIZE) { + if (cmd->size > VIA_PCI_BUF_SIZE) return -ENOMEM; - } if (DRM_COPY_FROM_USER(dev_priv->pci_buf, cmd->buf, cmd->size)) return -EFAULT; @@ -291,9 +290,8 @@ static int via_dispatch_cmdbuffer(struct drm_device * dev, drm_via_cmdbuffer_t * } vb = via_check_dma(dev_priv, (cmd->size < 0x100) ? 0x102 : cmd->size); - if (vb == NULL) { + if (vb == NULL) return -EAGAIN; - } memcpy(vb, dev_priv->pci_buf, cmd->size); @@ -311,13 +309,12 @@ static int via_dispatch_cmdbuffer(struct drm_device * dev, drm_via_cmdbuffer_t * return 0; } -int via_driver_dma_quiescent(struct drm_device * dev) +int via_driver_dma_quiescent(struct drm_device *dev) { drm_via_private_t *dev_priv = dev->dev_private; - if (!via_wait_idle(dev_priv)) { + if (!via_wait_idle(dev_priv)) return -EBUSY; - } return 0; } @@ -339,22 +336,17 @@ static int via_cmdbuffer(struct drm_device *dev, void *data, struct drm_file *fi DRM_DEBUG("buf %p size %lu\n", cmdbuf->buf, cmdbuf->size); ret = via_dispatch_cmdbuffer(dev, cmdbuf); - if (ret) { - return ret; - } - - return 0; + return ret; } -static int via_dispatch_pci_cmdbuffer(struct drm_device * dev, - drm_via_cmdbuffer_t * cmd) +static int via_dispatch_pci_cmdbuffer(struct drm_device *dev, + drm_via_cmdbuffer_t *cmd) { drm_via_private_t *dev_priv = dev->dev_private; int ret; - if (cmd->size > VIA_PCI_BUF_SIZE) { + if (cmd->size > VIA_PCI_BUF_SIZE) return -ENOMEM; - } if (DRM_COPY_FROM_USER(dev_priv->pci_buf, cmd->buf, cmd->size)) return -EFAULT; @@ -380,19 +372,14 @@ static int via_pci_cmdbuffer(struct drm_device *dev, void *data, struct drm_file DRM_DEBUG("buf %p size %lu\n", cmdbuf->buf, cmdbuf->size); ret = via_dispatch_pci_cmdbuffer(dev, cmdbuf); - if (ret) { - return ret; - } - - return 0; + return ret; } -static inline uint32_t *via_align_buffer(drm_via_private_t * dev_priv, +static inline uint32_t *via_align_buffer(drm_via_private_t *dev_priv, uint32_t * vb, int qw_count) { - for (; qw_count > 0; --qw_count) { + for (; qw_count > 0; --qw_count) VIA_OUT_RING_QW(HC_DUMMY, HC_DUMMY); - } return vb; } @@ -401,7 +388,7 @@ static inline uint32_t *via_align_buffer(drm_via_private_t * dev_priv, * * Returns virtual pointer to ring buffer. */ -static inline uint32_t *via_get_dma(drm_via_private_t * dev_priv) +static inline uint32_t *via_get_dma(drm_via_private_t *dev_priv) { return (uint32_t *) (dev_priv->dma_ptr + dev_priv->dma_low); } @@ -411,18 +398,18 @@ static inline uint32_t *via_get_dma(drm_via_private_t * dev_priv) * modifying the pause address stored in the buffer itself. If * the regulator has already paused, restart it. */ -static int via_hook_segment(drm_via_private_t * dev_priv, +static int via_hook_segment(drm_via_private_t *dev_priv, uint32_t pause_addr_hi, uint32_t pause_addr_lo, int no_pci_fire) { int paused, count; volatile uint32_t *paused_at = dev_priv->last_pause_ptr; - uint32_t reader,ptr; + uint32_t reader, ptr; uint32_t diff; paused = 0; via_flush_write_combine(); - (void) *(volatile uint32_t *)(via_get_dma(dev_priv) -1); + (void) *(volatile uint32_t *)(via_get_dma(dev_priv) - 1); *paused_at = pause_addr_lo; via_flush_write_combine(); @@ -435,7 +422,7 @@ static int via_hook_segment(drm_via_private_t * dev_priv, dev_priv->last_pause_ptr = via_get_dma(dev_priv) - 1; /* - * If there is a possibility that the command reader will + * If there is a possibility that the command reader will * miss the new pause address and pause on the old one, * In that case we need to program the new start address * using PCI. @@ -443,9 +430,9 @@ static int via_hook_segment(drm_via_private_t * dev_priv, diff = (uint32_t) (ptr - reader) - dev_priv->dma_diff; count = 10000000; - while(diff == 0 && count--) { + while (diff == 0 && count--) { paused = (VIA_READ(0x41c) & 0x80000000); - if (paused) + if (paused) break; reader = *(dev_priv->hw_addr_ptr); diff = (uint32_t) (ptr - reader) - dev_priv->dma_diff; @@ -477,7 +464,7 @@ static int via_hook_segment(drm_via_private_t * dev_priv, return paused; } -static int via_wait_idle(drm_via_private_t * dev_priv) +static int via_wait_idle(drm_via_private_t *dev_priv) { int count = 10000000; @@ -491,9 +478,9 @@ static int via_wait_idle(drm_via_private_t * dev_priv) return count; } -static uint32_t *via_align_cmd(drm_via_private_t * dev_priv, uint32_t cmd_type, - uint32_t addr, uint32_t * cmd_addr_hi, - uint32_t * cmd_addr_lo, int skip_wait) +static uint32_t *via_align_cmd(drm_via_private_t *dev_priv, uint32_t cmd_type, + uint32_t addr, uint32_t *cmd_addr_hi, + uint32_t *cmd_addr_lo, int skip_wait) { uint32_t agp_base; uint32_t cmd_addr, addr_lo, addr_hi; @@ -521,7 +508,7 @@ static uint32_t *via_align_cmd(drm_via_private_t * dev_priv, uint32_t cmd_type, return vb; } -static void via_cmdbuf_start(drm_via_private_t * dev_priv) +static void via_cmdbuf_start(drm_via_private_t *dev_priv) { uint32_t pause_addr_lo, pause_addr_hi; uint32_t start_addr, start_addr_lo; @@ -580,7 +567,7 @@ static void via_cmdbuf_start(drm_via_private_t * dev_priv) dev_priv->dma_diff = ptr - reader; } -static void via_pad_cache(drm_via_private_t * dev_priv, int qwords) +static void via_pad_cache(drm_via_private_t *dev_priv, int qwords) { uint32_t *vb; @@ -590,7 +577,7 @@ static void via_pad_cache(drm_via_private_t * dev_priv, int qwords) via_align_buffer(dev_priv, vb, qwords); } -static inline void via_dummy_bitblt(drm_via_private_t * dev_priv) +static inline void via_dummy_bitblt(drm_via_private_t *dev_priv) { uint32_t *vb = via_get_dma(dev_priv); SetReg2DAGP(0x0C, (0 | (0 << 16))); @@ -598,7 +585,7 @@ static inline void via_dummy_bitblt(drm_via_private_t * dev_priv) SetReg2DAGP(0x0, 0x1 | 0x2000 | 0xAA000000); } -static void via_cmdbuf_jump(drm_via_private_t * dev_priv) +static void via_cmdbuf_jump(drm_via_private_t *dev_priv) { uint32_t agp_base; uint32_t pause_addr_lo, pause_addr_hi; @@ -617,9 +604,8 @@ static void via_cmdbuf_jump(drm_via_private_t * dev_priv) */ dev_priv->dma_low = 0; - if (via_cmdbuf_wait(dev_priv, CMDBUF_ALIGNMENT_SIZE) != 0) { + if (via_cmdbuf_wait(dev_priv, CMDBUF_ALIGNMENT_SIZE) != 0) DRM_ERROR("via_cmdbuf_jump failed\n"); - } via_dummy_bitblt(dev_priv); via_dummy_bitblt(dev_priv); @@ -657,12 +643,12 @@ static void via_cmdbuf_jump(drm_via_private_t * dev_priv) } -static void via_cmdbuf_rewind(drm_via_private_t * dev_priv) +static void via_cmdbuf_rewind(drm_via_private_t *dev_priv) { via_cmdbuf_jump(dev_priv); } -static void via_cmdbuf_flush(drm_via_private_t * dev_priv, uint32_t cmd_type) +static void via_cmdbuf_flush(drm_via_private_t *dev_priv, uint32_t cmd_type) { uint32_t pause_addr_lo, pause_addr_hi; @@ -670,12 +656,12 @@ static void via_cmdbuf_flush(drm_via_private_t * dev_priv, uint32_t cmd_type) via_hook_segment(dev_priv, pause_addr_hi, pause_addr_lo, 0); } -static void via_cmdbuf_pause(drm_via_private_t * dev_priv) +static void via_cmdbuf_pause(drm_via_private_t *dev_priv) { via_cmdbuf_flush(dev_priv, HC_HAGPBpID_PAUSE); } -static void via_cmdbuf_reset(drm_via_private_t * dev_priv) +static void via_cmdbuf_reset(drm_via_private_t *dev_priv) { via_cmdbuf_flush(dev_priv, HC_HAGPBpID_STOP); via_wait_idle(dev_priv); @@ -708,9 +694,8 @@ static int via_cmdbuf_size(struct drm_device *dev, void *data, struct drm_file * case VIA_CMDBUF_SPACE: while (((tmp_size = via_cmdbuf_space(dev_priv)) < d_siz->size) && --count) { - if (!d_siz->wait) { + if (!d_siz->wait) break; - } } if (!count) { DRM_ERROR("VIA_CMDBUF_SPACE timed out.\n"); @@ -720,9 +705,8 @@ static int via_cmdbuf_size(struct drm_device *dev, void *data, struct drm_file * case VIA_CMDBUF_LAG: while (((tmp_size = via_cmdbuf_lag(dev_priv)) > d_siz->size) && --count) { - if (!d_siz->wait) { + if (!d_siz->wait) break; - } } if (!count) { DRM_ERROR("VIA_CMDBUF_LAG timed out.\n"); diff --git a/drivers/gpu/drm/via/via_dmablit.c b/drivers/gpu/drm/via/via_dmablit.c index 4c54f04..9b5b4d9 100644 --- a/drivers/gpu/drm/via/via_dmablit.c +++ b/drivers/gpu/drm/via/via_dmablit.c @@ -70,7 +70,7 @@ via_unmap_blit_from_device(struct pci_dev *pdev, drm_via_sg_info_t *vsg) descriptor_this_page; dma_addr_t next = vsg->chain_start; - while(num_desc--) { + while (num_desc--) { if (descriptor_this_page-- == 0) { cur_descriptor_page--; descriptor_this_page = vsg->descriptors_per_page - 1; @@ -174,19 +174,19 @@ via_free_sg_info(struct pci_dev *pdev, drm_via_sg_info_t *vsg) struct page *page; int i; - switch(vsg->state) { + switch (vsg->state) { case dr_via_device_mapped: via_unmap_blit_from_device(pdev, vsg); case dr_via_desc_pages_alloc: - for (i=0; i<vsg->num_desc_pages; ++i) { + for (i = 0; i < vsg->num_desc_pages; ++i) { if (vsg->desc_pages[i] != NULL) - free_page((unsigned long)vsg->desc_pages[i]); + free_page((unsigned long)vsg->desc_pages[i]); } kfree(vsg->desc_pages); case dr_via_pages_locked: - for (i=0; i<vsg->num_pages; ++i) { - if ( NULL != (page = vsg->pages[i])) { - if (! PageReserved(page) && (DMA_FROM_DEVICE == vsg->direction)) + for (i = 0; i < vsg->num_pages; ++i) { + if (NULL != (page = vsg->pages[i])) { + if (!PageReserved(page) && (DMA_FROM_DEVICE == vsg->direction)) SetPageDirty(page); page_cache_release(page); } @@ -232,7 +232,7 @@ via_lock_all_dma_pages(drm_via_sg_info_t *vsg, drm_via_dmablit_t *xfer) { int ret; unsigned long first_pfn = VIA_PFN(xfer->mem_addr); - vsg->num_pages = VIA_PFN(xfer->mem_addr + (xfer->num_lines * xfer->mem_stride -1)) - + vsg->num_pages = VIA_PFN(xfer->mem_addr + (xfer->num_lines * xfer->mem_stride - 1)) - first_pfn + 1; if (NULL == (vsg->pages = vmalloc(sizeof(struct page *) * vsg->num_pages))) @@ -268,7 +268,7 @@ via_alloc_desc_pages(drm_via_sg_info_t *vsg) { int i; - vsg->descriptors_per_page = PAGE_SIZE / sizeof( drm_via_descriptor_t); + vsg->descriptors_per_page = PAGE_SIZE / sizeof(drm_via_descriptor_t); vsg->num_desc_pages = (vsg->num_desc + vsg->descriptors_per_page - 1) / vsg->descriptors_per_page; @@ -276,7 +276,7 @@ via_alloc_desc_pages(drm_via_sg_info_t *vsg) return -ENOMEM; vsg->state = dr_via_desc_pages_alloc; - for (i=0; i<vsg->num_desc_pages; ++i) { + for (i = 0; i < vsg->num_desc_pages; ++i) { if (NULL == (vsg->desc_pages[i] = (drm_via_descriptor_t *) __get_free_page(GFP_KERNEL))) return -ENOMEM; @@ -318,21 +318,20 @@ via_dmablit_handler(struct drm_device *dev, int engine, int from_irq) drm_via_blitq_t *blitq = dev_priv->blit_queues + engine; int cur; int done_transfer; - unsigned long irqsave=0; + unsigned long irqsave = 0; uint32_t status = 0; DRM_DEBUG("DMA blit handler called. engine = %d, from_irq = %d, blitq = 0x%lx\n", engine, from_irq, (unsigned long) blitq); - if (from_irq) { + if (from_irq) spin_lock(&blitq->blit_lock); - } else { + else spin_lock_irqsave(&blitq->blit_lock, irqsave); - } done_transfer = blitq->is_active && - (( status = VIA_READ(VIA_PCI_DMA_CSR0 + engine*0x04)) & VIA_DMA_CSR_TD); - done_transfer = done_transfer || ( blitq->aborting && !(status & VIA_DMA_CSR_DE)); + ((status = VIA_READ(VIA_PCI_DMA_CSR0 + engine*0x04)) & VIA_DMA_CSR_TD); + done_transfer = done_transfer || (blitq->aborting && !(status & VIA_DMA_CSR_DE)); cur = blitq->cur; if (done_transfer) { @@ -377,18 +376,16 @@ via_dmablit_handler(struct drm_device *dev, int engine, int from_irq) if (!timer_pending(&blitq->poll_timer)) mod_timer(&blitq->poll_timer, jiffies + 1); } else { - if (timer_pending(&blitq->poll_timer)) { + if (timer_pending(&blitq->poll_timer)) del_timer(&blitq->poll_timer); - } via_dmablit_engine_off(dev, engine); } } - if (from_irq) { + if (from_irq) spin_unlock(&blitq->blit_lock); - } else { + else spin_unlock_irqrestore(&blitq->blit_lock, irqsave); - } } @@ -414,10 +411,9 @@ via_dmablit_active(drm_via_blitq_t *blitq, int engine, uint32_t handle, wait_que ((blitq->cur_blit_handle - handle) <= (1 << 23)); if (queue && active) { - slot = handle - blitq->done_blit_handle + blitq->cur -1; - if (slot >= VIA_NUM_BLIT_SLOTS) { + slot = handle - blitq->done_blit_handle + blitq->cur - 1; + if (slot >= VIA_NUM_BLIT_SLOTS) slot -= VIA_NUM_BLIT_SLOTS; - } *queue = blitq->blit_queue + slot; } @@ -506,12 +502,12 @@ via_dmablit_workqueue(struct work_struct *work) int cur_released; - DRM_DEBUG("Workqueue task called for blit engine %ld\n",(unsigned long) + DRM_DEBUG("Workqueue task called for blit engine %ld\n", (unsigned long) (blitq - ((drm_via_private_t *)dev->dev_private)->blit_queues)); spin_lock_irqsave(&blitq->blit_lock, irqsave); - while(blitq->serviced != blitq->cur) { + while (blitq->serviced != blitq->cur) { cur_released = blitq->serviced++; @@ -545,13 +541,13 @@ via_dmablit_workqueue(struct work_struct *work) void via_init_dmablit(struct drm_device *dev) { - int i,j; + int i, j; drm_via_private_t *dev_priv = (drm_via_private_t *)dev->dev_private; drm_via_blitq_t *blitq; pci_set_master(dev->pdev); - for (i=0; i< VIA_NUM_BLIT_ENGINES; ++i) { + for (i = 0; i < VIA_NUM_BLIT_ENGINES; ++i) { blitq = dev_priv->blit_queues + i; blitq->dev = dev; blitq->cur_blit_handle = 0; @@ -564,9 +560,8 @@ via_init_dmablit(struct drm_device *dev) blitq->is_active = 0; blitq->aborting = 0; spin_lock_init(&blitq->blit_lock); - for (j=0; j<VIA_NUM_BLIT_SLOTS; ++j) { + for (j = 0; j < VIA_NUM_BLIT_SLOTS; ++j) DRM_INIT_WAITQUEUE(blitq->blit_queue + j); - } DRM_INIT_WAITQUEUE(&blitq->busy_queue); INIT_WORK(&blitq->wq, via_dmablit_workqueue); setup_timer(&blitq->poll_timer, via_dmablit_timer, @@ -685,18 +680,17 @@ via_build_sg_info(struct drm_device *dev, drm_via_sg_info_t *vsg, drm_via_dmabli static int via_dmablit_grab_slot(drm_via_blitq_t *blitq, int engine) { - int ret=0; + int ret = 0; unsigned long irqsave; DRM_DEBUG("Num free is %d\n", blitq->num_free); spin_lock_irqsave(&blitq->blit_lock, irqsave); - while(blitq->num_free == 0) { + while (blitq->num_free == 0) { spin_unlock_irqrestore(&blitq->blit_lock, irqsave); DRM_WAIT_ON(ret, blitq->busy_queue, DRM_HZ, blitq->num_free > 0); - if (ret) { + if (ret) return (-EINTR == ret) ? -EAGAIN : ret; - } spin_lock_irqsave(&blitq->blit_lock, irqsave); } @@ -719,7 +713,7 @@ via_dmablit_release_slot(drm_via_blitq_t *blitq) spin_lock_irqsave(&blitq->blit_lock, irqsave); blitq->num_free++; spin_unlock_irqrestore(&blitq->blit_lock, irqsave); - DRM_WAKEUP( &blitq->busy_queue ); + DRM_WAKEUP(&blitq->busy_queue); } /* @@ -744,9 +738,8 @@ via_dmablit(struct drm_device *dev, drm_via_dmablit_t *xfer) engine = (xfer->to_fb) ? 0 : 1; blitq = dev_priv->blit_queues + engine; - if (0 != (ret = via_dmablit_grab_slot(blitq, engine))) { + if (0 != (ret = via_dmablit_grab_slot(blitq, engine))) return ret; - } if (NULL == (vsg = kmalloc(sizeof(*vsg), GFP_KERNEL))) { via_dmablit_release_slot(blitq); return -ENOMEM; @@ -780,7 +773,7 @@ via_dmablit(struct drm_device *dev, drm_via_dmablit_t *xfer) */ int -via_dma_blit_sync( struct drm_device *dev, void *data, struct drm_file *file_priv ) +via_dma_blit_sync(struct drm_device *dev, void *data, struct drm_file *file_priv) { drm_via_blitsync_t *sync = data; int err; @@ -804,7 +797,7 @@ via_dma_blit_sync( struct drm_device *dev, void *data, struct drm_file *file_pri */ int -via_dma_blit( struct drm_device *dev, void *data, struct drm_file *file_priv ) +via_dma_blit(struct drm_device *dev, void *data, struct drm_file *file_priv) { drm_via_dmablit_t *xfer = data; int err; diff --git a/drivers/gpu/drm/via/via_dmablit.h b/drivers/gpu/drm/via/via_dmablit.h index 7408a54..9b662a3 100644 --- a/drivers/gpu/drm/via/via_dmablit.h +++ b/drivers/gpu/drm/via/via_dmablit.h @@ -45,12 +45,12 @@ typedef struct _drm_via_sg_info { int num_desc; enum dma_data_direction direction; unsigned char *bounce_buffer; - dma_addr_t chain_start; + dma_addr_t chain_start; uint32_t free_on_sequence; - unsigned int descriptors_per_page; + unsigned int descriptors_per_page; int aborted; enum { - dr_via_device_mapped, + dr_via_device_mapped, dr_via_desc_pages_alloc, dr_via_pages_locked, dr_via_pages_alloc, @@ -68,7 +68,7 @@ typedef struct _drm_via_blitq { unsigned num_free; unsigned num_outstanding; unsigned long end; - int aborting; + int aborting; int is_active; drm_via_sg_info_t *blits[VIA_NUM_BLIT_SLOTS]; spinlock_t blit_lock; diff --git a/drivers/gpu/drm/via/via_drv.h b/drivers/gpu/drm/via/via_drv.h index cafcb84..9cf87d9 100644 --- a/drivers/gpu/drm/via/via_drv.h +++ b/drivers/gpu/drm/via/via_drv.h @@ -107,9 +107,9 @@ enum via_family { #define VIA_BASE ((dev_priv->mmio)) #define VIA_READ(reg) DRM_READ32(VIA_BASE, reg) -#define VIA_WRITE(reg,val) DRM_WRITE32(VIA_BASE, reg, val) +#define VIA_WRITE(reg, val) DRM_WRITE32(VIA_BASE, reg, val) #define VIA_READ8(reg) DRM_READ8(VIA_BASE, reg) -#define VIA_WRITE8(reg,val) DRM_WRITE8(VIA_BASE, reg, val) +#define VIA_WRITE8(reg, val) DRM_WRITE8(VIA_BASE, reg, val) extern struct drm_ioctl_desc via_ioctls[]; extern int via_max_ioctl; @@ -121,28 +121,28 @@ extern int via_agp_init(struct drm_device *dev, void *data, struct drm_file *fil extern int via_map_init(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int via_decoder_futex(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int via_wait_irq(struct drm_device *dev, void *data, struct drm_file *file_priv); -extern int via_dma_blit_sync( struct drm_device *dev, void *data, struct drm_file *file_priv ); -extern int via_dma_blit( struct drm_device *dev, void *data, struct drm_file *file_priv ); +extern int via_dma_blit_sync(struct drm_device *dev, void *data, struct drm_file *file_priv); +extern int via_dma_blit(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int via_driver_load(struct drm_device *dev, unsigned long chipset); extern int via_driver_unload(struct drm_device *dev); -extern int via_init_context(struct drm_device * dev, int context); -extern int via_final_context(struct drm_device * dev, int context); +extern int via_init_context(struct drm_device *dev, int context); +extern int via_final_context(struct drm_device *dev, int context); -extern int via_do_cleanup_map(struct drm_device * dev); +extern int via_do_cleanup_map(struct drm_device *dev); extern u32 via_get_vblank_counter(struct drm_device *dev, int crtc); extern int via_enable_vblank(struct drm_device *dev, int crtc); extern void via_disable_vblank(struct drm_device *dev, int crtc); extern irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS); -extern void via_driver_irq_preinstall(struct drm_device * dev); +extern void via_driver_irq_preinstall(struct drm_device *dev); extern int via_driver_irq_postinstall(struct drm_device *dev); -extern void via_driver_irq_uninstall(struct drm_device * dev); +extern void via_driver_irq_uninstall(struct drm_device *dev); -extern int via_dma_cleanup(struct drm_device * dev); +extern int via_dma_cleanup(struct drm_device *dev); extern void via_init_command_verifier(void); -extern int via_driver_dma_quiescent(struct drm_device * dev); +extern int via_driver_dma_quiescent(struct drm_device *dev); extern void via_init_futex(drm_via_private_t *dev_priv); extern void via_cleanup_futex(drm_via_private_t *dev_priv); extern void via_release_futex(drm_via_private_t *dev_priv, int context); diff --git a/drivers/gpu/drm/via/via_irq.c b/drivers/gpu/drm/via/via_irq.c index 34079f2..d391f48 100644 --- a/drivers/gpu/drm/via/via_irq.c +++ b/drivers/gpu/drm/via/via_irq.c @@ -141,11 +141,10 @@ irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS) atomic_inc(&cur_irq->irq_received); DRM_WAKEUP(&cur_irq->irq_queue); handled = 1; - if (dev_priv->irq_map[drm_via_irq_dma0_td] == i) { + if (dev_priv->irq_map[drm_via_irq_dma0_td] == i) via_dmablit_handler(dev, 0, 1); - } else if (dev_priv->irq_map[drm_via_irq_dma1_td] == i) { + else if (dev_priv->irq_map[drm_via_irq_dma1_td] == i) via_dmablit_handler(dev, 1, 1); - } } cur_irq++; } @@ -160,7 +159,7 @@ irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS) return IRQ_NONE; } -static __inline__ void viadrv_acknowledge_irqs(drm_via_private_t * dev_priv) +static __inline__ void viadrv_acknowledge_irqs(drm_via_private_t *dev_priv) { u32 status; @@ -207,7 +206,7 @@ void via_disable_vblank(struct drm_device *dev, int crtc) } static int -via_driver_irq_wait(struct drm_device * dev, unsigned int irq, int force_sequence, +via_driver_irq_wait(struct drm_device *dev, unsigned int irq, int force_sequence, unsigned int *sequence) { drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; @@ -260,7 +259,7 @@ via_driver_irq_wait(struct drm_device * dev, unsigned int irq, int force_sequenc * drm_dma.h hooks */ -void via_driver_irq_preinstall(struct drm_device * dev) +void via_driver_irq_preinstall(struct drm_device *dev) { drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; u32 status; @@ -329,7 +328,7 @@ int via_driver_irq_postinstall(struct drm_device *dev) return 0; } -void via_driver_irq_uninstall(struct drm_device * dev) +void via_driver_irq_uninstall(struct drm_device *dev) { drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private; u32 status; diff --git a/drivers/gpu/drm/via/via_map.c b/drivers/gpu/drm/via/via_map.c index 6e6f915..6cca9a7 100644 --- a/drivers/gpu/drm/via/via_map.c +++ b/drivers/gpu/drm/via/via_map.c @@ -25,7 +25,7 @@ #include "via_drm.h" #include "via_drv.h" -static int via_do_init_map(struct drm_device * dev, drm_via_init_t * init) +static int via_do_init_map(struct drm_device *dev, drm_via_init_t *init) { drm_via_private_t *dev_priv = dev->dev_private; @@ -68,7 +68,7 @@ static int via_do_init_map(struct drm_device * dev, drm_via_init_t * init) return 0; } -int via_do_cleanup_map(struct drm_device * dev) +int via_do_cleanup_map(struct drm_device *dev) { via_dma_cleanup(dev); diff --git a/drivers/gpu/drm/via/via_mm.c b/drivers/gpu/drm/via/via_mm.c index f694cb5..6cc2dad 100644 --- a/drivers/gpu/drm/via/via_mm.c +++ b/drivers/gpu/drm/via/via_mm.c @@ -31,7 +31,7 @@ #include "drm_sman.h" #define VIA_MM_ALIGN_SHIFT 4 -#define VIA_MM_ALIGN_MASK ( (1 << VIA_MM_ALIGN_SHIFT) - 1) +#define VIA_MM_ALIGN_MASK ((1 << VIA_MM_ALIGN_SHIFT) - 1) int via_agp_init(struct drm_device *dev, void *data, struct drm_file *file_priv) { @@ -172,7 +172,7 @@ int via_mem_free(struct drm_device *dev, void *data, struct drm_file *file_priv) } -void via_reclaim_buffers_locked(struct drm_device * dev, +void via_reclaim_buffers_locked(struct drm_device *dev, struct drm_file *file_priv) { drm_via_private_t *dev_priv = dev->dev_private; @@ -183,9 +183,8 @@ void via_reclaim_buffers_locked(struct drm_device * dev, return; } - if (dev->driver->dma_quiescent) { + if (dev->driver->dma_quiescent) dev->driver->dma_quiescent(dev); - } drm_sman_owner_cleanup(&dev_priv->sman, (unsigned long)file_priv); mutex_unlock(&dev->struct_mutex); diff --git a/drivers/gpu/drm/via/via_verifier.c b/drivers/gpu/drm/via/via_verifier.c index 46a5791..48957b8 100644 --- a/drivers/gpu/drm/via/via_verifier.c +++ b/drivers/gpu/drm/via/via_verifier.c @@ -235,7 +235,7 @@ static hazard_t table2[256]; static hazard_t table3[256]; static __inline__ int -eat_words(const uint32_t ** buf, const uint32_t * buf_end, unsigned num_words) +eat_words(const uint32_t **buf, const uint32_t *buf_end, unsigned num_words) { if ((buf_end - *buf) >= num_words) { *buf += num_words; @@ -252,7 +252,7 @@ eat_words(const uint32_t ** buf, const uint32_t * buf_end, unsigned num_words) static __inline__ drm_local_map_t *via_drm_lookup_agp_map(drm_via_state_t *seq, unsigned long offset, unsigned long size, - struct drm_device * dev) + struct drm_device *dev) { struct drm_map_list *r_list; drm_local_map_t *map = seq->map_cache; @@ -344,7 +344,7 @@ static __inline__ int finish_current_sequence(drm_via_state_t * cur_seq) } static __inline__ int -investigate_hazard(uint32_t cmd, hazard_t hz, drm_via_state_t * cur_seq) +investigate_hazard(uint32_t cmd, hazard_t hz, drm_via_state_t *cur_seq) { register uint32_t tmp, *tmp_addr; @@ -518,7 +518,7 @@ investigate_hazard(uint32_t cmd, hazard_t hz, drm_via_state_t * cur_seq) static __inline__ int via_check_prim_list(uint32_t const **buffer, const uint32_t * buf_end, - drm_via_state_t * cur_seq) + drm_via_state_t *cur_seq) { drm_via_private_t *dev_priv = (drm_via_private_t *) cur_seq->dev->dev_private; @@ -621,8 +621,8 @@ via_check_prim_list(uint32_t const **buffer, const uint32_t * buf_end, } static __inline__ verifier_state_t -via_check_header2(uint32_t const **buffer, const uint32_t * buf_end, - drm_via_state_t * hc_state) +via_check_header2(uint32_t const **buffer, const uint32_t *buf_end, + drm_via_state_t *hc_state) { uint32_t cmd; int hz_mode; @@ -706,16 +706,15 @@ via_check_header2(uint32_t const **buffer, const uint32_t * buf_end, return state_error; } } - if (hc_state->unfinished && finish_current_sequence(hc_state)) { + if (hc_state->unfinished && finish_current_sequence(hc_state)) return state_error; - } *buffer = buf; return state_command; } static __inline__ verifier_state_t -via_parse_header2(drm_via_private_t * dev_priv, uint32_t const **buffer, - const uint32_t * buf_end, int *fire_count) +via_parse_header2(drm_via_private_t *dev_priv, uint32_t const **buffer, + const uint32_t *buf_end, int *fire_count) { uint32_t cmd; const uint32_t *buf = *buffer; @@ -833,8 +832,8 @@ via_check_header1(uint32_t const **buffer, const uint32_t * buf_end) } static __inline__ verifier_state_t -via_parse_header1(drm_via_private_t * dev_priv, uint32_t const **buffer, - const uint32_t * buf_end) +via_parse_header1(drm_via_private_t *dev_priv, uint32_t const **buffer, + const uint32_t *buf_end) { register uint32_t cmd; const uint32_t *buf = *buffer; @@ -851,7 +850,7 @@ via_parse_header1(drm_via_private_t * dev_priv, uint32_t const **buffer, } static __inline__ verifier_state_t -via_check_vheader5(uint32_t const **buffer, const uint32_t * buf_end) +via_check_vheader5(uint32_t const **buffer, const uint32_t *buf_end) { uint32_t data; const uint32_t *buf = *buffer; @@ -884,8 +883,8 @@ via_check_vheader5(uint32_t const **buffer, const uint32_t * buf_end) } static __inline__ verifier_state_t -via_parse_vheader5(drm_via_private_t * dev_priv, uint32_t const **buffer, - const uint32_t * buf_end) +via_parse_vheader5(drm_via_private_t *dev_priv, uint32_t const **buffer, + const uint32_t *buf_end) { uint32_t addr, count, i; const uint32_t *buf = *buffer; @@ -893,9 +892,8 @@ via_parse_vheader5(drm_via_private_t * dev_priv, uint32_t const **buffer, addr = *buf++ & ~VIA_VIDEOMASK; i = count = *buf; buf += 3; - while (i--) { + while (i--) VIA_WRITE(addr, *buf++); - } if (count & 3) buf += 4 - (count & 3); *buffer = buf; @@ -940,8 +938,8 @@ via_check_vheader6(uint32_t const **buffer, const uint32_t * buf_end) } static __inline__ verifier_state_t -via_parse_vheader6(drm_via_private_t * dev_priv, uint32_t const **buffer, - const uint32_t * buf_end) +via_parse_vheader6(drm_via_private_t *dev_priv, uint32_t const **buffer, + const uint32_t *buf_end) { uint32_t addr, count, i; @@ -1037,7 +1035,7 @@ via_verify_command_stream(const uint32_t * buf, unsigned int size, } int -via_parse_command_stream(struct drm_device * dev, const uint32_t * buf, +via_parse_command_stream(struct drm_device *dev, const uint32_t *buf, unsigned int size) { @@ -1085,9 +1083,8 @@ via_parse_command_stream(struct drm_device * dev, const uint32_t * buf, return -EINVAL; } } - if (state == state_error) { + if (state == state_error) return -EINVAL; - } return 0; } @@ -1096,13 +1093,11 @@ setup_hazard_table(hz_init_t init_table[], hazard_t table[], int size) { int i; - for (i = 0; i < 256; ++i) { + for (i = 0; i < 256; ++i) table[i] = forbidden_command; - } - for (i = 0; i < size; ++i) { + for (i = 0; i < size; ++i) table[init_table[i].code] = init_table[i].hz; - } } void via_init_command_verifier(void) diff --git a/drivers/gpu/drm/via/via_verifier.h b/drivers/gpu/drm/via/via_verifier.h index d6f8214..26b6d36 100644 --- a/drivers/gpu/drm/via/via_verifier.h +++ b/drivers/gpu/drm/via/via_verifier.h @@ -54,8 +54,8 @@ typedef struct { const uint32_t *buf_start; } drm_via_state_t; -extern int via_verify_command_stream(const uint32_t * buf, unsigned int size, - struct drm_device * dev, int agp); +extern int via_verify_command_stream(const uint32_t *buf, unsigned int size, + struct drm_device *dev, int agp); extern int via_parse_command_stream(struct drm_device *dev, const uint32_t *buf, unsigned int size); diff --git a/drivers/gpu/drm/via/via_video.c b/drivers/gpu/drm/via/via_video.c index 6efac81..675d311 100644 --- a/drivers/gpu/drm/via/via_video.c +++ b/drivers/gpu/drm/via/via_video.c @@ -29,7 +29,7 @@ #include "via_drm.h" #include "via_drv.h" -void via_init_futex(drm_via_private_t * dev_priv) +void via_init_futex(drm_via_private_t *dev_priv) { unsigned int i; @@ -41,11 +41,11 @@ void via_init_futex(drm_via_private_t * dev_priv) } } -void via_cleanup_futex(drm_via_private_t * dev_priv) +void via_cleanup_futex(drm_via_private_t *dev_priv) { } -void via_release_futex(drm_via_private_t * dev_priv, int context) +void via_release_futex(drm_via_private_t *dev_priv, int context) { unsigned int i; volatile int *lock; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index b793c8c..9dd395b 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -764,7 +764,7 @@ static struct drm_driver driver = { static int vmw_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { - return drm_get_dev(pdev, ent, &driver); + return drm_get_pci_dev(pdev, ent, &driver); } static int __init vmwgfx_init(void) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index eaad520..429f917 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -164,7 +164,7 @@ struct vmw_vga_topology_state { struct vmw_private { struct ttm_bo_device bdev; struct ttm_bo_global_ref bo_global_ref; - struct ttm_global_reference mem_global_ref; + struct drm_global_reference mem_global_ref; struct vmw_fifo_state fifo; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c index b0866f0..870967a 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c @@ -528,7 +528,7 @@ int vmw_fb_init(struct vmw_private *vmw_priv) * Dirty & Deferred IO */ par->dirty.x1 = par->dirty.x2 = 0; - par->dirty.y1 = par->dirty.y1 = 0; + par->dirty.y1 = par->dirty.y2 = 0; par->dirty.active = true; spin_lock_init(&par->dirty.lock); info->fbdefio = &vmw_defio; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_glue.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_glue.c index e3df4ad..8312328 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_glue.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ttm_glue.c @@ -44,29 +44,29 @@ int vmw_mmap(struct file *filp, struct vm_area_struct *vma) return ttm_bo_mmap(filp, vma, &dev_priv->bdev); } -static int vmw_ttm_mem_global_init(struct ttm_global_reference *ref) +static int vmw_ttm_mem_global_init(struct drm_global_reference *ref) { DRM_INFO("global init.\n"); return ttm_mem_global_init(ref->object); } -static void vmw_ttm_mem_global_release(struct ttm_global_reference *ref) +static void vmw_ttm_mem_global_release(struct drm_global_reference *ref) { ttm_mem_global_release(ref->object); } int vmw_ttm_global_init(struct vmw_private *dev_priv) { - struct ttm_global_reference *global_ref; + struct drm_global_reference *global_ref; int ret; global_ref = &dev_priv->mem_global_ref; - global_ref->global_type = TTM_GLOBAL_TTM_MEM; + global_ref->global_type = DRM_GLOBAL_TTM_MEM; global_ref->size = sizeof(struct ttm_mem_global); global_ref->init = &vmw_ttm_mem_global_init; global_ref->release = &vmw_ttm_mem_global_release; - ret = ttm_global_item_ref(global_ref); + ret = drm_global_item_ref(global_ref); if (unlikely(ret != 0)) { DRM_ERROR("Failed setting up TTM memory accounting.\n"); return ret; @@ -75,11 +75,11 @@ int vmw_ttm_global_init(struct vmw_private *dev_priv) dev_priv->bo_global_ref.mem_glob = dev_priv->mem_global_ref.object; global_ref = &dev_priv->bo_global_ref.ref; - global_ref->global_type = TTM_GLOBAL_TTM_BO; + global_ref->global_type = DRM_GLOBAL_TTM_BO; global_ref->size = sizeof(struct ttm_bo_global); global_ref->init = &ttm_bo_global_init; global_ref->release = &ttm_bo_global_release; - ret = ttm_global_item_ref(global_ref); + ret = drm_global_item_ref(global_ref); if (unlikely(ret != 0)) { DRM_ERROR("Failed setting up TTM buffer objects.\n"); @@ -88,12 +88,12 @@ int vmw_ttm_global_init(struct vmw_private *dev_priv) return 0; out_no_bo: - ttm_global_item_unref(&dev_priv->mem_global_ref); + drm_global_item_unref(&dev_priv->mem_global_ref); return ret; } void vmw_ttm_global_release(struct vmw_private *dev_priv) { - ttm_global_item_unref(&dev_priv->bo_global_ref.ref); - ttm_global_item_unref(&dev_priv->mem_global_ref); + drm_global_item_unref(&dev_priv->bo_global_ref.ref); + drm_global_item_unref(&dev_priv->mem_global_ref); } diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index c57e530..4d382ae 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -407,6 +407,13 @@ config SENSORS_CORETEMP sensor inside your CPU. Most of the family 6 CPUs are supported. Check documentation/driver for details. +config SENSORS_PKGTEMP + tristate "Intel processor package temperature sensor" + depends on X86 && PCI && EXPERIMENTAL + help + If you say yes here you get support for the package level temperature + sensor inside your CPU. Check documentation/driver for details. + config SENSORS_IBMAEM tristate "IBM Active Energy Manager temperature/power sensors and control" select IPMI_SI diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index c505774..9103bd6 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -39,6 +39,7 @@ obj-$(CONFIG_SENSORS_AMS) += ams/ obj-$(CONFIG_SENSORS_ASC7621) += asc7621.o obj-$(CONFIG_SENSORS_ATXP1) += atxp1.o obj-$(CONFIG_SENSORS_CORETEMP) += coretemp.o +obj-$(CONFIG_SENSORS_PKGTEMP) += pkgtemp.o obj-$(CONFIG_SENSORS_DME1737) += dme1737.o obj-$(CONFIG_SENSORS_DS1621) += ds1621.o obj-$(CONFIG_SENSORS_EMC1403) += emc1403.o diff --git a/drivers/hwmon/pkgtemp.c b/drivers/hwmon/pkgtemp.c new file mode 100644 index 0000000..74157fc --- /dev/null +++ b/drivers/hwmon/pkgtemp.c @@ -0,0 +1,456 @@ +/* + * pkgtemp.c - Linux kernel module for processor package hardware monitoring + * + * Copyright (C) 2010 Fenghua Yu <fenghua.yu@intel.com> + * + * Inspired from many hwmon drivers especially coretemp. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + */ + +#include <linux/module.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/jiffies.h> +#include <linux/hwmon.h> +#include <linux/sysfs.h> +#include <linux/hwmon-sysfs.h> +#include <linux/err.h> +#include <linux/mutex.h> +#include <linux/list.h> +#include <linux/platform_device.h> +#include <linux/cpu.h> +#include <linux/pci.h> +#include <asm/msr.h> +#include <asm/processor.h> + +#define DRVNAME "pkgtemp" + +enum { SHOW_TEMP, SHOW_TJMAX, SHOW_TTARGET, SHOW_LABEL, SHOW_NAME }; + +/* + * Functions declaration + */ + +static struct pkgtemp_data *pkgtemp_update_device(struct device *dev); + +struct pkgtemp_data { + struct device *hwmon_dev; + struct mutex update_lock; + const char *name; + u32 id; + u16 phys_proc_id; + char valid; /* zero until following fields are valid */ + unsigned long last_updated; /* in jiffies */ + int temp; + int tjmax; + int ttarget; + u8 alarm; +}; + +/* + * Sysfs stuff + */ + +static ssize_t show_name(struct device *dev, struct device_attribute + *devattr, char *buf) +{ + int ret; + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct pkgtemp_data *data = dev_get_drvdata(dev); + + if (attr->index == SHOW_NAME) + ret = sprintf(buf, "%s\n", data->name); + else /* show label */ + ret = sprintf(buf, "physical id %d\n", + data->phys_proc_id); + return ret; +} + +static ssize_t show_alarm(struct device *dev, struct device_attribute + *devattr, char *buf) +{ + struct pkgtemp_data *data = pkgtemp_update_device(dev); + /* read the Out-of-spec log, never clear */ + return sprintf(buf, "%d\n", data->alarm); +} + +static ssize_t show_temp(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct pkgtemp_data *data = pkgtemp_update_device(dev); + int err = 0; + + if (attr->index == SHOW_TEMP) + err = data->valid ? sprintf(buf, "%d\n", data->temp) : -EAGAIN; + else if (attr->index == SHOW_TJMAX) + err = sprintf(buf, "%d\n", data->tjmax); + else + err = sprintf(buf, "%d\n", data->ttarget); + return err; +} + +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, SHOW_TEMP); +static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO, show_temp, NULL, SHOW_TJMAX); +static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO, show_temp, NULL, SHOW_TTARGET); +static DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL); +static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, show_name, NULL, SHOW_LABEL); +static SENSOR_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, SHOW_NAME); + +static struct attribute *pkgtemp_attributes[] = { + &sensor_dev_attr_name.dev_attr.attr, + &sensor_dev_attr_temp1_label.dev_attr.attr, + &dev_attr_temp1_crit_alarm.attr, + &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_temp1_crit.dev_attr.attr, + NULL +}; + +static const struct attribute_group pkgtemp_group = { + .attrs = pkgtemp_attributes, +}; + +static struct pkgtemp_data *pkgtemp_update_device(struct device *dev) +{ + struct pkgtemp_data *data = dev_get_drvdata(dev); + unsigned int cpu; + int err; + + mutex_lock(&data->update_lock); + + if (!data->valid || time_after(jiffies, data->last_updated + HZ)) { + u32 eax, edx; + + data->valid = 0; + cpu = data->id; + err = rdmsr_on_cpu(cpu, MSR_IA32_PACKAGE_THERM_STATUS, + &eax, &edx); + if (!err) { + data->alarm = (eax >> 5) & 1; + data->temp = data->tjmax - (((eax >> 16) + & 0x7f) * 1000); + data->valid = 1; + } else + dev_dbg(dev, "Temperature data invalid (0x%x)\n", eax); + + data->last_updated = jiffies; + } + + mutex_unlock(&data->update_lock); + return data; +} + +static int get_tjmax(int cpu, struct device *dev) +{ + int default_tjmax = 100000; + int err; + u32 eax, edx; + u32 val; + + /* IA32_TEMPERATURE_TARGET contains the TjMax value */ + err = rdmsr_safe_on_cpu(cpu, MSR_IA32_TEMPERATURE_TARGET, &eax, &edx); + if (!err) { + val = (eax >> 16) & 0xff; + if ((val > 80) && (val < 120)) { + dev_info(dev, "TjMax is %d C.\n", val); + return val * 1000; + } + } + dev_warn(dev, "Unable to read TjMax from CPU.\n"); + return default_tjmax; +} + +static int __devinit pkgtemp_probe(struct platform_device *pdev) +{ + struct pkgtemp_data *data; + int err; + u32 eax, edx; +#ifdef CONFIG_SMP + struct cpuinfo_x86 *c = &cpu_data(pdev->id); +#endif + + data = kzalloc(sizeof(struct pkgtemp_data), GFP_KERNEL); + if (!data) { + err = -ENOMEM; + dev_err(&pdev->dev, "Out of memory\n"); + goto exit; + } + + data->id = pdev->id; +#ifdef CONFIG_SMP + data->phys_proc_id = c->phys_proc_id; +#endif + data->name = "pkgtemp"; + mutex_init(&data->update_lock); + + /* test if we can access the THERM_STATUS MSR */ + err = rdmsr_safe_on_cpu(data->id, MSR_IA32_PACKAGE_THERM_STATUS, + &eax, &edx); + if (err) { + dev_err(&pdev->dev, + "Unable to access THERM_STATUS MSR, giving up\n"); + goto exit_free; + } + + data->tjmax = get_tjmax(data->id, &pdev->dev); + platform_set_drvdata(pdev, data); + + err = rdmsr_safe_on_cpu(data->id, MSR_IA32_TEMPERATURE_TARGET, + &eax, &edx); + if (err) { + dev_warn(&pdev->dev, "Unable to read" + " IA32_TEMPERATURE_TARGET MSR\n"); + } else { + data->ttarget = data->tjmax - (((eax >> 8) & 0xff) * 1000); + err = device_create_file(&pdev->dev, + &sensor_dev_attr_temp1_max.dev_attr); + if (err) + goto exit_free; + } + + err = sysfs_create_group(&pdev->dev.kobj, &pkgtemp_group); + if (err) + goto exit_free; + + data->hwmon_dev = hwmon_device_register(&pdev->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); + dev_err(&pdev->dev, "Class registration failed (%d)\n", + err); + goto exit_class; + } + + return 0; + +exit_class: + sysfs_remove_group(&pdev->dev.kobj, &pkgtemp_group); +exit_free: + kfree(data); +exit: + return err; +} + +static int __devexit pkgtemp_remove(struct platform_device *pdev) +{ + struct pkgtemp_data *data = platform_get_drvdata(pdev); + + hwmon_device_unregister(data->hwmon_dev); + sysfs_remove_group(&pdev->dev.kobj, &pkgtemp_group); + platform_set_drvdata(pdev, NULL); + kfree(data); + return 0; +} + +static struct platform_driver pkgtemp_driver = { + .driver = { + .owner = THIS_MODULE, + .name = DRVNAME, + }, + .probe = pkgtemp_probe, + .remove = __devexit_p(pkgtemp_remove), +}; + +struct pdev_entry { + struct list_head list; + struct platform_device *pdev; + unsigned int cpu; +#ifdef CONFIG_SMP + u16 phys_proc_id; +#endif +}; + +static LIST_HEAD(pdev_list); +static DEFINE_MUTEX(pdev_list_mutex); + +static int __cpuinit pkgtemp_device_add(unsigned int cpu) +{ + int err; + struct platform_device *pdev; + struct pdev_entry *pdev_entry; +#ifdef CONFIG_SMP + struct cpuinfo_x86 *c = &cpu_data(cpu); +#endif + + mutex_lock(&pdev_list_mutex); + +#ifdef CONFIG_SMP + /* Only keep the first entry in each package */ + list_for_each_entry(pdev_entry, &pdev_list, list) { + if (c->phys_proc_id == pdev_entry->phys_proc_id) { + err = 0; /* Not an error */ + goto exit; + } + } +#endif + + pdev = platform_device_alloc(DRVNAME, cpu); + if (!pdev) { + err = -ENOMEM; + printk(KERN_ERR DRVNAME ": Device allocation failed\n"); + goto exit; + } + + pdev_entry = kzalloc(sizeof(struct pdev_entry), GFP_KERNEL); + if (!pdev_entry) { + err = -ENOMEM; + goto exit_device_put; + } + + err = platform_device_add(pdev); + if (err) { + printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n", + err); + goto exit_device_free; + } + +#ifdef CONFIG_SMP + pdev_entry->phys_proc_id = c->phys_proc_id; +#endif + pdev_entry->pdev = pdev; + pdev_entry->cpu = cpu; + list_add_tail(&pdev_entry->list, &pdev_list); + mutex_unlock(&pdev_list_mutex); + + return 0; + +exit_device_free: + kfree(pdev_entry); +exit_device_put: + platform_device_put(pdev); +exit: + mutex_unlock(&pdev_list_mutex); + return err; +} + +#ifdef CONFIG_HOTPLUG_CPU +static void pkgtemp_device_remove(unsigned int cpu) +{ + struct pdev_entry *p, *n; + unsigned int i; + int err; + + mutex_lock(&pdev_list_mutex); + list_for_each_entry_safe(p, n, &pdev_list, list) { + if (p->cpu != cpu) + continue; + + platform_device_unregister(p->pdev); + list_del(&p->list); + kfree(p); + for_each_cpu(i, cpu_core_mask(cpu)) { + if (i != cpu) { + err = pkgtemp_device_add(i); + if (!err) + break; + } + } + break; + } + mutex_unlock(&pdev_list_mutex); +} + +static int __cpuinit pkgtemp_cpu_callback(struct notifier_block *nfb, + unsigned long action, void *hcpu) +{ + unsigned int cpu = (unsigned long) hcpu; + + switch (action) { + case CPU_ONLINE: + case CPU_DOWN_FAILED: + pkgtemp_device_add(cpu); + break; + case CPU_DOWN_PREPARE: + pkgtemp_device_remove(cpu); + break; + } + return NOTIFY_OK; +} + +static struct notifier_block pkgtemp_cpu_notifier __refdata = { + .notifier_call = pkgtemp_cpu_callback, +}; +#endif /* !CONFIG_HOTPLUG_CPU */ + +static int __init pkgtemp_init(void) +{ + int i, err = -ENODEV; + struct pdev_entry *p, *n; + + /* quick check if we run Intel */ + if (cpu_data(0).x86_vendor != X86_VENDOR_INTEL) + goto exit; + + err = platform_driver_register(&pkgtemp_driver); + if (err) + goto exit; + + for_each_online_cpu(i) { + struct cpuinfo_x86 *c = &cpu_data(i); + + if (!cpu_has(c, X86_FEATURE_PTS)) + continue; + + err = pkgtemp_device_add(i); + if (err) + goto exit_devices_unreg; + } + if (list_empty(&pdev_list)) { + err = -ENODEV; + goto exit_driver_unreg; + } + +#ifdef CONFIG_HOTPLUG_CPU + register_hotcpu_notifier(&pkgtemp_cpu_notifier); +#endif + return 0; + +exit_devices_unreg: + mutex_lock(&pdev_list_mutex); + list_for_each_entry_safe(p, n, &pdev_list, list) { + platform_device_unregister(p->pdev); + list_del(&p->list); + kfree(p); + } + mutex_unlock(&pdev_list_mutex); +exit_driver_unreg: + platform_driver_unregister(&pkgtemp_driver); +exit: + return err; +} + +static void __exit pkgtemp_exit(void) +{ + struct pdev_entry *p, *n; +#ifdef CONFIG_HOTPLUG_CPU + unregister_hotcpu_notifier(&pkgtemp_cpu_notifier); +#endif + mutex_lock(&pdev_list_mutex); + list_for_each_entry_safe(p, n, &pdev_list, list) { + platform_device_unregister(p->pdev); + list_del(&p->list); + kfree(p); + } + mutex_unlock(&pdev_list_mutex); + platform_driver_unregister(&pkgtemp_driver); +} + +MODULE_AUTHOR("Fenghua Yu <fenghua.yu@intel.com>"); +MODULE_DESCRIPTION("Intel processor package temperature monitor"); +MODULE_LICENSE("GPL"); + +module_init(pkgtemp_init) +module_exit(pkgtemp_exit) diff --git a/drivers/hwmon/ultra45_env.c b/drivers/hwmon/ultra45_env.c index 5da5942..8964326 100644 --- a/drivers/hwmon/ultra45_env.c +++ b/drivers/hwmon/ultra45_env.c @@ -311,12 +311,12 @@ static struct of_platform_driver env_driver = { static int __init env_init(void) { - return of_register_driver(&env_driver, &of_bus_type); + return of_register_platform_driver(&env_driver); } static void __exit env_exit(void) { - of_unregister_driver(&env_driver); + of_unregister_platform_driver(&env_driver); } module_init(env_init); diff --git a/drivers/i2c/busses/i2c-cpm.c b/drivers/i2c/busses/i2c-cpm.c index b02b453..e591de1 100644 --- a/drivers/i2c/busses/i2c-cpm.c +++ b/drivers/i2c/busses/i2c-cpm.c @@ -652,6 +652,7 @@ static int __devinit cpm_i2c_probe(struct of_device *ofdev, cpm->adap = cpm_ops; i2c_set_adapdata(&cpm->adap, cpm); cpm->adap.dev.parent = &ofdev->dev; + cpm->adap.dev.of_node = of_node_get(ofdev->dev.of_node); result = cpm_i2c_setup(cpm); if (result) { @@ -676,11 +677,6 @@ static int __devinit cpm_i2c_probe(struct of_device *ofdev, dev_dbg(&ofdev->dev, "hw routines for %s registered.\n", cpm->adap.name); - /* - * register OF I2C devices - */ - of_register_i2c_devices(&cpm->adap, ofdev->dev.of_node); - return 0; out_shut: cpm_i2c_shutdown(cpm); diff --git a/drivers/i2c/busses/i2c-ibm_iic.c b/drivers/i2c/busses/i2c-ibm_iic.c index bf34413..1168d61 100644 --- a/drivers/i2c/busses/i2c-ibm_iic.c +++ b/drivers/i2c/busses/i2c-ibm_iic.c @@ -745,6 +745,7 @@ static int __devinit iic_probe(struct of_device *ofdev, /* Register it with i2c layer */ adap = &dev->adap; adap->dev.parent = &ofdev->dev; + adap->dev.of_node = of_node_get(np); strlcpy(adap->name, "IBM IIC", sizeof(adap->name)); i2c_set_adapdata(adap, dev); adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD; @@ -760,9 +761,6 @@ static int __devinit iic_probe(struct of_device *ofdev, dev_info(&ofdev->dev, "using %s mode\n", dev->fast_mode ? "fast (400 kHz)" : "standard (100 kHz)"); - /* Now register all the child nodes */ - of_register_i2c_devices(adap, np); - return 0; error_cleanup: diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c index 54247d4..6545d1c 100644 --- a/drivers/i2c/busses/i2c-mpc.c +++ b/drivers/i2c/busses/i2c-mpc.c @@ -625,13 +625,13 @@ static int __devinit fsl_i2c_probe(struct of_device *op, i2c->adap = mpc_ops; i2c_set_adapdata(&i2c->adap, i2c); i2c->adap.dev.parent = &op->dev; + i2c->adap.dev.of_node = of_node_get(op->dev.of_node); result = i2c_add_adapter(&i2c->adap); if (result < 0) { dev_err(i2c->dev, "failed to add adapter\n"); goto fail_add; } - of_register_i2c_devices(&i2c->adap, op->dev.of_node); return result; diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 0815e10..df937df 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -30,6 +30,8 @@ #include <linux/init.h> #include <linux/idr.h> #include <linux/mutex.h> +#include <linux/of_i2c.h> +#include <linux/of_device.h> #include <linux/completion.h> #include <linux/hardirq.h> #include <linux/irqflags.h> @@ -70,6 +72,10 @@ static int i2c_device_match(struct device *dev, struct device_driver *drv) if (!client) return 0; + /* Attempt an OF style match */ + if (of_driver_match_device(dev, drv)) + return 1; + driver = to_i2c_driver(drv); /* match on an id table if there is one */ if (driver->id_table) @@ -790,6 +796,9 @@ static int i2c_register_adapter(struct i2c_adapter *adap) if (adap->nr < __i2c_first_dynamic_bus_num) i2c_scan_static_board_info(adap); + /* Register devices from the device tree */ + of_i2c_register_devices(adap); + /* Notify drivers */ mutex_lock(&core_lock); dummy = bus_for_each_drv(&i2c_bus_type, NULL, adap, diff --git a/drivers/input/misc/sparcspkr.c b/drivers/input/misc/sparcspkr.c index 1dacae4..f3bb92e 100644 --- a/drivers/input/misc/sparcspkr.c +++ b/drivers/input/misc/sparcspkr.c @@ -353,14 +353,12 @@ static struct of_platform_driver grover_beep_driver = { static int __init sparcspkr_init(void) { - int err = of_register_driver(&bbc_beep_driver, - &of_platform_bus_type); + int err = of_register_platform_driver(&bbc_beep_driver); if (!err) { - err = of_register_driver(&grover_beep_driver, - &of_platform_bus_type); + err = of_register_platform_driver(&grover_beep_driver); if (err) - of_unregister_driver(&bbc_beep_driver); + of_unregister_platform_driver(&bbc_beep_driver); } return err; @@ -368,8 +366,8 @@ static int __init sparcspkr_init(void) static void __exit sparcspkr_exit(void) { - of_unregister_driver(&bbc_beep_driver); - of_unregister_driver(&grover_beep_driver); + of_unregister_platform_driver(&bbc_beep_driver); + of_unregister_platform_driver(&grover_beep_driver); } module_init(sparcspkr_init); diff --git a/drivers/input/serio/i8042-sparcio.h b/drivers/input/serio/i8042-sparcio.h index 04e32f2..cb2a24b 100644 --- a/drivers/input/serio/i8042-sparcio.h +++ b/drivers/input/serio/i8042-sparcio.h @@ -58,9 +58,9 @@ static int __devinit sparc_i8042_probe(struct of_device *op, const struct of_dev if (!strcmp(dp->name, OBP_PS2KBD_NAME1) || !strcmp(dp->name, OBP_PS2KBD_NAME2)) { struct of_device *kbd = of_find_device_by_node(dp); - unsigned int irq = kbd->irqs[0]; + unsigned int irq = kbd->archdata.irqs[0]; if (irq == 0xffffffff) - irq = op->irqs[0]; + irq = op->archdata.irqs[0]; i8042_kbd_irq = irq; kbd_iobase = of_ioremap(&kbd->resource[0], 0, 8, "kbd"); @@ -68,9 +68,9 @@ static int __devinit sparc_i8042_probe(struct of_device *op, const struct of_dev } else if (!strcmp(dp->name, OBP_PS2MS_NAME1) || !strcmp(dp->name, OBP_PS2MS_NAME2)) { struct of_device *ms = of_find_device_by_node(dp); - unsigned int irq = ms->irqs[0]; + unsigned int irq = ms->archdata.irqs[0]; if (irq == 0xffffffff) - irq = op->irqs[0]; + irq = op->archdata.irqs[0]; i8042_aux_irq = irq; } @@ -116,8 +116,7 @@ static int __init i8042_platform_init(void) if (!kbd_iobase) return -ENODEV; } else { - int err = of_register_driver(&sparc_i8042_driver, - &of_bus_type); + int err = of_register_platform_driver(&sparc_i8042_driver); if (err) return err; @@ -141,7 +140,7 @@ static inline void i8042_platform_exit(void) struct device_node *root = of_find_node_by_path("/"); if (strcmp(root->name, "SUNW,JavaStation-1")) - of_unregister_driver(&sparc_i8042_driver); + of_unregister_platform_driver(&sparc_i8042_driver); } #else /* !CONFIG_PCI */ diff --git a/drivers/input/xen-kbdfront.c b/drivers/input/xen-kbdfront.c index e140816..ebb1190 100644 --- a/drivers/input/xen-kbdfront.c +++ b/drivers/input/xen-kbdfront.c @@ -339,7 +339,7 @@ static struct xenbus_driver xenkbd_driver = { static int __init xenkbd_init(void) { - if (!xen_domain()) + if (!xen_pv_domain()) return -ENODEV; /* Nothing to do if running in dom0. */ diff --git a/drivers/macintosh/macio_sysfs.c b/drivers/macintosh/macio_sysfs.c index 6999ce5..6024038 100644 --- a/drivers/macintosh/macio_sysfs.c +++ b/drivers/macintosh/macio_sysfs.c @@ -41,10 +41,7 @@ compatible_show (struct device *dev, struct device_attribute *attr, char *buf) static ssize_t modalias_show (struct device *dev, struct device_attribute *attr, char *buf) { - struct of_device *ofdev = to_of_device(dev); - int len; - - len = of_device_get_modalias(ofdev, buf, PAGE_SIZE - 2); + int len = of_device_get_modalias(dev, buf, PAGE_SIZE - 2); buf[len] = '\n'; buf[len+1] = 0; diff --git a/drivers/mmc/host/mmc_spi.c b/drivers/mmc/host/mmc_spi.c index ad847a2..7b0f3ef 100644 --- a/drivers/mmc/host/mmc_spi.c +++ b/drivers/mmc/host/mmc_spi.c @@ -1533,12 +1533,20 @@ static int __devexit mmc_spi_remove(struct spi_device *spi) return 0; } +#if defined(CONFIG_OF) +static struct of_device_id mmc_spi_of_match_table[] __devinitdata = { + { .compatible = "mmc-spi-slot", }, +}; +#endif static struct spi_driver mmc_spi_driver = { .driver = { .name = "mmc_spi", .bus = &spi_bus_type, .owner = THIS_MODULE, +#if defined(CONFIG_OF) + .of_match_table = mmc_spi_of_match_table, +#endif }, .probe = mmc_spi_probe, .remove = __devexit_p(mmc_spi_remove), diff --git a/drivers/mtd/maps/sun_uflash.c b/drivers/mtd/maps/sun_uflash.c index 0391c25..8984236 100644 --- a/drivers/mtd/maps/sun_uflash.c +++ b/drivers/mtd/maps/sun_uflash.c @@ -160,12 +160,12 @@ static struct of_platform_driver uflash_driver = { static int __init uflash_init(void) { - return of_register_driver(&uflash_driver, &of_bus_type); + return of_register_platform_driver(&uflash_driver); } static void __exit uflash_exit(void) { - of_unregister_driver(&uflash_driver); + of_unregister_platform_driver(&uflash_driver); } module_init(uflash_init); diff --git a/drivers/net/fsl_pq_mdio.c b/drivers/net/fsl_pq_mdio.c index b4c41d7..f53f850 100644 --- a/drivers/net/fsl_pq_mdio.c +++ b/drivers/net/fsl_pq_mdio.c @@ -35,6 +35,7 @@ #include <linux/mii.h> #include <linux/phy.h> #include <linux/of.h> +#include <linux/of_address.h> #include <linux/of_mdio.h> #include <linux/of_platform.h> diff --git a/drivers/net/ibm_newemac/core.c b/drivers/net/ibm_newemac/core.c index 0f1d4e9..eeec7bc 100644 --- a/drivers/net/ibm_newemac/core.c +++ b/drivers/net/ibm_newemac/core.c @@ -2339,11 +2339,11 @@ static int __devinit emac_wait_deps(struct emac_instance *dev) deps[EMAC_DEP_MDIO_IDX].phandle = dev->mdio_ph; if (dev->blist && dev->blist > emac_boot_list) deps[EMAC_DEP_PREV_IDX].phandle = 0xffffffffu; - bus_register_notifier(&of_platform_bus_type, &emac_of_bus_notifier); + bus_register_notifier(&platform_bus_type, &emac_of_bus_notifier); wait_event_timeout(emac_probe_wait, emac_check_deps(dev, deps), EMAC_PROBE_DEP_TIMEOUT); - bus_unregister_notifier(&of_platform_bus_type, &emac_of_bus_notifier); + bus_unregister_notifier(&platform_bus_type, &emac_of_bus_notifier); err = emac_check_deps(dev, deps) ? 0 : -ENODEV; for (i = 0; i < EMAC_DEP_COUNT; i++) { if (deps[i].node) diff --git a/drivers/net/myri_sbus.c b/drivers/net/myri_sbus.c index 1a57c3d..04e552a 100644 --- a/drivers/net/myri_sbus.c +++ b/drivers/net/myri_sbus.c @@ -1079,7 +1079,7 @@ static int __devinit myri_sbus_probe(struct of_device *op, const struct of_devic mp->dev = dev; dev->watchdog_timeo = 5*HZ; - dev->irq = op->irqs[0]; + dev->irq = op->archdata.irqs[0]; dev->netdev_ops = &myri_ops; /* Register interrupt handler now. */ @@ -1172,12 +1172,12 @@ static struct of_platform_driver myri_sbus_driver = { static int __init myri_sbus_init(void) { - return of_register_driver(&myri_sbus_driver, &of_bus_type); + return of_register_platform_driver(&myri_sbus_driver); } static void __exit myri_sbus_exit(void) { - of_unregister_driver(&myri_sbus_driver); + of_unregister_platform_driver(&myri_sbus_driver); } module_init(myri_sbus_init); diff --git a/drivers/net/niu.c b/drivers/net/niu.c index b9b9508..404f2d55 100644 --- a/drivers/net/niu.c +++ b/drivers/net/niu.c @@ -28,10 +28,7 @@ #include <linux/slab.h> #include <linux/io.h> - -#ifdef CONFIG_SPARC64 #include <linux/of_device.h> -#endif #include "niu.h" @@ -9114,12 +9111,12 @@ static int __devinit niu_n2_irq_init(struct niu *np, u8 *ldg_num_map) if (!int_prop) return -ENODEV; - for (i = 0; i < op->num_irqs; i++) { + for (i = 0; i < op->archdata.num_irqs; i++) { ldg_num_map[i] = int_prop[i]; - np->ldg[i].irq = op->irqs[i]; + np->ldg[i].irq = op->archdata.irqs[i]; } - np->num_ldg = op->num_irqs; + np->num_ldg = op->archdata.num_irqs; return 0; #else @@ -10249,14 +10246,14 @@ static int __init niu_init(void) niu_debug = netif_msg_init(debug, NIU_MSG_DEFAULT); #ifdef CONFIG_SPARC64 - err = of_register_driver(&niu_of_driver, &of_bus_type); + err = of_register_platform_driver(&niu_of_driver); #endif if (!err) { err = pci_register_driver(&niu_pci_driver); #ifdef CONFIG_SPARC64 if (err) - of_unregister_driver(&niu_of_driver); + of_unregister_platform_driver(&niu_of_driver); #endif } @@ -10267,7 +10264,7 @@ static void __exit niu_exit(void) { pci_unregister_driver(&niu_pci_driver); #ifdef CONFIG_SPARC64 - of_unregister_driver(&niu_of_driver); + of_unregister_platform_driver(&niu_of_driver); #endif } diff --git a/drivers/net/niu.h b/drivers/net/niu.h index d671546..a41fa8e 100644 --- a/drivers/net/niu.h +++ b/drivers/net/niu.h @@ -3236,7 +3236,7 @@ struct niu_phy_ops { int (*link_status)(struct niu *np, int *); }; -struct of_device; +struct platform_device; struct niu { void __iomem *regs; struct net_device *dev; @@ -3297,7 +3297,7 @@ struct niu { struct niu_vpd vpd; u32 eeprom_len; - struct of_device *op; + struct platform_device *op; void __iomem *vir_regs_1; void __iomem *vir_regs_2; }; diff --git a/drivers/net/sunbmac.c b/drivers/net/sunbmac.c index 367e96f..09c071b 100644 --- a/drivers/net/sunbmac.c +++ b/drivers/net/sunbmac.c @@ -1201,7 +1201,7 @@ static int __devinit bigmac_ether_init(struct of_device *op, dev->watchdog_timeo = 5*HZ; /* Finish net device registration. */ - dev->irq = bp->bigmac_op->irqs[0]; + dev->irq = bp->bigmac_op->archdata.irqs[0]; dev->dma = 0; if (register_netdev(dev)) { @@ -1301,12 +1301,12 @@ static struct of_platform_driver bigmac_sbus_driver = { static int __init bigmac_init(void) { - return of_register_driver(&bigmac_sbus_driver, &of_bus_type); + return of_register_platform_driver(&bigmac_sbus_driver); } static void __exit bigmac_exit(void) { - of_unregister_driver(&bigmac_sbus_driver); + of_unregister_platform_driver(&bigmac_sbus_driver); } module_init(bigmac_init); diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c index 3d9650b..eec443f 100644 --- a/drivers/net/sunhme.c +++ b/drivers/net/sunhme.c @@ -2561,7 +2561,7 @@ static int __init quattro_sbus_register_irqs(void) if (skip) continue; - err = request_irq(op->irqs[0], + err = request_irq(op->archdata.irqs[0], quattro_sbus_interrupt, IRQF_SHARED, "Quattro", qp); @@ -2590,7 +2590,7 @@ static void quattro_sbus_free_irqs(void) if (skip) continue; - free_irq(op->irqs[0], qp); + free_irq(op->archdata.irqs[0], qp); } } #endif /* CONFIG_SBUS */ @@ -2790,7 +2790,7 @@ static int __devinit happy_meal_sbus_probe_one(struct of_device *op, int is_qfe) /* Happy Meal can do it all... */ dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM; - dev->irq = op->irqs[0]; + dev->irq = op->archdata.irqs[0]; #if defined(CONFIG_SBUS) && defined(CONFIG_PCI) /* Hook up SBUS register/descriptor accessors. */ @@ -3304,7 +3304,7 @@ static int __init happy_meal_sbus_init(void) { int err; - err = of_register_driver(&hme_sbus_driver, &of_bus_type); + err = of_register_platform_driver(&hme_sbus_driver); if (!err) err = quattro_sbus_register_irqs(); @@ -3313,7 +3313,7 @@ static int __init happy_meal_sbus_init(void) static void happy_meal_sbus_exit(void) { - of_unregister_driver(&hme_sbus_driver); + of_unregister_platform_driver(&hme_sbus_driver); quattro_sbus_free_irqs(); while (qfe_sbus_list) { diff --git a/drivers/net/sunlance.c b/drivers/net/sunlance.c index 7d9c33d..ee364fa 100644 --- a/drivers/net/sunlance.c +++ b/drivers/net/sunlance.c @@ -1474,7 +1474,7 @@ no_link_test: dev->ethtool_ops = &sparc_lance_ethtool_ops; dev->netdev_ops = &sparc_lance_ops; - dev->irq = op->irqs[0]; + dev->irq = op->archdata.irqs[0]; /* We cannot sleep if the chip is busy during a * multicast list update event, because such events @@ -1558,12 +1558,12 @@ static struct of_platform_driver sunlance_sbus_driver = { /* Find all the lance cards on the system and initialize them */ static int __init sparc_lance_init(void) { - return of_register_driver(&sunlance_sbus_driver, &of_bus_type); + return of_register_platform_driver(&sunlance_sbus_driver); } static void __exit sparc_lance_exit(void) { - of_unregister_driver(&sunlance_sbus_driver); + of_unregister_platform_driver(&sunlance_sbus_driver); } module_init(sparc_lance_init); diff --git a/drivers/net/sunqe.c b/drivers/net/sunqe.c index 72b579c..5f84a5d 100644 --- a/drivers/net/sunqe.c +++ b/drivers/net/sunqe.c @@ -803,7 +803,7 @@ static struct sunqec * __devinit get_qec(struct of_device *child) qec_init_once(qecp, op); - if (request_irq(op->irqs[0], qec_interrupt, + if (request_irq(op->archdata.irqs[0], qec_interrupt, IRQF_SHARED, "qec", (void *) qecp)) { printk(KERN_ERR "qec: Can't register irq.\n"); goto fail; @@ -901,7 +901,7 @@ static int __devinit qec_ether_init(struct of_device *op) SET_NETDEV_DEV(dev, &op->dev); dev->watchdog_timeo = 5*HZ; - dev->irq = op->irqs[0]; + dev->irq = op->archdata.irqs[0]; dev->dma = 0; dev->ethtool_ops = &qe_ethtool_ops; dev->netdev_ops = &qec_ops; @@ -988,18 +988,18 @@ static struct of_platform_driver qec_sbus_driver = { static int __init qec_init(void) { - return of_register_driver(&qec_sbus_driver, &of_bus_type); + return of_register_platform_driver(&qec_sbus_driver); } static void __exit qec_exit(void) { - of_unregister_driver(&qec_sbus_driver); + of_unregister_platform_driver(&qec_sbus_driver); while (root_qec_dev) { struct sunqec *next = root_qec_dev->next_module; struct of_device *op = root_qec_dev->op; - free_irq(op->irqs[0], (void *) root_qec_dev); + free_irq(op->archdata.irqs[0], (void *) root_qec_dev); of_iounmap(&op->resource[0], root_qec_dev->gregs, GLOB_REG_SIZE); kfree(root_qec_dev); diff --git a/drivers/net/xilinx_emaclite.c b/drivers/net/xilinx_emaclite.c index d04c5b2..b2c2f39 100644 --- a/drivers/net/xilinx_emaclite.c +++ b/drivers/net/xilinx_emaclite.c @@ -20,7 +20,7 @@ #include <linux/skbuff.h> #include <linux/io.h> #include <linux/slab.h> - +#include <linux/of_address.h> #include <linux/of_device.h> #include <linux/of_platform.h> #include <linux/of_mdio.h> diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig index 7cecc8f..6acbff3 100644 --- a/drivers/of/Kconfig +++ b/drivers/of/Kconfig @@ -1,35 +1,61 @@ -config OF_FLATTREE +config DTC + bool + +config OF bool + +menu "Flattened Device Tree and Open Firmware support" depends on OF +config PROC_DEVICETREE + bool "Support for device tree in /proc" + depends on PROC_FS && !SPARC + help + This option adds a device-tree directory under /proc which contains + an image of the device tree that the kernel copies from Open + Firmware or other boot firmware. If unsure, say Y here. + +config OF_FLATTREE + bool + select DTC + config OF_DYNAMIC def_bool y - depends on OF && PPC_OF + depends on PPC_OF + +config OF_ADDRESS + def_bool y + depends on !SPARC + +config OF_IRQ + def_bool y + depends on !SPARC config OF_DEVICE def_bool y - depends on OF && (SPARC || PPC_OF || MICROBLAZE) config OF_GPIO def_bool y - depends on OF && (PPC_OF || MICROBLAZE) && GPIOLIB + depends on GPIOLIB && !SPARC help OpenFirmware GPIO accessors config OF_I2C def_tristate I2C - depends on (PPC_OF || MICROBLAZE) && I2C + depends on I2C && !SPARC help OpenFirmware I2C accessors config OF_SPI def_tristate SPI - depends on OF && (PPC_OF || MICROBLAZE) && SPI + depends on SPI && !SPARC help OpenFirmware SPI accessors config OF_MDIO def_tristate PHYLIB - depends on OF && PHYLIB + depends on PHYLIB help OpenFirmware MDIO bus (Ethernet PHY) accessors + +endmenu # OF diff --git a/drivers/of/Makefile b/drivers/of/Makefile index f232cc9..0052c40 100644 --- a/drivers/of/Makefile +++ b/drivers/of/Makefile @@ -1,5 +1,7 @@ obj-y = base.o obj-$(CONFIG_OF_FLATTREE) += fdt.o +obj-$(CONFIG_OF_ADDRESS) += address.o +obj-$(CONFIG_OF_IRQ) += irq.o obj-$(CONFIG_OF_DEVICE) += device.o platform.o obj-$(CONFIG_OF_GPIO) += gpio.o obj-$(CONFIG_OF_I2C) += of_i2c.o diff --git a/drivers/of/address.c b/drivers/of/address.c new file mode 100644 index 0000000..fcadb72 --- /dev/null +++ b/drivers/of/address.c @@ -0,0 +1,595 @@ + +#include <linux/io.h> +#include <linux/ioport.h> +#include <linux/module.h> +#include <linux/of_address.h> +#include <linux/pci_regs.h> +#include <linux/string.h> + +/* Max address size we deal with */ +#define OF_MAX_ADDR_CELLS 4 +#define OF_CHECK_COUNTS(na, ns) ((na) > 0 && (na) <= OF_MAX_ADDR_CELLS && \ + (ns) > 0) + +static struct of_bus *of_match_bus(struct device_node *np); +static int __of_address_to_resource(struct device_node *dev, const u32 *addrp, + u64 size, unsigned int flags, + struct resource *r); + +/* Debug utility */ +#ifdef DEBUG +static void of_dump_addr(const char *s, const u32 *addr, int na) +{ + printk(KERN_DEBUG "%s", s); + while (na--) + printk(" %08x", be32_to_cpu(*(addr++))); + printk("\n"); +} +#else +static void of_dump_addr(const char *s, const u32 *addr, int na) { } +#endif + +/* Callbacks for bus specific translators */ +struct of_bus { + const char *name; + const char *addresses; + int (*match)(struct device_node *parent); + void (*count_cells)(struct device_node *child, + int *addrc, int *sizec); + u64 (*map)(u32 *addr, const u32 *range, + int na, int ns, int pna); + int (*translate)(u32 *addr, u64 offset, int na); + unsigned int (*get_flags)(const u32 *addr); +}; + +/* + * Default translator (generic bus) + */ + +static void of_bus_default_count_cells(struct device_node *dev, + int *addrc, int *sizec) +{ + if (addrc) + *addrc = of_n_addr_cells(dev); + if (sizec) + *sizec = of_n_size_cells(dev); +} + +static u64 of_bus_default_map(u32 *addr, const u32 *range, + int na, int ns, int pna) +{ + u64 cp, s, da; + + cp = of_read_number(range, na); + s = of_read_number(range + na + pna, ns); + da = of_read_number(addr, na); + + pr_debug("OF: default map, cp=%llx, s=%llx, da=%llx\n", + (unsigned long long)cp, (unsigned long long)s, + (unsigned long long)da); + + if (da < cp || da >= (cp + s)) + return OF_BAD_ADDR; + return da - cp; +} + +static int of_bus_default_translate(u32 *addr, u64 offset, int na) +{ + u64 a = of_read_number(addr, na); + memset(addr, 0, na * 4); + a += offset; + if (na > 1) + addr[na - 2] = cpu_to_be32(a >> 32); + addr[na - 1] = cpu_to_be32(a & 0xffffffffu); + + return 0; +} + +static unsigned int of_bus_default_get_flags(const u32 *addr) +{ + return IORESOURCE_MEM; +} + +#ifdef CONFIG_PCI +/* + * PCI bus specific translator + */ + +static int of_bus_pci_match(struct device_node *np) +{ + /* "vci" is for the /chaos bridge on 1st-gen PCI powermacs */ + return !strcmp(np->type, "pci") || !strcmp(np->type, "vci"); +} + +static void of_bus_pci_count_cells(struct device_node *np, + int *addrc, int *sizec) +{ + if (addrc) + *addrc = 3; + if (sizec) + *sizec = 2; +} + +static unsigned int of_bus_pci_get_flags(const u32 *addr) +{ + unsigned int flags = 0; + u32 w = addr[0]; + + switch((w >> 24) & 0x03) { + case 0x01: + flags |= IORESOURCE_IO; + break; + case 0x02: /* 32 bits */ + case 0x03: /* 64 bits */ + flags |= IORESOURCE_MEM; + break; + } + if (w & 0x40000000) + flags |= IORESOURCE_PREFETCH; + return flags; +} + +static u64 of_bus_pci_map(u32 *addr, const u32 *range, int na, int ns, int pna) +{ + u64 cp, s, da; + unsigned int af, rf; + + af = of_bus_pci_get_flags(addr); + rf = of_bus_pci_get_flags(range); + + /* Check address type match */ + if ((af ^ rf) & (IORESOURCE_MEM | IORESOURCE_IO)) + return OF_BAD_ADDR; + + /* Read address values, skipping high cell */ + cp = of_read_number(range + 1, na - 1); + s = of_read_number(range + na + pna, ns); + da = of_read_number(addr + 1, na - 1); + + pr_debug("OF: PCI map, cp=%llx, s=%llx, da=%llx\n", + (unsigned long long)cp, (unsigned long long)s, + (unsigned long long)da); + + if (da < cp || da >= (cp + s)) + return OF_BAD_ADDR; + return da - cp; +} + +static int of_bus_pci_translate(u32 *addr, u64 offset, int na) +{ + return of_bus_default_translate(addr + 1, offset, na - 1); +} + +const u32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size, + unsigned int *flags) +{ + const u32 *prop; + unsigned int psize; + struct device_node *parent; + struct of_bus *bus; + int onesize, i, na, ns; + + /* Get parent & match bus type */ + parent = of_get_parent(dev); + if (parent == NULL) + return NULL; + bus = of_match_bus(parent); + if (strcmp(bus->name, "pci")) { + of_node_put(parent); + return NULL; + } + bus->count_cells(dev, &na, &ns); + of_node_put(parent); + if (!OF_CHECK_COUNTS(na, ns)) + return NULL; + + /* Get "reg" or "assigned-addresses" property */ + prop = of_get_property(dev, bus->addresses, &psize); + if (prop == NULL) + return NULL; + psize /= 4; + + onesize = na + ns; + for (i = 0; psize >= onesize; psize -= onesize, prop += onesize, i++) { + u32 val = be32_to_cpu(prop[0]); + if ((val & 0xff) == ((bar_no * 4) + PCI_BASE_ADDRESS_0)) { + if (size) + *size = of_read_number(prop + na, ns); + if (flags) + *flags = bus->get_flags(prop); + return prop; + } + } + return NULL; +} +EXPORT_SYMBOL(of_get_pci_address); + +int of_pci_address_to_resource(struct device_node *dev, int bar, + struct resource *r) +{ + const u32 *addrp; + u64 size; + unsigned int flags; + + addrp = of_get_pci_address(dev, bar, &size, &flags); + if (addrp == NULL) + return -EINVAL; + return __of_address_to_resource(dev, addrp, size, flags, r); +} +EXPORT_SYMBOL_GPL(of_pci_address_to_resource); +#endif /* CONFIG_PCI */ + +/* + * ISA bus specific translator + */ + +static int of_bus_isa_match(struct device_node *np) +{ + return !strcmp(np->name, "isa"); +} + +static void of_bus_isa_count_cells(struct device_node *child, + int *addrc, int *sizec) +{ + if (addrc) + *addrc = 2; + if (sizec) + *sizec = 1; +} + +static u64 of_bus_isa_map(u32 *addr, const u32 *range, int na, int ns, int pna) +{ + u64 cp, s, da; + + /* Check address type match */ + if ((addr[0] ^ range[0]) & 0x00000001) + return OF_BAD_ADDR; + + /* Read address values, skipping high cell */ + cp = of_read_number(range + 1, na - 1); + s = of_read_number(range + na + pna, ns); + da = of_read_number(addr + 1, na - 1); + + pr_debug("OF: ISA map, cp=%llx, s=%llx, da=%llx\n", + (unsigned long long)cp, (unsigned long long)s, + (unsigned long long)da); + + if (da < cp || da >= (cp + s)) + return OF_BAD_ADDR; + return da - cp; +} + +static int of_bus_isa_translate(u32 *addr, u64 offset, int na) +{ + return of_bus_default_translate(addr + 1, offset, na - 1); +} + +static unsigned int of_bus_isa_get_flags(const u32 *addr) +{ + unsigned int flags = 0; + u32 w = addr[0]; + + if (w & 1) + flags |= IORESOURCE_IO; + else + flags |= IORESOURCE_MEM; + return flags; +} + +/* + * Array of bus specific translators + */ + +static struct of_bus of_busses[] = { +#ifdef CONFIG_PCI + /* PCI */ + { + .name = "pci", + .addresses = "assigned-addresses", + .match = of_bus_pci_match, + .count_cells = of_bus_pci_count_cells, + .map = of_bus_pci_map, + .translate = of_bus_pci_translate, + .get_flags = of_bus_pci_get_flags, + }, +#endif /* CONFIG_PCI */ + /* ISA */ + { + .name = "isa", + .addresses = "reg", + .match = of_bus_isa_match, + .count_cells = of_bus_isa_count_cells, + .map = of_bus_isa_map, + .translate = of_bus_isa_translate, + .get_flags = of_bus_isa_get_flags, + }, + /* Default */ + { + .name = "default", + .addresses = "reg", + .match = NULL, + .count_cells = of_bus_default_count_cells, + .map = of_bus_default_map, + .translate = of_bus_default_translate, + .get_flags = of_bus_default_get_flags, + }, +}; + +static struct of_bus *of_match_bus(struct device_node *np) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(of_busses); i++) + if (!of_busses[i].match || of_busses[i].match(np)) + return &of_busses[i]; + BUG(); + return NULL; +} + +static int of_translate_one(struct device_node *parent, struct of_bus *bus, + struct of_bus *pbus, u32 *addr, + int na, int ns, int pna, const char *rprop) +{ + const u32 *ranges; + unsigned int rlen; + int rone; + u64 offset = OF_BAD_ADDR; + + /* Normally, an absence of a "ranges" property means we are + * crossing a non-translatable boundary, and thus the addresses + * below the current not cannot be converted to CPU physical ones. + * Unfortunately, while this is very clear in the spec, it's not + * what Apple understood, and they do have things like /uni-n or + * /ht nodes with no "ranges" property and a lot of perfectly + * useable mapped devices below them. Thus we treat the absence of + * "ranges" as equivalent to an empty "ranges" property which means + * a 1:1 translation at that level. It's up to the caller not to try + * to translate addresses that aren't supposed to be translated in + * the first place. --BenH. + * + * As far as we know, this damage only exists on Apple machines, so + * This code is only enabled on powerpc. --gcl + */ + ranges = of_get_property(parent, rprop, &rlen); +#if !defined(CONFIG_PPC) + if (ranges == NULL) { + pr_err("OF: no ranges; cannot translate\n"); + return 1; + } +#endif /* !defined(CONFIG_PPC) */ + if (ranges == NULL || rlen == 0) { + offset = of_read_number(addr, na); + memset(addr, 0, pna * 4); + pr_debug("OF: empty ranges; 1:1 translation\n"); + goto finish; + } + + pr_debug("OF: walking ranges...\n"); + + /* Now walk through the ranges */ + rlen /= 4; + rone = na + pna + ns; + for (; rlen >= rone; rlen -= rone, ranges += rone) { + offset = bus->map(addr, ranges, na, ns, pna); + if (offset != OF_BAD_ADDR) + break; + } + if (offset == OF_BAD_ADDR) { + pr_debug("OF: not found !\n"); + return 1; + } + memcpy(addr, ranges + na, 4 * pna); + + finish: + of_dump_addr("OF: parent translation for:", addr, pna); + pr_debug("OF: with offset: %llx\n", (unsigned long long)offset); + + /* Translate it into parent bus space */ + return pbus->translate(addr, offset, pna); +} + +/* + * Translate an address from the device-tree into a CPU physical address, + * this walks up the tree and applies the various bus mappings on the + * way. + * + * Note: We consider that crossing any level with #size-cells == 0 to mean + * that translation is impossible (that is we are not dealing with a value + * that can be mapped to a cpu physical address). This is not really specified + * that way, but this is traditionally the way IBM at least do things + */ +u64 __of_translate_address(struct device_node *dev, const u32 *in_addr, + const char *rprop) +{ + struct device_node *parent = NULL; + struct of_bus *bus, *pbus; + u32 addr[OF_MAX_ADDR_CELLS]; + int na, ns, pna, pns; + u64 result = OF_BAD_ADDR; + + pr_debug("OF: ** translation for device %s **\n", dev->full_name); + + /* Increase refcount at current level */ + of_node_get(dev); + + /* Get parent & match bus type */ + parent = of_get_parent(dev); + if (parent == NULL) + goto bail; + bus = of_match_bus(parent); + + /* Cound address cells & copy address locally */ + bus->count_cells(dev, &na, &ns); + if (!OF_CHECK_COUNTS(na, ns)) { + printk(KERN_ERR "prom_parse: Bad cell count for %s\n", + dev->full_name); + goto bail; + } + memcpy(addr, in_addr, na * 4); + + pr_debug("OF: bus is %s (na=%d, ns=%d) on %s\n", + bus->name, na, ns, parent->full_name); + of_dump_addr("OF: translating address:", addr, na); + + /* Translate */ + for (;;) { + /* Switch to parent bus */ + of_node_put(dev); + dev = parent; + parent = of_get_parent(dev); + + /* If root, we have finished */ + if (parent == NULL) { + pr_debug("OF: reached root node\n"); + result = of_read_number(addr, na); + break; + } + + /* Get new parent bus and counts */ + pbus = of_match_bus(parent); + pbus->count_cells(dev, &pna, &pns); + if (!OF_CHECK_COUNTS(pna, pns)) { + printk(KERN_ERR "prom_parse: Bad cell count for %s\n", + dev->full_name); + break; + } + + pr_debug("OF: parent bus is %s (na=%d, ns=%d) on %s\n", + pbus->name, pna, pns, parent->full_name); + + /* Apply bus translation */ + if (of_translate_one(dev, bus, pbus, addr, na, ns, pna, rprop)) + break; + + /* Complete the move up one level */ + na = pna; + ns = pns; + bus = pbus; + + of_dump_addr("OF: one level translation:", addr, na); + } + bail: + of_node_put(parent); + of_node_put(dev); + + return result; +} + +u64 of_translate_address(struct device_node *dev, const u32 *in_addr) +{ + return __of_translate_address(dev, in_addr, "ranges"); +} +EXPORT_SYMBOL(of_translate_address); + +u64 of_translate_dma_address(struct device_node *dev, const u32 *in_addr) +{ + return __of_translate_address(dev, in_addr, "dma-ranges"); +} +EXPORT_SYMBOL(of_translate_dma_address); + +const u32 *of_get_address(struct device_node *dev, int index, u64 *size, + unsigned int *flags) +{ + const u32 *prop; + unsigned int psize; + struct device_node *parent; + struct of_bus *bus; + int onesize, i, na, ns; + + /* Get parent & match bus type */ + parent = of_get_parent(dev); + if (parent == NULL) + return NULL; + bus = of_match_bus(parent); + bus->count_cells(dev, &na, &ns); + of_node_put(parent); + if (!OF_CHECK_COUNTS(na, ns)) + return NULL; + + /* Get "reg" or "assigned-addresses" property */ + prop = of_get_property(dev, bus->addresses, &psize); + if (prop == NULL) + return NULL; + psize /= 4; + + onesize = na + ns; + for (i = 0; psize >= onesize; psize -= onesize, prop += onesize, i++) + if (i == index) { + if (size) + *size = of_read_number(prop + na, ns); + if (flags) + *flags = bus->get_flags(prop); + return prop; + } + return NULL; +} +EXPORT_SYMBOL(of_get_address); + +static int __of_address_to_resource(struct device_node *dev, const u32 *addrp, + u64 size, unsigned int flags, + struct resource *r) +{ + u64 taddr; + + if ((flags & (IORESOURCE_IO | IORESOURCE_MEM)) == 0) + return -EINVAL; + taddr = of_translate_address(dev, addrp); + if (taddr == OF_BAD_ADDR) + return -EINVAL; + memset(r, 0, sizeof(struct resource)); + if (flags & IORESOURCE_IO) { + unsigned long port; + port = pci_address_to_pio(taddr); + if (port == (unsigned long)-1) + return -EINVAL; + r->start = port; + r->end = port + size - 1; + } else { + r->start = taddr; + r->end = taddr + size - 1; + } + r->flags = flags; + r->name = dev->full_name; + return 0; +} + +/** + * of_address_to_resource - Translate device tree address and return as resource + * + * Note that if your address is a PIO address, the conversion will fail if + * the physical address can't be internally converted to an IO token with + * pci_address_to_pio(), that is because it's either called to early or it + * can't be matched to any host bridge IO space + */ +int of_address_to_resource(struct device_node *dev, int index, + struct resource *r) +{ + const u32 *addrp; + u64 size; + unsigned int flags; + + addrp = of_get_address(dev, index, &size, &flags); + if (addrp == NULL) + return -EINVAL; + return __of_address_to_resource(dev, addrp, size, flags, r); +} +EXPORT_SYMBOL_GPL(of_address_to_resource); + + +/** + * of_iomap - Maps the memory mapped IO for a given device_node + * @device: the device whose io range will be mapped + * @index: index of the io range + * + * Returns a pointer to the mapped memory + */ +void __iomem *of_iomap(struct device_node *np, int index) +{ + struct resource res; + + if (of_address_to_resource(np, index, &res)) + return NULL; + + return ioremap(res.start, 1 + res.end - res.start); +} +EXPORT_SYMBOL(of_iomap); diff --git a/drivers/of/base.c b/drivers/of/base.c index b5ad974..aa80525 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -545,74 +545,28 @@ struct device_node *of_find_matching_node(struct device_node *from, EXPORT_SYMBOL(of_find_matching_node); /** - * of_modalias_table: Table of explicit compatible ==> modalias mappings - * - * This table allows particulare compatible property values to be mapped - * to modalias strings. This is useful for busses which do not directly - * understand the OF device tree but are populated based on data contained - * within the device tree. SPI and I2C are the two current users of this - * table. - * - * In most cases, devices do not need to be listed in this table because - * the modalias value can be derived directly from the compatible table. - * However, if for any reason a value cannot be derived, then this table - * provides a method to override the implicit derivation. - * - * At the moment, a single table is used for all bus types because it is - * assumed that the data size is small and that the compatible values - * should already be distinct enough to differentiate between SPI, I2C - * and other devices. - */ -struct of_modalias_table { - char *of_device; - char *modalias; -}; -static struct of_modalias_table of_modalias_table[] = { - { "fsl,mcu-mpc8349emitx", "mcu-mpc8349emitx" }, - { "mmc-spi-slot", "mmc_spi" }, -}; - -/** * of_modalias_node - Lookup appropriate modalias for a device node * @node: pointer to a device tree node * @modalias: Pointer to buffer that modalias value will be copied into * @len: Length of modalias value * - * Based on the value of the compatible property, this routine will determine - * an appropriate modalias value for a particular device tree node. Two - * separate methods are attempted to derive a modalias value. + * Based on the value of the compatible property, this routine will attempt + * to choose an appropriate modalias value for a particular device tree node. + * It does this by stripping the manufacturer prefix (as delimited by a ',') + * from the first entry in the compatible list property. * - * First method is to lookup the compatible value in of_modalias_table. - * Second is to strip off the manufacturer prefix from the first - * compatible entry and use the remainder as modalias - * - * This routine returns 0 on success + * This routine returns 0 on success, <0 on failure. */ int of_modalias_node(struct device_node *node, char *modalias, int len) { - int i, cplen; - const char *compatible; - const char *p; - - /* 1. search for exception list entry */ - for (i = 0; i < ARRAY_SIZE(of_modalias_table); i++) { - compatible = of_modalias_table[i].of_device; - if (!of_device_is_compatible(node, compatible)) - continue; - strlcpy(modalias, of_modalias_table[i].modalias, len); - return 0; - } + const char *compatible, *p; + int cplen; compatible = of_get_property(node, "compatible", &cplen); - if (!compatible) + if (!compatible || strlen(compatible) > cplen) return -ENODEV; - - /* 2. take first compatible entry and strip manufacturer */ p = strchr(compatible, ','); - if (!p) - return -ENODEV; - p++; - strlcpy(modalias, p, len); + strlcpy(modalias, p ? p + 1 : compatible, len); return 0; } EXPORT_SYMBOL_GPL(of_modalias_node); @@ -651,14 +605,14 @@ EXPORT_SYMBOL(of_find_node_by_phandle); struct device_node * of_parse_phandle(struct device_node *np, const char *phandle_name, int index) { - const phandle *phandle; + const __be32 *phandle; int size; phandle = of_get_property(np, phandle_name, &size); if ((!phandle) || (size < sizeof(*phandle) * (index + 1))) return NULL; - return of_find_node_by_phandle(phandle[index]); + return of_find_node_by_phandle(be32_to_cpup(phandle + index)); } EXPORT_SYMBOL(of_parse_phandle); @@ -714,16 +668,16 @@ int of_parse_phandles_with_args(struct device_node *np, const char *list_name, while (list < list_end) { const __be32 *cells; - const phandle *phandle; + phandle phandle; - phandle = list++; + phandle = be32_to_cpup(list++); args = list; /* one cell hole in the list = <>; */ - if (!*phandle) + if (!phandle) goto next; - node = of_find_node_by_phandle(*phandle); + node = of_find_node_by_phandle(phandle); if (!node) { pr_debug("%s: could not find phandle\n", np->full_name); diff --git a/drivers/of/device.c b/drivers/of/device.c index 7d18f8e..0d8a064 100644 --- a/drivers/of/device.c +++ b/drivers/of/device.c @@ -20,13 +20,13 @@ const struct of_device_id *of_match_device(const struct of_device_id *matches, const struct device *dev) { - if (!dev->of_node) + if ((!matches) || (!dev->of_node)) return NULL; return of_match_node(matches, dev->of_node); } EXPORT_SYMBOL(of_match_device); -struct of_device *of_dev_get(struct of_device *dev) +struct platform_device *of_dev_get(struct platform_device *dev) { struct device *tmp; @@ -34,13 +34,13 @@ struct of_device *of_dev_get(struct of_device *dev) return NULL; tmp = get_device(&dev->dev); if (tmp) - return to_of_device(tmp); + return to_platform_device(tmp); else return NULL; } EXPORT_SYMBOL(of_dev_get); -void of_dev_put(struct of_device *dev) +void of_dev_put(struct platform_device *dev) { if (dev) put_device(&dev->dev); @@ -50,28 +50,25 @@ EXPORT_SYMBOL(of_dev_put); static ssize_t devspec_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct of_device *ofdev; + struct platform_device *ofdev; - ofdev = to_of_device(dev); + ofdev = to_platform_device(dev); return sprintf(buf, "%s\n", ofdev->dev.of_node->full_name); } static ssize_t name_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct of_device *ofdev; + struct platform_device *ofdev; - ofdev = to_of_device(dev); + ofdev = to_platform_device(dev); return sprintf(buf, "%s\n", ofdev->dev.of_node->name); } static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct of_device *ofdev = to_of_device(dev); - ssize_t len = 0; - - len = of_device_get_modalias(ofdev, buf, PAGE_SIZE - 2); + ssize_t len = of_device_get_modalias(dev, buf, PAGE_SIZE - 2); buf[len] = '\n'; buf[len+1] = 0; return len+1; @@ -93,20 +90,25 @@ struct device_attribute of_platform_device_attrs[] = { */ void of_release_dev(struct device *dev) { - struct of_device *ofdev; + struct platform_device *ofdev; - ofdev = to_of_device(dev); + ofdev = to_platform_device(dev); of_node_put(ofdev->dev.of_node); kfree(ofdev); } EXPORT_SYMBOL(of_release_dev); -int of_device_register(struct of_device *ofdev) +int of_device_register(struct platform_device *ofdev) { BUG_ON(ofdev->dev.of_node == NULL); device_initialize(&ofdev->dev); + /* name and id have to be set so that the platform bus doesn't get + * confused on matching */ + ofdev->name = dev_name(&ofdev->dev); + ofdev->id = -1; + /* device_add will assume that this device is on the same node as * the parent. If there is no parent defined, set the node * explicitly */ @@ -117,25 +119,24 @@ int of_device_register(struct of_device *ofdev) } EXPORT_SYMBOL(of_device_register); -void of_device_unregister(struct of_device *ofdev) +void of_device_unregister(struct platform_device *ofdev) { device_unregister(&ofdev->dev); } EXPORT_SYMBOL(of_device_unregister); -ssize_t of_device_get_modalias(struct of_device *ofdev, - char *str, ssize_t len) +ssize_t of_device_get_modalias(struct device *dev, char *str, ssize_t len) { const char *compat; int cplen, i; ssize_t tsize, csize, repend; /* Name & Type */ - csize = snprintf(str, len, "of:N%sT%s", ofdev->dev.of_node->name, - ofdev->dev.of_node->type); + csize = snprintf(str, len, "of:N%sT%s", dev->of_node->name, + dev->of_node->type); /* Get compatible property if any */ - compat = of_get_property(ofdev->dev.of_node, "compatible", &cplen); + compat = of_get_property(dev->of_node, "compatible", &cplen); if (!compat) return csize; @@ -170,3 +171,51 @@ ssize_t of_device_get_modalias(struct of_device *ofdev, return tsize; } + +/** + * of_device_uevent - Display OF related uevent information + */ +int of_device_uevent(struct device *dev, struct kobj_uevent_env *env) +{ + const char *compat; + int seen = 0, cplen, sl; + + if ((!dev) || (!dev->of_node)) + return -ENODEV; + + if (add_uevent_var(env, "OF_NAME=%s", dev->of_node->name)) + return -ENOMEM; + + if (add_uevent_var(env, "OF_TYPE=%s", dev->of_node->type)) + return -ENOMEM; + + /* Since the compatible field can contain pretty much anything + * it's not really legal to split it out with commas. We split it + * up using a number of environment variables instead. */ + + compat = of_get_property(dev->of_node, "compatible", &cplen); + while (compat && *compat && cplen > 0) { + if (add_uevent_var(env, "OF_COMPATIBLE_%d=%s", seen, compat)) + return -ENOMEM; + + sl = strlen(compat) + 1; + compat += sl; + cplen -= sl; + seen++; + } + + if (add_uevent_var(env, "OF_COMPATIBLE_N=%d", seen)) + return -ENOMEM; + + /* modalias is trickier, we add it in 2 steps */ + if (add_uevent_var(env, "MODALIAS=")) + return -ENOMEM; + + sl = of_device_get_modalias(dev, &env->buf[env->buflen-1], + sizeof(env->buf) - env->buflen); + if (sl >= (sizeof(env->buf) - env->buflen)) + return -ENOMEM; + env->buflen += sl; + + return 0; +} diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index b6987bb..65da5ae 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -69,9 +69,9 @@ int __init of_scan_flat_dt(int (*it)(unsigned long node, u32 sz = be32_to_cpup((__be32 *)p); p += 8; if (be32_to_cpu(initial_boot_params->version) < 0x10) - p = _ALIGN(p, sz >= 8 ? 8 : 4); + p = ALIGN(p, sz >= 8 ? 8 : 4); p += sz; - p = _ALIGN(p, 4); + p = ALIGN(p, 4); continue; } if (tag != OF_DT_BEGIN_NODE) { @@ -80,7 +80,7 @@ int __init of_scan_flat_dt(int (*it)(unsigned long node, } depth++; pathp = (char *)p; - p = _ALIGN(p + strlen(pathp) + 1, 4); + p = ALIGN(p + strlen(pathp) + 1, 4); if ((*pathp) == '/') { char *lp, *np; for (lp = NULL, np = pathp; *np; np++) @@ -109,7 +109,7 @@ unsigned long __init of_get_flat_dt_root(void) p += 4; BUG_ON(be32_to_cpup((__be32 *)p) != OF_DT_BEGIN_NODE); p += 4; - return _ALIGN(p + strlen((char *)p) + 1, 4); + return ALIGN(p + strlen((char *)p) + 1, 4); } /** @@ -138,7 +138,7 @@ void *__init of_get_flat_dt_prop(unsigned long node, const char *name, noff = be32_to_cpup((__be32 *)(p + 4)); p += 8; if (be32_to_cpu(initial_boot_params->version) < 0x10) - p = _ALIGN(p, sz >= 8 ? 8 : 4); + p = ALIGN(p, sz >= 8 ? 8 : 4); nstr = find_flat_dt_string(noff); if (nstr == NULL) { @@ -151,7 +151,7 @@ void *__init of_get_flat_dt_prop(unsigned long node, const char *name, return (void *)p; } p += sz; - p = _ALIGN(p, 4); + p = ALIGN(p, 4); } while (1); } @@ -169,7 +169,7 @@ int __init of_flat_dt_is_compatible(unsigned long node, const char *compat) if (cp == NULL) return 0; while (cplen > 0) { - if (strncasecmp(cp, compat, strlen(compat)) == 0) + if (of_compat_cmp(cp, compat, strlen(compat)) == 0) return 1; l = strlen(cp) + 1; cp += l; @@ -184,7 +184,7 @@ static void *__init unflatten_dt_alloc(unsigned long *mem, unsigned long size, { void *res; - *mem = _ALIGN(*mem, align); + *mem = ALIGN(*mem, align); res = (void *)*mem; *mem += size; @@ -220,7 +220,7 @@ unsigned long __init unflatten_dt_node(unsigned long mem, *p += 4; pathp = (char *)*p; l = allocl = strlen(pathp) + 1; - *p = _ALIGN(*p + l, 4); + *p = ALIGN(*p + l, 4); /* version 0x10 has a more compact unit name here instead of the full * path. we accumulate the full path size using "fpsize", we'll rebuild @@ -299,7 +299,7 @@ unsigned long __init unflatten_dt_node(unsigned long mem, noff = be32_to_cpup((__be32 *)((*p) + 4)); *p += 8; if (be32_to_cpu(initial_boot_params->version) < 0x10) - *p = _ALIGN(*p, sz >= 8 ? 8 : 4); + *p = ALIGN(*p, sz >= 8 ? 8 : 4); pname = find_flat_dt_string(noff); if (pname == NULL) { @@ -320,20 +320,20 @@ unsigned long __init unflatten_dt_node(unsigned long mem, if ((strcmp(pname, "phandle") == 0) || (strcmp(pname, "linux,phandle") == 0)) { if (np->phandle == 0) - np->phandle = *((u32 *)*p); + np->phandle = be32_to_cpup((__be32*)*p); } /* And we process the "ibm,phandle" property * used in pSeries dynamic device tree * stuff */ if (strcmp(pname, "ibm,phandle") == 0) - np->phandle = *((u32 *)*p); + np->phandle = be32_to_cpup((__be32 *)*p); pp->name = pname; pp->length = sz; pp->value = (void *)*p; *prev_pp = pp; prev_pp = &pp->next; } - *p = _ALIGN((*p) + sz, 4); + *p = ALIGN((*p) + sz, 4); } /* with version 0x10 we may not have the name property, recreate * it here from the unit name if absent diff --git a/drivers/of/gpio.c b/drivers/of/gpio.c index a1b31a4..9059603 100644 --- a/drivers/of/gpio.c +++ b/drivers/of/gpio.c @@ -11,13 +11,14 @@ * (at your option) any later version. */ -#include <linux/kernel.h> +#include <linux/device.h> #include <linux/errno.h> +#include <linux/module.h> #include <linux/io.h> #include <linux/of.h> -#include <linux/slab.h> +#include <linux/of_address.h> #include <linux/of_gpio.h> -#include <asm/prom.h> +#include <linux/slab.h> /** * of_get_gpio_flags - Get a GPIO number and flags to use with GPIO API @@ -33,32 +34,32 @@ int of_get_gpio_flags(struct device_node *np, int index, enum of_gpio_flags *flags) { int ret; - struct device_node *gc; - struct of_gpio_chip *of_gc = NULL; + struct device_node *gpio_np; + struct gpio_chip *gc; int size; const void *gpio_spec; const __be32 *gpio_cells; ret = of_parse_phandles_with_args(np, "gpios", "#gpio-cells", index, - &gc, &gpio_spec); + &gpio_np, &gpio_spec); if (ret) { pr_debug("%s: can't parse gpios property\n", __func__); goto err0; } - of_gc = gc->data; - if (!of_gc) { + gc = of_node_to_gpiochip(gpio_np); + if (!gc) { pr_debug("%s: gpio controller %s isn't registered\n", - np->full_name, gc->full_name); + np->full_name, gpio_np->full_name); ret = -ENODEV; goto err1; } - gpio_cells = of_get_property(gc, "#gpio-cells", &size); + gpio_cells = of_get_property(gpio_np, "#gpio-cells", &size); if (!gpio_cells || size != sizeof(*gpio_cells) || - be32_to_cpup(gpio_cells) != of_gc->gpio_cells) { + be32_to_cpup(gpio_cells) != gc->of_gpio_n_cells) { pr_debug("%s: wrong #gpio-cells for %s\n", - np->full_name, gc->full_name); + np->full_name, gpio_np->full_name); ret = -EINVAL; goto err1; } @@ -67,13 +68,13 @@ int of_get_gpio_flags(struct device_node *np, int index, if (flags) *flags = 0; - ret = of_gc->xlate(of_gc, np, gpio_spec, flags); + ret = gc->of_xlate(gc, np, gpio_spec, flags); if (ret < 0) goto err1; - ret += of_gc->gc.base; + ret += gc->base; err1: - of_node_put(gc); + of_node_put(gpio_np); err0: pr_debug("%s exited with status %d\n", __func__, ret); return ret; @@ -116,7 +117,7 @@ EXPORT_SYMBOL(of_gpio_count); /** * of_gpio_simple_xlate - translate gpio_spec to the GPIO number and flags - * @of_gc: pointer to the of_gpio_chip structure + * @gc: pointer to the gpio_chip structure * @np: device node of the GPIO chip * @gpio_spec: gpio specifier as found in the device tree * @flags: a flags pointer to fill in @@ -125,8 +126,8 @@ EXPORT_SYMBOL(of_gpio_count); * gpio chips. This function performs only one sanity check: whether gpio * is less than ngpios (that is specified in the gpio_chip). */ -int of_gpio_simple_xlate(struct of_gpio_chip *of_gc, struct device_node *np, - const void *gpio_spec, enum of_gpio_flags *flags) +static int of_gpio_simple_xlate(struct gpio_chip *gc, struct device_node *np, + const void *gpio_spec, u32 *flags) { const __be32 *gpio = gpio_spec; const u32 n = be32_to_cpup(gpio); @@ -137,12 +138,12 @@ int of_gpio_simple_xlate(struct of_gpio_chip *of_gc, struct device_node *np, * number and the flags from a single gpio cell -- this is possible, * but not recommended). */ - if (of_gc->gpio_cells < 2) { + if (gc->of_gpio_n_cells < 2) { WARN_ON(1); return -EINVAL; } - if (n > of_gc->gc.ngpio) + if (n > gc->ngpio) return -EINVAL; if (flags) @@ -150,7 +151,6 @@ int of_gpio_simple_xlate(struct of_gpio_chip *of_gc, struct device_node *np, return n; } -EXPORT_SYMBOL(of_gpio_simple_xlate); /** * of_mm_gpiochip_add - Add memory mapped GPIO chip (bank) @@ -161,10 +161,8 @@ EXPORT_SYMBOL(of_gpio_simple_xlate); * * 1) In the gpio_chip structure: * - all the callbacks - * - * 2) In the of_gpio_chip structure: - * - gpio_cells - * - xlate callback (optional) + * - of_gpio_n_cells + * - of_xlate callback (optional) * * 3) In the of_mm_gpio_chip structure: * - save_regs callback (optional) @@ -177,8 +175,7 @@ int of_mm_gpiochip_add(struct device_node *np, struct of_mm_gpio_chip *mm_gc) { int ret = -ENOMEM; - struct of_gpio_chip *of_gc = &mm_gc->of_gc; - struct gpio_chip *gc = &of_gc->gc; + struct gpio_chip *gc = &mm_gc->gc; gc->label = kstrdup(np->full_name, GFP_KERNEL); if (!gc->label) @@ -190,26 +187,19 @@ int of_mm_gpiochip_add(struct device_node *np, gc->base = -1; - if (!of_gc->xlate) - of_gc->xlate = of_gpio_simple_xlate; - if (mm_gc->save_regs) mm_gc->save_regs(mm_gc); - np->data = of_gc; + mm_gc->gc.of_node = np; ret = gpiochip_add(gc); if (ret) goto err2; - /* We don't want to lose the node and its ->data */ - of_node_get(np); - pr_debug("%s: registered as generic GPIO chip, base is %d\n", np->full_name, gc->base); return 0; err2: - np->data = NULL; iounmap(mm_gc->regs); err1: kfree(gc->label); @@ -219,3 +209,36 @@ err0: return ret; } EXPORT_SYMBOL(of_mm_gpiochip_add); + +void of_gpiochip_add(struct gpio_chip *chip) +{ + if ((!chip->of_node) && (chip->dev)) + chip->of_node = chip->dev->of_node; + + if (!chip->of_node) + return; + + if (!chip->of_xlate) { + chip->of_gpio_n_cells = 2; + chip->of_xlate = of_gpio_simple_xlate; + } + + of_node_get(chip->of_node); +} + +void of_gpiochip_remove(struct gpio_chip *chip) +{ + if (chip->of_node) + of_node_put(chip->of_node); +} + +/* Private function for resolving node pointer to gpio_chip */ +static int of_gpiochip_is_match(struct gpio_chip *chip, void *data) +{ + return chip->of_node == data; +} + +struct gpio_chip *of_node_to_gpiochip(struct device_node *np) +{ + return gpiochip_find(np, of_gpiochip_is_match); +} diff --git a/drivers/of/irq.c b/drivers/of/irq.c new file mode 100644 index 0000000..6e595e5 --- /dev/null +++ b/drivers/of/irq.c @@ -0,0 +1,349 @@ +/* + * Derived from arch/i386/kernel/irq.c + * Copyright (C) 1992 Linus Torvalds + * Adapted from arch/i386 by Gary Thomas + * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) + * Updated and modified by Cort Dougan <cort@fsmlabs.com> + * Copyright (C) 1996-2001 Cort Dougan + * Adapted for Power Macintosh by Paul Mackerras + * Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * This file contains the code used to make IRQ descriptions in the + * device tree to actual irq numbers on an interrupt controller + * driver. + */ + +#include <linux/errno.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_irq.h> +#include <linux/string.h> + +/** + * irq_of_parse_and_map - Parse and map an interrupt into linux virq space + * @device: Device node of the device whose interrupt is to be mapped + * @index: Index of the interrupt to map + * + * This function is a wrapper that chains of_irq_map_one() and + * irq_create_of_mapping() to make things easier to callers + */ +unsigned int irq_of_parse_and_map(struct device_node *dev, int index) +{ + struct of_irq oirq; + + if (of_irq_map_one(dev, index, &oirq)) + return NO_IRQ; + + return irq_create_of_mapping(oirq.controller, oirq.specifier, + oirq.size); +} +EXPORT_SYMBOL_GPL(irq_of_parse_and_map); + +/** + * of_irq_find_parent - Given a device node, find its interrupt parent node + * @child: pointer to device node + * + * Returns a pointer to the interrupt parent node, or NULL if the interrupt + * parent could not be determined. + */ +static struct device_node *of_irq_find_parent(struct device_node *child) +{ + struct device_node *p; + const __be32 *parp; + + if (!of_node_get(child)) + return NULL; + + do { + parp = of_get_property(child, "interrupt-parent", NULL); + if (parp == NULL) + p = of_get_parent(child); + else { + if (of_irq_workarounds & OF_IMAP_NO_PHANDLE) + p = of_node_get(of_irq_dflt_pic); + else + p = of_find_node_by_phandle(be32_to_cpup(parp)); + } + of_node_put(child); + child = p; + } while (p && of_get_property(p, "#interrupt-cells", NULL) == NULL); + + return p; +} + +/** + * of_irq_map_raw - Low level interrupt tree parsing + * @parent: the device interrupt parent + * @intspec: interrupt specifier ("interrupts" property of the device) + * @ointsize: size of the passed in interrupt specifier + * @addr: address specifier (start of "reg" property of the device) + * @out_irq: structure of_irq filled by this function + * + * Returns 0 on success and a negative number on error + * + * This function is a low-level interrupt tree walking function. It + * can be used to do a partial walk with synthetized reg and interrupts + * properties, for example when resolving PCI interrupts when no device + * node exist for the parent. + */ +int of_irq_map_raw(struct device_node *parent, const __be32 *intspec, + u32 ointsize, const __be32 *addr, struct of_irq *out_irq) +{ + struct device_node *ipar, *tnode, *old = NULL, *newpar = NULL; + const __be32 *tmp, *imap, *imask; + u32 intsize = 1, addrsize, newintsize = 0, newaddrsize = 0; + int imaplen, match, i; + + pr_debug("of_irq_map_raw: par=%s,intspec=[0x%08x 0x%08x...],ointsize=%d\n", + parent->full_name, be32_to_cpup(intspec), + be32_to_cpup(intspec + 1), ointsize); + + ipar = of_node_get(parent); + + /* First get the #interrupt-cells property of the current cursor + * that tells us how to interpret the passed-in intspec. If there + * is none, we are nice and just walk up the tree + */ + do { + tmp = of_get_property(ipar, "#interrupt-cells", NULL); + if (tmp != NULL) { + intsize = be32_to_cpu(*tmp); + break; + } + tnode = ipar; + ipar = of_irq_find_parent(ipar); + of_node_put(tnode); + } while (ipar); + if (ipar == NULL) { + pr_debug(" -> no parent found !\n"); + goto fail; + } + + pr_debug("of_irq_map_raw: ipar=%s, size=%d\n", ipar->full_name, intsize); + + if (ointsize != intsize) + return -EINVAL; + + /* Look for this #address-cells. We have to implement the old linux + * trick of looking for the parent here as some device-trees rely on it + */ + old = of_node_get(ipar); + do { + tmp = of_get_property(old, "#address-cells", NULL); + tnode = of_get_parent(old); + of_node_put(old); + old = tnode; + } while (old && tmp == NULL); + of_node_put(old); + old = NULL; + addrsize = (tmp == NULL) ? 2 : be32_to_cpu(*tmp); + + pr_debug(" -> addrsize=%d\n", addrsize); + + /* Now start the actual "proper" walk of the interrupt tree */ + while (ipar != NULL) { + /* Now check if cursor is an interrupt-controller and if it is + * then we are done + */ + if (of_get_property(ipar, "interrupt-controller", NULL) != + NULL) { + pr_debug(" -> got it !\n"); + for (i = 0; i < intsize; i++) + out_irq->specifier[i] = + of_read_number(intspec +i, 1); + out_irq->size = intsize; + out_irq->controller = ipar; + of_node_put(old); + return 0; + } + + /* Now look for an interrupt-map */ + imap = of_get_property(ipar, "interrupt-map", &imaplen); + /* No interrupt map, check for an interrupt parent */ + if (imap == NULL) { + pr_debug(" -> no map, getting parent\n"); + newpar = of_irq_find_parent(ipar); + goto skiplevel; + } + imaplen /= sizeof(u32); + + /* Look for a mask */ + imask = of_get_property(ipar, "interrupt-map-mask", NULL); + + /* If we were passed no "reg" property and we attempt to parse + * an interrupt-map, then #address-cells must be 0. + * Fail if it's not. + */ + if (addr == NULL && addrsize != 0) { + pr_debug(" -> no reg passed in when needed !\n"); + goto fail; + } + + /* Parse interrupt-map */ + match = 0; + while (imaplen > (addrsize + intsize + 1) && !match) { + /* Compare specifiers */ + match = 1; + for (i = 0; i < addrsize && match; ++i) { + u32 mask = imask ? imask[i] : 0xffffffffu; + match = ((addr[i] ^ imap[i]) & mask) == 0; + } + for (; i < (addrsize + intsize) && match; ++i) { + u32 mask = imask ? imask[i] : 0xffffffffu; + match = + ((intspec[i-addrsize] ^ imap[i]) & mask) == 0; + } + imap += addrsize + intsize; + imaplen -= addrsize + intsize; + + pr_debug(" -> match=%d (imaplen=%d)\n", match, imaplen); + + /* Get the interrupt parent */ + if (of_irq_workarounds & OF_IMAP_NO_PHANDLE) + newpar = of_node_get(of_irq_dflt_pic); + else + newpar = of_find_node_by_phandle(be32_to_cpup(imap)); + imap++; + --imaplen; + + /* Check if not found */ + if (newpar == NULL) { + pr_debug(" -> imap parent not found !\n"); + goto fail; + } + + /* Get #interrupt-cells and #address-cells of new + * parent + */ + tmp = of_get_property(newpar, "#interrupt-cells", NULL); + if (tmp == NULL) { + pr_debug(" -> parent lacks #interrupt-cells!\n"); + goto fail; + } + newintsize = be32_to_cpu(*tmp); + tmp = of_get_property(newpar, "#address-cells", NULL); + newaddrsize = (tmp == NULL) ? 0 : be32_to_cpu(*tmp); + + pr_debug(" -> newintsize=%d, newaddrsize=%d\n", + newintsize, newaddrsize); + + /* Check for malformed properties */ + if (imaplen < (newaddrsize + newintsize)) + goto fail; + + imap += newaddrsize + newintsize; + imaplen -= newaddrsize + newintsize; + + pr_debug(" -> imaplen=%d\n", imaplen); + } + if (!match) + goto fail; + + of_node_put(old); + old = of_node_get(newpar); + addrsize = newaddrsize; + intsize = newintsize; + intspec = imap - intsize; + addr = intspec - addrsize; + + skiplevel: + /* Iterate again with new parent */ + pr_debug(" -> new parent: %s\n", newpar ? newpar->full_name : "<>"); + of_node_put(ipar); + ipar = newpar; + newpar = NULL; + } + fail: + of_node_put(ipar); + of_node_put(old); + of_node_put(newpar); + + return -EINVAL; +} +EXPORT_SYMBOL_GPL(of_irq_map_raw); + +/** + * of_irq_map_one - Resolve an interrupt for a device + * @device: the device whose interrupt is to be resolved + * @index: index of the interrupt to resolve + * @out_irq: structure of_irq filled by this function + * + * This function resolves an interrupt, walking the tree, for a given + * device-tree node. It's the high level pendant to of_irq_map_raw(). + */ +int of_irq_map_one(struct device_node *device, int index, struct of_irq *out_irq) +{ + struct device_node *p; + const __be32 *intspec, *tmp, *addr; + u32 intsize, intlen; + int res = -EINVAL; + + pr_debug("of_irq_map_one: dev=%s, index=%d\n", device->full_name, index); + + /* OldWorld mac stuff is "special", handle out of line */ + if (of_irq_workarounds & OF_IMAP_OLDWORLD_MAC) + return of_irq_map_oldworld(device, index, out_irq); + + /* Get the interrupts property */ + intspec = of_get_property(device, "interrupts", &intlen); + if (intspec == NULL) + return -EINVAL; + intlen /= sizeof(*intspec); + + pr_debug(" intspec=%d intlen=%d\n", be32_to_cpup(intspec), intlen); + + /* Get the reg property (if any) */ + addr = of_get_property(device, "reg", NULL); + + /* Look for the interrupt parent. */ + p = of_irq_find_parent(device); + if (p == NULL) + return -EINVAL; + + /* Get size of interrupt specifier */ + tmp = of_get_property(p, "#interrupt-cells", NULL); + if (tmp == NULL) + goto out; + intsize = be32_to_cpu(*tmp); + + pr_debug(" intsize=%d intlen=%d\n", intsize, intlen); + + /* Check index */ + if ((index + 1) * intsize > intlen) + goto out; + + /* Get new specifier and map it */ + res = of_irq_map_raw(p, intspec + index * intsize, intsize, + addr, out_irq); + out: + of_node_put(p); + return res; +} +EXPORT_SYMBOL_GPL(of_irq_map_one); + +/** + * of_irq_to_resource - Decode a node's IRQ and return it as a resource + * @dev: pointer to device tree node + * @index: zero-based index of the irq + * @r: pointer to resource structure to return result into. + */ +int of_irq_to_resource(struct device_node *dev, int index, struct resource *r) +{ + int irq = irq_of_parse_and_map(dev, index); + + /* Only dereference the resource if both the + * resource and the irq are valid. */ + if (r && irq != NO_IRQ) { + r->start = r->end = irq; + r->flags = IORESOURCE_IRQ; + r->name = dev->full_name; + } + + return irq; +} +EXPORT_SYMBOL_GPL(of_irq_to_resource); diff --git a/drivers/of/of_i2c.c b/drivers/of/of_i2c.c index ab6522c..0a694de 100644 --- a/drivers/of/of_i2c.c +++ b/drivers/of/of_i2c.c @@ -14,57 +14,65 @@ #include <linux/i2c.h> #include <linux/of.h> #include <linux/of_i2c.h> +#include <linux/of_irq.h> #include <linux/module.h> -void of_register_i2c_devices(struct i2c_adapter *adap, - struct device_node *adap_node) +void of_i2c_register_devices(struct i2c_adapter *adap) { void *result; struct device_node *node; - for_each_child_of_node(adap_node, node) { + /* Only register child devices if the adapter has a node pointer set */ + if (!adap->dev.of_node) + return; + + dev_dbg(&adap->dev, "of_i2c: walking child nodes\n"); + + for_each_child_of_node(adap->dev.of_node, node) { struct i2c_board_info info = {}; struct dev_archdata dev_ad = {}; const __be32 *addr; int len; - if (of_modalias_node(node, info.type, sizeof(info.type)) < 0) + dev_dbg(&adap->dev, "of_i2c: register %s\n", node->full_name); + + if (of_modalias_node(node, info.type, sizeof(info.type)) < 0) { + dev_err(&adap->dev, "of_i2c: modalias failure on %s\n", + node->full_name); continue; + } addr = of_get_property(node, "reg", &len); - if (!addr || len < sizeof(int) || *addr > (1 << 10) - 1) { - printk(KERN_ERR - "of-i2c: invalid i2c device entry\n"); + if (!addr || (len < sizeof(int))) { + dev_err(&adap->dev, "of_i2c: invalid reg on %s\n", + node->full_name); continue; } - info.irq = irq_of_parse_and_map(node, 0); - info.addr = be32_to_cpup(addr); + if (info.addr > (1 << 10) - 1) { + dev_err(&adap->dev, "of_i2c: invalid addr=%x on %s\n", + info.addr, node->full_name); + continue; + } - info.of_node = node; + info.irq = irq_of_parse_and_map(node, 0); + info.of_node = of_node_get(node); info.archdata = &dev_ad; request_module("%s", info.type); result = i2c_new_device(adap, &info); if (result == NULL) { - printk(KERN_ERR - "of-i2c: Failed to load driver for %s\n", - info.type); + dev_err(&adap->dev, "of_i2c: Failure registering %s\n", + node->full_name); + of_node_put(node); irq_dispose_mapping(info.irq); continue; } - - /* - * Get the node to not lose the dev_archdata->of_node. - * Currently there is no way to put it back, as well as no - * of_unregister_i2c_devices() call. - */ - of_node_get(node); } } -EXPORT_SYMBOL(of_register_i2c_devices); +EXPORT_SYMBOL(of_i2c_register_devices); static int of_dev_node_match(struct device *dev, void *data) { diff --git a/drivers/of/of_mdio.c b/drivers/of/of_mdio.c index 42a6715..1fce00e 100644 --- a/drivers/of/of_mdio.c +++ b/drivers/of/of_mdio.c @@ -15,6 +15,7 @@ #include <linux/err.h> #include <linux/phy.h> #include <linux/of.h> +#include <linux/of_irq.h> #include <linux/of_mdio.h> #include <linux/module.h> diff --git a/drivers/of/of_spi.c b/drivers/of/of_spi.c index 5fed7e3..1dbce58 100644 --- a/drivers/of/of_spi.c +++ b/drivers/of/of_spi.c @@ -9,17 +9,17 @@ #include <linux/of.h> #include <linux/device.h> #include <linux/spi/spi.h> +#include <linux/of_irq.h> #include <linux/of_spi.h> /** * of_register_spi_devices - Register child devices onto the SPI bus * @master: Pointer to spi_master device - * @np: parent node of SPI device nodes * - * Registers an spi_device for each child node of 'np' which has a 'reg' + * Registers an spi_device for each child node of master node which has a 'reg' * property. */ -void of_register_spi_devices(struct spi_master *master, struct device_node *np) +void of_register_spi_devices(struct spi_master *master) { struct spi_device *spi; struct device_node *nc; @@ -27,7 +27,10 @@ void of_register_spi_devices(struct spi_master *master, struct device_node *np) int rc; int len; - for_each_child_of_node(np, nc) { + if (!master->dev.of_node) + return; + + for_each_child_of_node(master->dev.of_node, nc) { /* Alloc an spi_device */ spi = spi_alloc_device(master); if (!spi) { diff --git a/drivers/of/platform.c b/drivers/of/platform.c index 7dacc1e..bb72223 100644 --- a/drivers/of/platform.c +++ b/drivers/of/platform.c @@ -14,8 +14,105 @@ #include <linux/errno.h> #include <linux/module.h> #include <linux/device.h> +#include <linux/dma-mapping.h> +#include <linux/slab.h> +#include <linux/of_address.h> #include <linux/of_device.h> +#include <linux/of_irq.h> #include <linux/of_platform.h> +#include <linux/platform_device.h> + +static int of_dev_node_match(struct device *dev, void *data) +{ + return dev->of_node == data; +} + +/** + * of_find_device_by_node - Find the platform_device associated with a node + * @np: Pointer to device tree node + * + * Returns platform_device pointer, or NULL if not found + */ +struct platform_device *of_find_device_by_node(struct device_node *np) +{ + struct device *dev; + + dev = bus_find_device(&platform_bus_type, NULL, np, of_dev_node_match); + return dev ? to_platform_device(dev) : NULL; +} +EXPORT_SYMBOL(of_find_device_by_node); + +static int platform_driver_probe_shim(struct platform_device *pdev) +{ + struct platform_driver *pdrv; + struct of_platform_driver *ofpdrv; + const struct of_device_id *match; + + pdrv = container_of(pdev->dev.driver, struct platform_driver, driver); + ofpdrv = container_of(pdrv, struct of_platform_driver, platform_driver); + + /* There is an unlikely chance that an of_platform driver might match + * on a non-OF platform device. If so, then of_match_device() will + * come up empty. Return -EINVAL in this case so other drivers get + * the chance to bind. */ + match = of_match_device(pdev->dev.driver->of_match_table, &pdev->dev); + return match ? ofpdrv->probe(pdev, match) : -EINVAL; +} + +static void platform_driver_shutdown_shim(struct platform_device *pdev) +{ + struct platform_driver *pdrv; + struct of_platform_driver *ofpdrv; + + pdrv = container_of(pdev->dev.driver, struct platform_driver, driver); + ofpdrv = container_of(pdrv, struct of_platform_driver, platform_driver); + ofpdrv->shutdown(pdev); +} + +/** + * of_register_platform_driver + */ +int of_register_platform_driver(struct of_platform_driver *drv) +{ + char *of_name; + + /* setup of_platform_driver to platform_driver adaptors */ + drv->platform_driver.driver = drv->driver; + + /* Prefix the driver name with 'of:' to avoid namespace collisions + * and bogus matches. There are some drivers in the tree that + * register both an of_platform_driver and a platform_driver with + * the same name. This is a temporary measure until they are all + * cleaned up --gcl July 29, 2010 */ + of_name = kmalloc(strlen(drv->driver.name) + 5, GFP_KERNEL); + if (!of_name) + return -ENOMEM; + sprintf(of_name, "of:%s", drv->driver.name); + drv->platform_driver.driver.name = of_name; + + if (drv->probe) + drv->platform_driver.probe = platform_driver_probe_shim; + drv->platform_driver.remove = drv->remove; + if (drv->shutdown) + drv->platform_driver.shutdown = platform_driver_shutdown_shim; + drv->platform_driver.suspend = drv->suspend; + drv->platform_driver.resume = drv->resume; + + return platform_driver_register(&drv->platform_driver); +} +EXPORT_SYMBOL(of_register_platform_driver); + +void of_unregister_platform_driver(struct of_platform_driver *drv) +{ + platform_driver_unregister(&drv->platform_driver); + kfree(drv->platform_driver.driver.name); + drv->platform_driver.driver.name = NULL; +} +EXPORT_SYMBOL(of_unregister_platform_driver); + +#if defined(CONFIG_PPC_DCR) +#include <asm/dcr.h> +#endif extern struct device_attribute of_platform_device_attrs[]; @@ -33,11 +130,11 @@ static int of_platform_device_probe(struct device *dev) { int error = -ENODEV; struct of_platform_driver *drv; - struct of_device *of_dev; + struct platform_device *of_dev; const struct of_device_id *match; drv = to_of_platform_driver(dev->driver); - of_dev = to_of_device(dev); + of_dev = to_platform_device(dev); if (!drv->probe) return error; @@ -55,7 +152,7 @@ static int of_platform_device_probe(struct device *dev) static int of_platform_device_remove(struct device *dev) { - struct of_device *of_dev = to_of_device(dev); + struct platform_device *of_dev = to_platform_device(dev); struct of_platform_driver *drv = to_of_platform_driver(dev->driver); if (dev->driver && drv->remove) @@ -65,7 +162,7 @@ static int of_platform_device_remove(struct device *dev) static void of_platform_device_shutdown(struct device *dev) { - struct of_device *of_dev = to_of_device(dev); + struct platform_device *of_dev = to_platform_device(dev); struct of_platform_driver *drv = to_of_platform_driver(dev->driver); if (dev->driver && drv->shutdown) @@ -76,7 +173,7 @@ static void of_platform_device_shutdown(struct device *dev) static int of_platform_legacy_suspend(struct device *dev, pm_message_t mesg) { - struct of_device *of_dev = to_of_device(dev); + struct platform_device *of_dev = to_platform_device(dev); struct of_platform_driver *drv = to_of_platform_driver(dev->driver); int ret = 0; @@ -87,7 +184,7 @@ static int of_platform_legacy_suspend(struct device *dev, pm_message_t mesg) static int of_platform_legacy_resume(struct device *dev) { - struct of_device *of_dev = to_of_device(dev); + struct platform_device *of_dev = to_platform_device(dev); struct of_platform_driver *drv = to_of_platform_driver(dev->driver); int ret = 0; @@ -384,15 +481,286 @@ int of_bus_type_init(struct bus_type *bus, const char *name) int of_register_driver(struct of_platform_driver *drv, struct bus_type *bus) { - drv->driver.bus = bus; + /* + * Temporary: of_platform_bus used to be distinct from the platform + * bus. It isn't anymore, and so drivers on the platform bus need + * to be registered in a special way. + * + * After all of_platform_bus_type drivers are converted to + * platform_drivers, this exception can be removed. + */ + if (bus == &platform_bus_type) + return of_register_platform_driver(drv); /* register with core */ + drv->driver.bus = bus; return driver_register(&drv->driver); } EXPORT_SYMBOL(of_register_driver); void of_unregister_driver(struct of_platform_driver *drv) { - driver_unregister(&drv->driver); + if (drv->driver.bus == &platform_bus_type) + of_unregister_platform_driver(drv); + else + driver_unregister(&drv->driver); } EXPORT_SYMBOL(of_unregister_driver); + +#if !defined(CONFIG_SPARC) +/* + * The following routines scan a subtree and registers a device for + * each applicable node. + * + * Note: sparc doesn't use these routines because it has a different + * mechanism for creating devices from device tree nodes. + */ + +/** + * of_device_make_bus_id - Use the device node data to assign a unique name + * @dev: pointer to device structure that is linked to a device tree node + * + * This routine will first try using either the dcr-reg or the reg property + * value to derive a unique name. As a last resort it will use the node + * name followed by a unique number. + */ +void of_device_make_bus_id(struct device *dev) +{ + static atomic_t bus_no_reg_magic; + struct device_node *node = dev->of_node; + const u32 *reg; + u64 addr; + int magic; + +#ifdef CONFIG_PPC_DCR + /* + * If it's a DCR based device, use 'd' for native DCRs + * and 'D' for MMIO DCRs. + */ + reg = of_get_property(node, "dcr-reg", NULL); + if (reg) { +#ifdef CONFIG_PPC_DCR_NATIVE + dev_set_name(dev, "d%x.%s", *reg, node->name); +#else /* CONFIG_PPC_DCR_NATIVE */ + u64 addr = of_translate_dcr_address(node, *reg, NULL); + if (addr != OF_BAD_ADDR) { + dev_set_name(dev, "D%llx.%s", + (unsigned long long)addr, node->name); + return; + } +#endif /* !CONFIG_PPC_DCR_NATIVE */ + } +#endif /* CONFIG_PPC_DCR */ + + /* + * For MMIO, get the physical address + */ + reg = of_get_property(node, "reg", NULL); + if (reg) { + addr = of_translate_address(node, reg); + if (addr != OF_BAD_ADDR) { + dev_set_name(dev, "%llx.%s", + (unsigned long long)addr, node->name); + return; + } + } + + /* + * No BusID, use the node name and add a globally incremented + * counter (and pray...) + */ + magic = atomic_add_return(1, &bus_no_reg_magic); + dev_set_name(dev, "%s.%d", node->name, magic - 1); +} + +/** + * of_device_alloc - Allocate and initialize an of_device + * @np: device node to assign to device + * @bus_id: Name to assign to the device. May be null to use default name. + * @parent: Parent device. + */ +struct platform_device *of_device_alloc(struct device_node *np, + const char *bus_id, + struct device *parent) +{ + struct platform_device *dev; + int rc, i, num_reg = 0, num_irq = 0; + struct resource *res, temp_res; + + /* First count how many resources are needed */ + while (of_address_to_resource(np, num_reg, &temp_res) == 0) + num_reg++; + while (of_irq_to_resource(np, num_irq, &temp_res) != NO_IRQ) + num_irq++; + + /* Allocate memory for both the struct device and the resource table */ + dev = kzalloc(sizeof(*dev) + (sizeof(*res) * (num_reg + num_irq)), + GFP_KERNEL); + if (!dev) + return NULL; + res = (struct resource *) &dev[1]; + + /* Populate the resource table */ + if (num_irq || num_reg) { + dev->num_resources = num_reg + num_irq; + dev->resource = res; + for (i = 0; i < num_reg; i++, res++) { + rc = of_address_to_resource(np, i, res); + WARN_ON(rc); + } + for (i = 0; i < num_irq; i++, res++) { + rc = of_irq_to_resource(np, i, res); + WARN_ON(rc == NO_IRQ); + } + } + + dev->dev.of_node = of_node_get(np); +#if defined(CONFIG_PPC) || defined(CONFIG_MICROBLAZE) + dev->dev.dma_mask = &dev->archdata.dma_mask; +#endif + dev->dev.parent = parent; + dev->dev.release = of_release_dev; + + if (bus_id) + dev_set_name(&dev->dev, "%s", bus_id); + else + of_device_make_bus_id(&dev->dev); + + return dev; +} +EXPORT_SYMBOL(of_device_alloc); + +/** + * of_platform_device_create - Alloc, initialize and register an of_device + * @np: pointer to node to create device for + * @bus_id: name to assign device + * @parent: Linux device model parent device. + */ +struct platform_device *of_platform_device_create(struct device_node *np, + const char *bus_id, + struct device *parent) +{ + struct platform_device *dev; + + dev = of_device_alloc(np, bus_id, parent); + if (!dev) + return NULL; + +#if defined(CONFIG_PPC) || defined(CONFIG_MICROBLAZE) + dev->archdata.dma_mask = 0xffffffffUL; +#endif + dev->dev.coherent_dma_mask = DMA_BIT_MASK(32); + dev->dev.bus = &platform_bus_type; + + /* We do not fill the DMA ops for platform devices by default. + * This is currently the responsibility of the platform code + * to do such, possibly using a device notifier + */ + + if (of_device_register(dev) != 0) { + of_device_free(dev); + return NULL; + } + + return dev; +} +EXPORT_SYMBOL(of_platform_device_create); + +/** + * of_platform_bus_create - Create an OF device for a bus node and all its + * children. Optionally recursively instantiate matching busses. + * @bus: device node of the bus to instantiate + * @matches: match table, NULL to use the default, OF_NO_DEEP_PROBE to + * disallow recursive creation of child busses + */ +static int of_platform_bus_create(const struct device_node *bus, + const struct of_device_id *matches, + struct device *parent) +{ + struct device_node *child; + struct platform_device *dev; + int rc = 0; + + for_each_child_of_node(bus, child) { + pr_debug(" create child: %s\n", child->full_name); + dev = of_platform_device_create(child, NULL, parent); + if (dev == NULL) + rc = -ENOMEM; + else if (!of_match_node(matches, child)) + continue; + if (rc == 0) { + pr_debug(" and sub busses\n"); + rc = of_platform_bus_create(child, matches, &dev->dev); + } + if (rc) { + of_node_put(child); + break; + } + } + return rc; +} + +/** + * of_platform_bus_probe - Probe the device-tree for platform busses + * @root: parent of the first level to probe or NULL for the root of the tree + * @matches: match table, NULL to use the default + * @parent: parent to hook devices from, NULL for toplevel + * + * Note that children of the provided root are not instantiated as devices + * unless the specified root itself matches the bus list and is not NULL. + */ +int of_platform_bus_probe(struct device_node *root, + const struct of_device_id *matches, + struct device *parent) +{ + struct device_node *child; + struct platform_device *dev; + int rc = 0; + + if (WARN_ON(!matches || matches == OF_NO_DEEP_PROBE)) + return -EINVAL; + if (root == NULL) + root = of_find_node_by_path("/"); + else + of_node_get(root); + if (root == NULL) + return -EINVAL; + + pr_debug("of_platform_bus_probe()\n"); + pr_debug(" starting at: %s\n", root->full_name); + + /* Do a self check of bus type, if there's a match, create + * children + */ + if (of_match_node(matches, root)) { + pr_debug(" root match, create all sub devices\n"); + dev = of_platform_device_create(root, NULL, parent); + if (dev == NULL) { + rc = -ENOMEM; + goto bail; + } + pr_debug(" create all sub busses\n"); + rc = of_platform_bus_create(root, matches, &dev->dev); + goto bail; + } + for_each_child_of_node(root, child) { + if (!of_match_node(matches, child)) + continue; + + pr_debug(" match: %s\n", child->full_name); + dev = of_platform_device_create(child, NULL, parent); + if (dev == NULL) + rc = -ENOMEM; + else + rc = of_platform_bus_create(child, matches, &dev->dev); + if (rc) { + of_node_put(child); + break; + } + } + bail: + of_node_put(root); + return rc; +} +EXPORT_SYMBOL(of_platform_bus_probe); +#endif /* !CONFIG_SPARC */ diff --git a/drivers/oprofile/event_buffer.c b/drivers/oprofile/event_buffer.c index 5df60a6..dd87e86 100644 --- a/drivers/oprofile/event_buffer.c +++ b/drivers/oprofile/event_buffer.c @@ -135,7 +135,7 @@ static int event_buffer_open(struct inode *inode, struct file *file) * echo 1 >/dev/oprofile/enable */ - return 0; + return nonseekable_open(inode, file); fail: dcookie_unregister(file->private_data); @@ -205,4 +205,5 @@ const struct file_operations event_buffer_fops = { .open = event_buffer_open, .release = event_buffer_release, .read = event_buffer_read, + .llseek = no_llseek, }; diff --git a/drivers/parport/parport_sunbpp.c b/drivers/parport/parport_sunbpp.c index 9a5b4b8..210a644 100644 --- a/drivers/parport/parport_sunbpp.c +++ b/drivers/parport/parport_sunbpp.c @@ -295,7 +295,7 @@ static int __devinit bpp_probe(struct of_device *op, const struct of_device_id * void __iomem *base; struct parport *p; - irq = op->irqs[0]; + irq = op->archdata.irqs[0]; base = of_ioremap(&op->resource[0], 0, resource_size(&op->resource[0]), "sunbpp"); @@ -393,12 +393,12 @@ static struct of_platform_driver bpp_sbus_driver = { static int __init parport_sunbpp_init(void) { - return of_register_driver(&bpp_sbus_driver, &of_bus_type); + return of_register_platform_driver(&bpp_sbus_driver); } static void __exit parport_sunbpp_exit(void) { - of_unregister_driver(&bpp_sbus_driver); + of_unregister_platform_driver(&bpp_sbus_driver); } MODULE_AUTHOR("Derrick J Brashear"); diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c index c9171be..6a5af18 100644 --- a/drivers/pci/intel-iommu.c +++ b/drivers/pci/intel-iommu.c @@ -3698,6 +3698,8 @@ static int intel_iommu_domain_has_cap(struct iommu_domain *domain, if (cap == IOMMU_CAP_CACHE_COHERENCY) return dmar_domain->iommu_snooping; + if (cap == IOMMU_CAP_INTR_REMAP) + return intr_remapping_enabled; return 0; } diff --git a/drivers/pci/intr_remapping.c b/drivers/pci/intr_remapping.c index 1315ac6..1694a0e 100644 --- a/drivers/pci/intr_remapping.c +++ b/drivers/pci/intr_remapping.c @@ -311,8 +311,8 @@ int modify_irte(int irq, struct irte *irte_modified) index = irq_iommu->irte_index + irq_iommu->sub_handle; irte = &iommu->ir_table->base[index]; - set_64bit((unsigned long *)&irte->low, irte_modified->low); - set_64bit((unsigned long *)&irte->high, irte_modified->high); + set_64bit(&irte->low, irte_modified->low); + set_64bit(&irte->high, irte_modified->high); __iommu_flush_cache(iommu, irte, sizeof(*irte)); rc = qi_flush_iec(iommu, index, 0); @@ -393,8 +393,8 @@ static int clear_entries(struct irq_2_iommu *irq_iommu) end = start + (1 << irq_iommu->irte_mask); for (entry = start; entry < end; entry++) { - set_64bit((unsigned long *)&entry->low, 0); - set_64bit((unsigned long *)&entry->high, 0); + set_64bit(&entry->low, 0); + set_64bit(&entry->high, 0); } return qi_flush_iec(iommu, index, irq_iommu->irte_mask); diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 477345d..a0c20d9 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -1459,6 +1459,7 @@ static void quirk_jmicron_ata(struct pci_dev *pdev) switch (pdev->device) { case PCI_DEVICE_ID_JMICRON_JMB360: /* SATA single port */ case PCI_DEVICE_ID_JMICRON_JMB362: /* SATA dual ports */ + case PCI_DEVICE_ID_JMICRON_JMB364: /* SATA dual ports */ /* The controller should be in single function ahci mode */ conf1 |= 0x0002A100; /* Set 8, 13, 15, 17 */ break; @@ -1470,6 +1471,7 @@ static void quirk_jmicron_ata(struct pci_dev *pdev) /* Fall through */ case PCI_DEVICE_ID_JMICRON_JMB361: case PCI_DEVICE_ID_JMICRON_JMB363: + case PCI_DEVICE_ID_JMICRON_JMB369: /* Enable dual function mode, AHCI on fn 0, IDE fn1 */ /* Set the class codes correctly and then direct IDE 0 */ conf1 |= 0x00C2A1B3; /* Set 0, 1, 4, 5, 7, 8, 13, 15, 17, 22, 23 */ @@ -1496,16 +1498,20 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB360, qui DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB361, quirk_jmicron_ata); DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB362, quirk_jmicron_ata); DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB363, quirk_jmicron_ata); +DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB364, quirk_jmicron_ata); DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB365, quirk_jmicron_ata); DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB366, quirk_jmicron_ata); DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB368, quirk_jmicron_ata); +DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB369, quirk_jmicron_ata); DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB360, quirk_jmicron_ata); DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB361, quirk_jmicron_ata); DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB362, quirk_jmicron_ata); DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB363, quirk_jmicron_ata); +DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB364, quirk_jmicron_ata); DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB365, quirk_jmicron_ata); DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB366, quirk_jmicron_ata); DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB368, quirk_jmicron_ata); +DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB369, quirk_jmicron_ata); #endif diff --git a/drivers/sbus/char/bbc_i2c.c b/drivers/sbus/char/bbc_i2c.c index 8bfdd63..3e89c31 100644 --- a/drivers/sbus/char/bbc_i2c.c +++ b/drivers/sbus/char/bbc_i2c.c @@ -317,7 +317,7 @@ static struct bbc_i2c_bus * __init attach_one_i2c(struct of_device *op, int inde bp->waiting = 0; init_waitqueue_head(&bp->wq); - if (request_irq(op->irqs[0], bbc_i2c_interrupt, + if (request_irq(op->archdata.irqs[0], bbc_i2c_interrupt, IRQF_SHARED, "bbc_i2c", bp)) goto fail; @@ -373,7 +373,7 @@ static int __devinit bbc_i2c_probe(struct of_device *op, err = bbc_envctrl_init(bp); if (err) { - free_irq(op->irqs[0], bp); + free_irq(op->archdata.irqs[0], bp); if (bp->i2c_bussel_reg) of_iounmap(&op->resource[0], bp->i2c_bussel_reg, 1); if (bp->i2c_control_regs) @@ -392,7 +392,7 @@ static int __devexit bbc_i2c_remove(struct of_device *op) bbc_envctrl_cleanup(bp); - free_irq(op->irqs[0], bp); + free_irq(op->archdata.irqs[0], bp); if (bp->i2c_bussel_reg) of_iounmap(&op->resource[0], bp->i2c_bussel_reg, 1); @@ -425,12 +425,12 @@ static struct of_platform_driver bbc_i2c_driver = { static int __init bbc_i2c_init(void) { - return of_register_driver(&bbc_i2c_driver, &of_bus_type); + return of_register_platform_driver(&bbc_i2c_driver); } static void __exit bbc_i2c_exit(void) { - of_unregister_driver(&bbc_i2c_driver); + of_unregister_platform_driver(&bbc_i2c_driver); } module_init(bbc_i2c_init); diff --git a/drivers/sbus/char/display7seg.c b/drivers/sbus/char/display7seg.c index 4ad4d2c..47db975 100644 --- a/drivers/sbus/char/display7seg.c +++ b/drivers/sbus/char/display7seg.c @@ -277,12 +277,12 @@ static struct of_platform_driver d7s_driver = { static int __init d7s_init(void) { - return of_register_driver(&d7s_driver, &of_bus_type); + return of_register_platform_driver(&d7s_driver); } static void __exit d7s_exit(void) { - of_unregister_driver(&d7s_driver); + of_unregister_platform_driver(&d7s_driver); } module_init(d7s_init); diff --git a/drivers/sbus/char/envctrl.c b/drivers/sbus/char/envctrl.c index bd0bbc6..3c27f45 100644 --- a/drivers/sbus/char/envctrl.c +++ b/drivers/sbus/char/envctrl.c @@ -1140,12 +1140,12 @@ static struct of_platform_driver envctrl_driver = { static int __init envctrl_init(void) { - return of_register_driver(&envctrl_driver, &of_bus_type); + return of_register_platform_driver(&envctrl_driver); } static void __exit envctrl_exit(void) { - of_unregister_driver(&envctrl_driver); + of_unregister_platform_driver(&envctrl_driver); } module_init(envctrl_init); diff --git a/drivers/sbus/char/flash.c b/drivers/sbus/char/flash.c index ed9494e..8bb31c5 100644 --- a/drivers/sbus/char/flash.c +++ b/drivers/sbus/char/flash.c @@ -219,12 +219,12 @@ static struct of_platform_driver flash_driver = { static int __init flash_init(void) { - return of_register_driver(&flash_driver, &of_bus_type); + return of_register_platform_driver(&flash_driver); } static void __exit flash_cleanup(void) { - of_unregister_driver(&flash_driver); + of_unregister_platform_driver(&flash_driver); } module_init(flash_init); diff --git a/drivers/sbus/char/uctrl.c b/drivers/sbus/char/uctrl.c index 079da4c..41eb672 100644 --- a/drivers/sbus/char/uctrl.c +++ b/drivers/sbus/char/uctrl.c @@ -368,7 +368,7 @@ static int __devinit uctrl_probe(struct of_device *op, goto out_free; } - p->irq = op->irqs[0]; + p->irq = op->archdata.irqs[0]; err = request_irq(p->irq, uctrl_interrupt, 0, "uctrl", p); if (err) { printk(KERN_ERR "uctrl: Unable to register irq.\n"); @@ -438,12 +438,12 @@ static struct of_platform_driver uctrl_driver = { static int __init uctrl_init(void) { - return of_register_driver(&uctrl_driver, &of_bus_type); + return of_register_platform_driver(&uctrl_driver); } static void __exit uctrl_exit(void) { - of_unregister_driver(&uctrl_driver); + of_unregister_platform_driver(&uctrl_driver); } module_init(uctrl_init); diff --git a/drivers/scsi/qlogicpti.c b/drivers/scsi/qlogicpti.c index ca5c15c..53d7ed0 100644 --- a/drivers/scsi/qlogicpti.c +++ b/drivers/scsi/qlogicpti.c @@ -729,7 +729,7 @@ static int __devinit qpti_register_irq(struct qlogicpti *qpti) { struct of_device *op = qpti->op; - qpti->qhost->irq = qpti->irq = op->irqs[0]; + qpti->qhost->irq = qpti->irq = op->archdata.irqs[0]; /* We used to try various overly-clever things to * reduce the interrupt processing overhead on @@ -1302,7 +1302,7 @@ static int __devinit qpti_sbus_probe(struct of_device *op, const struct of_devic /* Sometimes Antares cards come up not completely * setup, and we get a report of a zero IRQ. */ - if (op->irqs[0] == 0) + if (op->archdata.irqs[0] == 0) return -ENODEV; host = scsi_host_alloc(tpnt, sizeof(struct qlogicpti)); @@ -1467,12 +1467,12 @@ static struct of_platform_driver qpti_sbus_driver = { static int __init qpti_init(void) { - return of_register_driver(&qpti_sbus_driver, &of_bus_type); + return of_register_platform_driver(&qpti_sbus_driver); } static void __exit qpti_exit(void) { - of_unregister_driver(&qpti_sbus_driver); + of_unregister_platform_driver(&qpti_sbus_driver); } MODULE_DESCRIPTION("QlogicISP SBUS driver"); diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h index 026295e..b4056d1 100644 --- a/drivers/scsi/scsi_priv.h +++ b/drivers/scsi/scsi_priv.h @@ -148,8 +148,6 @@ static inline void scsi_netlink_exit(void) {} /* scsi_pm.c */ #ifdef CONFIG_PM_OPS extern const struct dev_pm_ops scsi_bus_pm_ops; -#else /* CONFIG_PM_OPS */ -#define scsi_bus_pm_ops (*NULL) #endif #ifdef CONFIG_PM_RUNTIME extern void scsi_autopm_get_target(struct scsi_target *); diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index 562fb3b..c3f6737 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -381,7 +381,9 @@ struct bus_type scsi_bus_type = { .name = "scsi", .match = scsi_bus_match, .uevent = scsi_bus_uevent, +#ifdef CONFIG_PM_OPS .pm = &scsi_bus_pm_ops, +#endif }; EXPORT_SYMBOL_GPL(scsi_bus_type); diff --git a/drivers/scsi/sun_esp.c b/drivers/scsi/sun_esp.c index 386dd9d..89ba6fe 100644 --- a/drivers/scsi/sun_esp.c +++ b/drivers/scsi/sun_esp.c @@ -116,7 +116,7 @@ static int __devinit esp_sbus_register_irq(struct esp *esp) struct Scsi_Host *host = esp->host; struct of_device *op = esp->dev; - host->irq = op->irqs[0]; + host->irq = op->archdata.irqs[0]; return request_irq(host->irq, scsi_esp_intr, IRQF_SHARED, "ESP", esp); } @@ -644,12 +644,12 @@ static struct of_platform_driver esp_sbus_driver = { static int __init sunesp_init(void) { - return of_register_driver(&esp_sbus_driver, &of_bus_type); + return of_register_platform_driver(&esp_sbus_driver); } static void __exit sunesp_exit(void) { - of_unregister_driver(&esp_sbus_driver); + of_unregister_platform_driver(&esp_sbus_driver); } MODULE_DESCRIPTION("Sun ESP SCSI driver"); diff --git a/drivers/serial/kgdboc.c b/drivers/serial/kgdboc.c index a9a94ae..39f9a1a 100644 --- a/drivers/serial/kgdboc.c +++ b/drivers/serial/kgdboc.c @@ -17,6 +17,7 @@ #include <linux/kdb.h> #include <linux/tty.h> #include <linux/console.h> +#include <linux/vt_kern.h> #define MAX_CONFIG_LEN 40 @@ -31,6 +32,7 @@ static struct kparam_string kps = { .maxlen = MAX_CONFIG_LEN, }; +static int kgdboc_use_kms; /* 1 if we use kernel mode switching */ static struct tty_driver *kgdb_tty_driver; static int kgdb_tty_line; @@ -104,6 +106,12 @@ static int configure_kgdboc(void) kgdboc_io_ops.is_console = 0; kgdb_tty_driver = NULL; + kgdboc_use_kms = 0; + if (strncmp(cptr, "kms,", 4) == 0) { + cptr += 4; + kgdboc_use_kms = 1; + } + if (kgdboc_register_kbd(&cptr)) goto do_register; @@ -201,8 +209,14 @@ static int param_set_kgdboc_var(const char *kmessage, struct kernel_param *kp) return configure_kgdboc(); } +static int dbg_restore_graphics; + static void kgdboc_pre_exp_handler(void) { + if (!dbg_restore_graphics && kgdboc_use_kms) { + dbg_restore_graphics = 1; + con_debug_enter(vc_cons[fg_console].d); + } /* Increment the module count when the debugger is active */ if (!kgdb_connected) try_module_get(THIS_MODULE); @@ -213,6 +227,10 @@ static void kgdboc_post_exp_handler(void) /* decrement the module count when the debugger detaches */ if (!kgdb_connected) module_put(THIS_MODULE); + if (kgdboc_use_kms && dbg_restore_graphics) { + dbg_restore_graphics = 0; + con_debug_leave(); + } } static struct kgdb_io kgdboc_io_ops = { diff --git a/drivers/serial/sunhv.c b/drivers/serial/sunhv.c index 890f917..a779e22 100644 --- a/drivers/serial/sunhv.c +++ b/drivers/serial/sunhv.c @@ -525,7 +525,7 @@ static int __devinit hv_probe(struct of_device *op, const struct of_device_id *m unsigned long minor; int err; - if (op->irqs[0] == 0xffffffff) + if (op->archdata.irqs[0] == 0xffffffff) return -ENODEV; port = kzalloc(sizeof(struct uart_port), GFP_KERNEL); @@ -557,7 +557,7 @@ static int __devinit hv_probe(struct of_device *op, const struct of_device_id *m port->membase = (unsigned char __iomem *) __pa(port); - port->irq = op->irqs[0]; + port->irq = op->archdata.irqs[0]; port->dev = &op->dev; @@ -644,12 +644,12 @@ static int __init sunhv_init(void) if (tlb_type != hypervisor) return -ENODEV; - return of_register_driver(&hv_driver, &of_bus_type); + return of_register_platform_driver(&hv_driver); } static void __exit sunhv_exit(void) { - of_unregister_driver(&hv_driver); + of_unregister_platform_driver(&hv_driver); } module_init(sunhv_init); diff --git a/drivers/serial/sunsab.c b/drivers/serial/sunsab.c index 5e81bc6..9845fb1 100644 --- a/drivers/serial/sunsab.c +++ b/drivers/serial/sunsab.c @@ -969,7 +969,7 @@ static int __devinit sunsab_init_one(struct uart_sunsab_port *up, return -ENOMEM; up->regs = (union sab82532_async_regs __iomem *) up->port.membase; - up->port.irq = op->irqs[0]; + up->port.irq = op->archdata.irqs[0]; up->port.fifosize = SAB82532_XMIT_FIFO_SIZE; up->port.iotype = UPIO_MEM; @@ -1130,12 +1130,12 @@ static int __init sunsab_init(void) } } - return of_register_driver(&sab_driver, &of_bus_type); + return of_register_platform_driver(&sab_driver); } static void __exit sunsab_exit(void) { - of_unregister_driver(&sab_driver); + of_unregister_platform_driver(&sab_driver); if (sunsab_reg.nr) { sunserial_unregister_minors(&sunsab_reg, sunsab_reg.nr); } diff --git a/drivers/serial/sunsu.c b/drivers/serial/sunsu.c index ffbf455..3cdf748 100644 --- a/drivers/serial/sunsu.c +++ b/drivers/serial/sunsu.c @@ -1443,7 +1443,7 @@ static int __devinit su_probe(struct of_device *op, const struct of_device_id *m return -ENOMEM; } - up->port.irq = op->irqs[0]; + up->port.irq = op->archdata.irqs[0]; up->port.dev = &op->dev; @@ -1586,7 +1586,7 @@ static int __init sunsu_init(void) return err; } - err = of_register_driver(&su_driver, &of_bus_type); + err = of_register_platform_driver(&su_driver); if (err && num_uart) sunserial_unregister_minors(&sunsu_reg, num_uart); diff --git a/drivers/serial/sunzilog.c b/drivers/serial/sunzilog.c index f9a24f4..d1e6bcb 100644 --- a/drivers/serial/sunzilog.c +++ b/drivers/serial/sunzilog.c @@ -1426,7 +1426,7 @@ static int __devinit zs_probe(struct of_device *op, const struct of_device_id *m rp = sunzilog_chip_regs[inst]; if (zilog_irq == -1) - zilog_irq = op->irqs[0]; + zilog_irq = op->archdata.irqs[0]; up = &sunzilog_port_table[inst * 2]; @@ -1434,7 +1434,7 @@ static int __devinit zs_probe(struct of_device *op, const struct of_device_id *m up[0].port.mapbase = op->resource[0].start + 0x00; up[0].port.membase = (void __iomem *) &rp->channelA; up[0].port.iotype = UPIO_MEM; - up[0].port.irq = op->irqs[0]; + up[0].port.irq = op->archdata.irqs[0]; up[0].port.uartclk = ZS_CLOCK; up[0].port.fifosize = 1; up[0].port.ops = &sunzilog_pops; @@ -1451,7 +1451,7 @@ static int __devinit zs_probe(struct of_device *op, const struct of_device_id *m up[1].port.mapbase = op->resource[0].start + 0x04; up[1].port.membase = (void __iomem *) &rp->channelB; up[1].port.iotype = UPIO_MEM; - up[1].port.irq = op->irqs[0]; + up[1].port.irq = op->archdata.irqs[0]; up[1].port.uartclk = ZS_CLOCK; up[1].port.fifosize = 1; up[1].port.ops = &sunzilog_pops; @@ -1492,12 +1492,12 @@ static int __devinit zs_probe(struct of_device *op, const struct of_device_id *m "is a %s\n", dev_name(&op->dev), (unsigned long long) up[0].port.mapbase, - op->irqs[0], sunzilog_type(&up[0].port)); + op->archdata.irqs[0], sunzilog_type(&up[0].port)); printk(KERN_INFO "%s: Mouse at MMIO 0x%llx (irq = %d) " "is a %s\n", dev_name(&op->dev), (unsigned long long) up[1].port.mapbase, - op->irqs[0], sunzilog_type(&up[1].port)); + op->archdata.irqs[0], sunzilog_type(&up[1].port)); kbm_inst++; } @@ -1576,7 +1576,7 @@ static int __init sunzilog_init(void) goto out_free_tables; } - err = of_register_driver(&zs_driver, &of_bus_type); + err = of_register_platform_driver(&zs_driver); if (err) goto out_unregister_uart; @@ -1604,7 +1604,7 @@ out: return err; out_unregister_driver: - of_unregister_driver(&zs_driver); + of_unregister_platform_driver(&zs_driver); out_unregister_uart: if (num_sunzilog) { @@ -1619,7 +1619,7 @@ out_free_tables: static void __exit sunzilog_exit(void) { - of_unregister_driver(&zs_driver); + of_unregister_platform_driver(&zs_driver); if (zilog_irq != -1) { struct uart_sunzilog_port *up = sunzilog_irq_chain; diff --git a/drivers/serial/uartlite.c b/drivers/serial/uartlite.c index 8acccd5..caf085d 100644 --- a/drivers/serial/uartlite.c +++ b/drivers/serial/uartlite.c @@ -21,6 +21,7 @@ #include <asm/io.h> #if defined(CONFIG_OF) && (defined(CONFIG_PPC32) || defined(CONFIG_MICROBLAZE)) #include <linux/of.h> +#include <linux/of_address.h> #include <linux/of_device.h> #include <linux/of_platform.h> diff --git a/drivers/spi/mpc512x_psc_spi.c b/drivers/spi/mpc512x_psc_spi.c index 2534b1e..10baac3 100644 --- a/drivers/spi/mpc512x_psc_spi.c +++ b/drivers/spi/mpc512x_psc_spi.c @@ -19,6 +19,7 @@ #include <linux/init.h> #include <linux/errno.h> #include <linux/interrupt.h> +#include <linux/of_address.h> #include <linux/of_platform.h> #include <linux/workqueue.h> #include <linux/completion.h> @@ -440,6 +441,7 @@ static int __init mpc512x_psc_spi_do_probe(struct device *dev, u32 regaddr, master->setup = mpc512x_psc_spi_setup; master->transfer = mpc512x_psc_spi_transfer; master->cleanup = mpc512x_psc_spi_cleanup; + master->dev.of_node = dev->of_node; tempp = ioremap(regaddr, size); if (!tempp) { diff --git a/drivers/spi/mpc52xx_psc_spi.c b/drivers/spi/mpc52xx_psc_spi.c index 7104cb7..66d1701 100644 --- a/drivers/spi/mpc52xx_psc_spi.c +++ b/drivers/spi/mpc52xx_psc_spi.c @@ -16,8 +16,8 @@ #include <linux/types.h> #include <linux/errno.h> #include <linux/interrupt.h> +#include <linux/of_address.h> #include <linux/of_platform.h> -#include <linux/of_spi.h> #include <linux/workqueue.h> #include <linux/completion.h> #include <linux/io.h> @@ -398,6 +398,7 @@ static int __init mpc52xx_psc_spi_do_probe(struct device *dev, u32 regaddr, master->setup = mpc52xx_psc_spi_setup; master->transfer = mpc52xx_psc_spi_transfer; master->cleanup = mpc52xx_psc_spi_cleanup; + master->dev.of_node = dev->of_node; mps->psc = ioremap(regaddr, size); if (!mps->psc) { @@ -470,7 +471,6 @@ static int __init mpc52xx_psc_spi_of_probe(struct of_device *op, const u32 *regaddr_p; u64 regaddr64, size64; s16 id = -1; - int rc; regaddr_p = of_get_address(op->dev.of_node, 0, &size64, NULL); if (!regaddr_p) { @@ -491,13 +491,8 @@ static int __init mpc52xx_psc_spi_of_probe(struct of_device *op, id = *psc_nump + 1; } - rc = mpc52xx_psc_spi_do_probe(&op->dev, (u32)regaddr64, (u32)size64, + return mpc52xx_psc_spi_do_probe(&op->dev, (u32)regaddr64, (u32)size64, irq_of_parse_and_map(op->dev.of_node, 0), id); - if (rc == 0) - of_register_spi_devices(dev_get_drvdata(&op->dev), - op->dev.of_node); - - return rc; } static int __exit mpc52xx_psc_spi_of_remove(struct of_device *op) diff --git a/drivers/spi/mpc52xx_spi.c b/drivers/spi/mpc52xx_spi.c index b1a76bf..56136ff 100644 --- a/drivers/spi/mpc52xx_spi.c +++ b/drivers/spi/mpc52xx_spi.c @@ -18,7 +18,6 @@ #include <linux/interrupt.h> #include <linux/delay.h> #include <linux/spi/spi.h> -#include <linux/of_spi.h> #include <linux/io.h> #include <linux/of_gpio.h> #include <linux/slab.h> @@ -439,6 +438,7 @@ static int __devinit mpc52xx_spi_probe(struct of_device *op, master->setup = mpc52xx_spi_setup; master->transfer = mpc52xx_spi_transfer; master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST; + master->dev.of_node = op->dev.of_node; dev_set_drvdata(&op->dev, master); @@ -512,7 +512,6 @@ static int __devinit mpc52xx_spi_probe(struct of_device *op, if (rc) goto err_register; - of_register_spi_devices(master, op->dev.of_node); dev_info(&ms->master->dev, "registered MPC5200 SPI bus\n"); return rc; diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index b3a1f92..1bb1b88 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -26,6 +26,7 @@ #include <linux/slab.h> #include <linux/mod_devicetable.h> #include <linux/spi/spi.h> +#include <linux/of_spi.h> /* SPI bustype and spi_master class are registered after board init code @@ -540,6 +541,9 @@ int spi_register_master(struct spi_master *master) /* populate children from any spi device tables */ scan_boardinfo(master); status = 0; + + /* Register devices from the device tree */ + of_register_spi_devices(master); done: return status; } diff --git a/drivers/spi/spi_mpc8xxx.c b/drivers/spi/spi_mpc8xxx.c index 97ab0a8..aad9ae1 100644 --- a/drivers/spi/spi_mpc8xxx.c +++ b/drivers/spi/spi_mpc8xxx.c @@ -38,7 +38,6 @@ #include <linux/of_platform.h> #include <linux/gpio.h> #include <linux/of_gpio.h> -#include <linux/of_spi.h> #include <linux/slab.h> #include <sysdev/fsl_soc.h> @@ -1009,6 +1008,7 @@ mpc8xxx_spi_probe(struct device *dev, struct resource *mem, unsigned int irq) master->setup = mpc8xxx_spi_setup; master->transfer = mpc8xxx_spi_transfer; master->cleanup = mpc8xxx_spi_cleanup; + master->dev.of_node = dev->of_node; mpc8xxx_spi = spi_master_get_devdata(master); mpc8xxx_spi->dev = dev; @@ -1299,8 +1299,6 @@ static int __devinit of_mpc8xxx_spi_probe(struct of_device *ofdev, goto err; } - of_register_spi_devices(master, np); - return 0; err: diff --git a/drivers/spi/spi_ppc4xx.c b/drivers/spi/spi_ppc4xx.c index d53466a..0f5fa7e 100644 --- a/drivers/spi/spi_ppc4xx.c +++ b/drivers/spi/spi_ppc4xx.c @@ -407,6 +407,7 @@ static int __init spi_ppc4xx_of_probe(struct of_device *op, master = spi_alloc_master(dev, sizeof *hw); if (master == NULL) return -ENOMEM; + master->dev.of_node = np; dev_set_drvdata(dev, master); hw = spi_master_get_devdata(master); hw->master = spi_master_get(master); @@ -545,7 +546,6 @@ static int __init spi_ppc4xx_of_probe(struct of_device *op, } dev_info(dev, "driver initialized\n"); - of_register_spi_devices(master, np); return 0; diff --git a/drivers/spi/xilinx_spi.c b/drivers/spi/xilinx_spi.c index 1b47363..80f2db5 100644 --- a/drivers/spi/xilinx_spi.c +++ b/drivers/spi/xilinx_spi.c @@ -390,6 +390,9 @@ struct spi_master *xilinx_spi_init(struct device *dev, struct resource *mem, master->bus_num = bus_num; master->num_chipselect = pdata->num_chipselect; +#ifdef CONFIG_OF + master->dev.of_node = dev->of_node; +#endif xspi->mem = *mem; xspi->irq = irq; diff --git a/drivers/spi/xilinx_spi_of.c b/drivers/spi/xilinx_spi_of.c index 4654805..f53d3f6 100644 --- a/drivers/spi/xilinx_spi_of.c +++ b/drivers/spi/xilinx_spi_of.c @@ -29,6 +29,7 @@ #include <linux/io.h> #include <linux/slab.h> +#include <linux/of_address.h> #include <linux/of_platform.h> #include <linux/of_device.h> #include <linux/of_spi.h> @@ -80,9 +81,6 @@ static int __devinit xilinx_spi_of_probe(struct of_device *ofdev, dev_set_drvdata(&ofdev->dev, master); - /* Add any subnodes on the SPI bus */ - of_register_spi_devices(master, ofdev->dev.of_node); - return 0; } diff --git a/drivers/usb/gadget/fsl_qe_udc.c b/drivers/usb/gadget/fsl_qe_udc.c index 82506ca..9648b75 100644 --- a/drivers/usb/gadget/fsl_qe_udc.c +++ b/drivers/usb/gadget/fsl_qe_udc.c @@ -32,6 +32,7 @@ #include <linux/interrupt.h> #include <linux/io.h> #include <linux/moduleparam.h> +#include <linux/of_address.h> #include <linux/of_platform.h> #include <linux/dma-mapping.h> #include <linux/usb/ch9.h> diff --git a/drivers/video/bw2.c b/drivers/video/bw2.c index 09f1b9b..c779663 100644 --- a/drivers/video/bw2.c +++ b/drivers/video/bw2.c @@ -390,12 +390,12 @@ static int __init bw2_init(void) if (fb_get_options("bw2fb", NULL)) return -ENODEV; - return of_register_driver(&bw2_driver, &of_bus_type); + return of_register_platform_driver(&bw2_driver); } static void __exit bw2_exit(void) { - of_unregister_driver(&bw2_driver); + of_unregister_platform_driver(&bw2_driver); } module_init(bw2_init); diff --git a/drivers/video/cg14.c b/drivers/video/cg14.c index e5dc224..d09fde8 100644 --- a/drivers/video/cg14.c +++ b/drivers/video/cg14.c @@ -610,12 +610,12 @@ static int __init cg14_init(void) if (fb_get_options("cg14fb", NULL)) return -ENODEV; - return of_register_driver(&cg14_driver, &of_bus_type); + return of_register_platform_driver(&cg14_driver); } static void __exit cg14_exit(void) { - of_unregister_driver(&cg14_driver); + of_unregister_platform_driver(&cg14_driver); } module_init(cg14_init); diff --git a/drivers/video/cg3.c b/drivers/video/cg3.c index 558d73a..64aa298 100644 --- a/drivers/video/cg3.c +++ b/drivers/video/cg3.c @@ -477,12 +477,12 @@ static int __init cg3_init(void) if (fb_get_options("cg3fb", NULL)) return -ENODEV; - return of_register_driver(&cg3_driver, &of_bus_type); + return of_register_platform_driver(&cg3_driver); } static void __exit cg3_exit(void) { - of_unregister_driver(&cg3_driver); + of_unregister_platform_driver(&cg3_driver); } module_init(cg3_init); diff --git a/drivers/video/cg6.c b/drivers/video/cg6.c index 480d761..2389a71 100644 --- a/drivers/video/cg6.c +++ b/drivers/video/cg6.c @@ -870,12 +870,12 @@ static int __init cg6_init(void) if (fb_get_options("cg6fb", NULL)) return -ENODEV; - return of_register_driver(&cg6_driver, &of_bus_type); + return of_register_platform_driver(&cg6_driver); } static void __exit cg6_exit(void) { - of_unregister_driver(&cg6_driver); + of_unregister_platform_driver(&cg6_driver); } module_init(cg6_init); diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c index b0a3fa0..3b3f574 100644 --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c @@ -2342,6 +2342,30 @@ static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch) return 0; } +static int fbcon_debug_enter(struct vc_data *vc) +{ + struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; + struct fbcon_ops *ops = info->fbcon_par; + + ops->save_graphics = ops->graphics; + ops->graphics = 0; + if (info->fbops->fb_debug_enter) + info->fbops->fb_debug_enter(info); + fbcon_set_palette(vc, color_table); + return 0; +} + +static int fbcon_debug_leave(struct vc_data *vc) +{ + struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; + struct fbcon_ops *ops = info->fbcon_par; + + ops->graphics = ops->save_graphics; + if (info->fbops->fb_debug_leave) + info->fbops->fb_debug_leave(info); + return 0; +} + static int fbcon_get_font(struct vc_data *vc, struct console_font *font) { u8 *fontdata = vc->vc_font.data; @@ -3276,6 +3300,8 @@ static const struct consw fb_con = { .con_screen_pos = fbcon_screen_pos, .con_getxy = fbcon_getxy, .con_resize = fbcon_resize, + .con_debug_enter = fbcon_debug_enter, + .con_debug_leave = fbcon_debug_leave, }; static struct notifier_block fbcon_event_notifier = { diff --git a/drivers/video/console/fbcon.h b/drivers/video/console/fbcon.h index 89a34688..6bd2e0c 100644 --- a/drivers/video/console/fbcon.h +++ b/drivers/video/console/fbcon.h @@ -74,6 +74,7 @@ struct fbcon_ops { int cursor_reset; int blank_state; int graphics; + int save_graphics; /* for debug enter/leave */ int flags; int rotate; int cur_rotate; diff --git a/drivers/video/controlfb.c b/drivers/video/controlfb.c index 49fcbe8..c225dcc 100644 --- a/drivers/video/controlfb.c +++ b/drivers/video/controlfb.c @@ -40,6 +40,8 @@ #include <linux/vmalloc.h> #include <linux/delay.h> #include <linux/interrupt.h> +#include <linux/of.h> +#include <linux/of_address.h> #include <linux/fb.h> #include <linux/init.h> #include <linux/pci.h> diff --git a/drivers/video/ffb.c b/drivers/video/ffb.c index 95c0227..f6ecfab 100644 --- a/drivers/video/ffb.c +++ b/drivers/video/ffb.c @@ -1067,12 +1067,12 @@ static int __init ffb_init(void) if (fb_get_options("ffb", NULL)) return -ENODEV; - return of_register_driver(&ffb_driver, &of_bus_type); + return of_register_platform_driver(&ffb_driver); } static void __exit ffb_exit(void) { - of_unregister_driver(&ffb_driver); + of_unregister_platform_driver(&ffb_driver); } module_init(ffb_init); diff --git a/drivers/video/leo.c b/drivers/video/leo.c index 9e8bf7d..ad67763 100644 --- a/drivers/video/leo.c +++ b/drivers/video/leo.c @@ -677,12 +677,12 @@ static int __init leo_init(void) if (fb_get_options("leofb", NULL)) return -ENODEV; - return of_register_driver(&leo_driver, &of_bus_type); + return of_register_platform_driver(&leo_driver); } static void __exit leo_exit(void) { - of_unregister_driver(&leo_driver); + of_unregister_platform_driver(&leo_driver); } module_init(leo_init); diff --git a/drivers/video/offb.c b/drivers/video/offb.c index 46dda7d..cb163a5 100644 --- a/drivers/video/offb.c +++ b/drivers/video/offb.c @@ -19,13 +19,14 @@ #include <linux/mm.h> #include <linux/vmalloc.h> #include <linux/delay.h> +#include <linux/of.h> +#include <linux/of_address.h> #include <linux/interrupt.h> #include <linux/fb.h> #include <linux/init.h> #include <linux/ioport.h> #include <linux/pci.h> #include <asm/io.h> -#include <asm/prom.h> #ifdef CONFIG_PPC64 #include <asm/pci-bridge.h> diff --git a/drivers/video/p9100.c b/drivers/video/p9100.c index 6552751..688b055 100644 --- a/drivers/video/p9100.c +++ b/drivers/video/p9100.c @@ -367,12 +367,12 @@ static int __init p9100_init(void) if (fb_get_options("p9100fb", NULL)) return -ENODEV; - return of_register_driver(&p9100_driver, &of_bus_type); + return of_register_platform_driver(&p9100_driver); } static void __exit p9100_exit(void) { - of_unregister_driver(&p9100_driver); + of_unregister_platform_driver(&p9100_driver); } module_init(p9100_init); diff --git a/drivers/video/sunxvr1000.c b/drivers/video/sunxvr1000.c index 489b44e..7288934 100644 --- a/drivers/video/sunxvr1000.c +++ b/drivers/video/sunxvr1000.c @@ -213,12 +213,12 @@ static int __init gfb_init(void) if (fb_get_options("gfb", NULL)) return -ENODEV; - return of_register_driver(&gfb_driver, &of_bus_type); + return of_register_platform_driver(&gfb_driver); } static void __exit gfb_exit(void) { - of_unregister_driver(&gfb_driver); + of_unregister_platform_driver(&gfb_driver); } module_init(gfb_init); diff --git a/drivers/video/tcx.c b/drivers/video/tcx.c index cc039b3..f375e0d 100644 --- a/drivers/video/tcx.c +++ b/drivers/video/tcx.c @@ -526,12 +526,12 @@ static int __init tcx_init(void) if (fb_get_options("tcxfb", NULL)) return -ENODEV; - return of_register_driver(&tcx_driver, &of_bus_type); + return of_register_platform_driver(&tcx_driver); } static void __exit tcx_exit(void) { - of_unregister_driver(&tcx_driver); + of_unregister_platform_driver(&tcx_driver); } module_init(tcx_init); diff --git a/drivers/video/xen-fbfront.c b/drivers/video/xen-fbfront.c index fa97d3e..7c7f42a12 100644 --- a/drivers/video/xen-fbfront.c +++ b/drivers/video/xen-fbfront.c @@ -684,7 +684,7 @@ static struct xenbus_driver xenfb_driver = { static int __init xenfb_init(void) { - if (!xen_domain()) + if (!xen_pv_domain()) return -ENODEV; /* Nothing to do if running in dom0. */ diff --git a/drivers/watchdog/cpwd.c b/drivers/watchdog/cpwd.c index d62b9ce..30a2512 100644 --- a/drivers/watchdog/cpwd.c +++ b/drivers/watchdog/cpwd.c @@ -545,7 +545,7 @@ static int __devinit cpwd_probe(struct of_device *op, goto out; } - p->irq = op->irqs[0]; + p->irq = op->archdata.irqs[0]; spin_lock_init(&p->lock); @@ -688,12 +688,12 @@ static struct of_platform_driver cpwd_driver = { static int __init cpwd_init(void) { - return of_register_driver(&cpwd_driver, &of_bus_type); + return of_register_platform_driver(&cpwd_driver); } static void __exit cpwd_exit(void) { - of_unregister_driver(&cpwd_driver); + of_unregister_platform_driver(&cpwd_driver); } module_init(cpwd_init); diff --git a/drivers/watchdog/riowd.c b/drivers/watchdog/riowd.c index 5dceedd..4082b4a 100644 --- a/drivers/watchdog/riowd.c +++ b/drivers/watchdog/riowd.c @@ -250,12 +250,12 @@ static struct of_platform_driver riowd_driver = { static int __init riowd_init(void) { - return of_register_driver(&riowd_driver, &of_bus_type); + return of_register_platform_driver(&riowd_driver); } static void __exit riowd_exit(void) { - of_unregister_driver(&riowd_driver); + of_unregister_platform_driver(&riowd_driver); } module_init(riowd_init); diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig index fad3df2..0a88269 100644 --- a/drivers/xen/Kconfig +++ b/drivers/xen/Kconfig @@ -62,4 +62,13 @@ config XEN_SYS_HYPERVISOR virtual environment, /sys/hypervisor will still be present, but will have no xen contents. +config XEN_PLATFORM_PCI + tristate "xen platform pci device driver" + depends on XEN_PVHVM + default m + help + Driver for the Xen PCI Platform device: it is responsible for + initializing xenbus and grant_table when running in a Xen HVM + domain. As a consequence this driver is required to run any Xen PV + frontend on Xen HVM. endmenu diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile index 7c28434..e392fb7 100644 --- a/drivers/xen/Makefile +++ b/drivers/xen/Makefile @@ -9,4 +9,5 @@ obj-$(CONFIG_XEN_XENCOMM) += xencomm.o obj-$(CONFIG_XEN_BALLOON) += balloon.o obj-$(CONFIG_XEN_DEV_EVTCHN) += evtchn.o obj-$(CONFIG_XENFS) += xenfs/ -obj-$(CONFIG_XEN_SYS_HYPERVISOR) += sys-hypervisor.o
\ No newline at end of file +obj-$(CONFIG_XEN_SYS_HYPERVISOR) += sys-hypervisor.o +obj-$(CONFIG_XEN_PLATFORM_PCI) += platform-pci.o diff --git a/drivers/xen/events.c b/drivers/xen/events.c index db8f506..5e1f348 100644 --- a/drivers/xen/events.c +++ b/drivers/xen/events.c @@ -29,6 +29,7 @@ #include <linux/bootmem.h> #include <linux/slab.h> +#include <asm/desc.h> #include <asm/ptrace.h> #include <asm/irq.h> #include <asm/idle.h> @@ -36,10 +37,14 @@ #include <asm/xen/hypercall.h> #include <asm/xen/hypervisor.h> +#include <xen/xen.h> +#include <xen/hvm.h> #include <xen/xen-ops.h> #include <xen/events.h> #include <xen/interface/xen.h> #include <xen/interface/event_channel.h> +#include <xen/interface/hvm/hvm_op.h> +#include <xen/interface/hvm/params.h> /* * This lock protects updates to the following mapping and reference-count @@ -335,9 +340,18 @@ static int find_unbound_irq(void) int irq; struct irq_desc *desc; - for (irq = 0; irq < nr_irqs; irq++) + for (irq = 0; irq < nr_irqs; irq++) { + desc = irq_to_desc(irq); + /* only 0->15 have init'd desc; handle irq > 16 */ + if (desc == NULL) + break; + if (desc->chip == &no_irq_chip) + break; + if (desc->chip != &xen_dynamic_chip) + continue; if (irq_info[irq].type == IRQT_UNBOUND) break; + } if (irq == nr_irqs) panic("No available IRQ to bind to: increase nr_irqs!\n"); @@ -346,7 +360,7 @@ static int find_unbound_irq(void) if (WARN_ON(desc == NULL)) return -1; - dynamic_irq_init(irq); + dynamic_irq_init_keep_chip_data(irq); return irq; } @@ -617,17 +631,13 @@ static DEFINE_PER_CPU(unsigned, xed_nesting_count); * a bitset of words which contain pending event bits. The second * level is a bitset of pending events themselves. */ -void xen_evtchn_do_upcall(struct pt_regs *regs) +static void __xen_evtchn_do_upcall(void) { int cpu = get_cpu(); - struct pt_regs *old_regs = set_irq_regs(regs); struct shared_info *s = HYPERVISOR_shared_info; struct vcpu_info *vcpu_info = __get_cpu_var(xen_vcpu); unsigned count; - exit_idle(); - irq_enter(); - do { unsigned long pending_words; @@ -664,14 +674,31 @@ void xen_evtchn_do_upcall(struct pt_regs *regs) count = __get_cpu_var(xed_nesting_count); __get_cpu_var(xed_nesting_count) = 0; - } while(count != 1); + } while (count != 1 || vcpu_info->evtchn_upcall_pending); out: + + put_cpu(); +} + +void xen_evtchn_do_upcall(struct pt_regs *regs) +{ + struct pt_regs *old_regs = set_irq_regs(regs); + + exit_idle(); + irq_enter(); + + __xen_evtchn_do_upcall(); + irq_exit(); set_irq_regs(old_regs); +} - put_cpu(); +void xen_hvm_evtchn_do_upcall(void) +{ + __xen_evtchn_do_upcall(); } +EXPORT_SYMBOL_GPL(xen_hvm_evtchn_do_upcall); /* Rebind a new event channel to an existing irq. */ void rebind_evtchn_irq(int evtchn, int irq) @@ -708,7 +735,10 @@ static int rebind_irq_to_cpu(unsigned irq, unsigned tcpu) struct evtchn_bind_vcpu bind_vcpu; int evtchn = evtchn_from_irq(irq); - if (!VALID_EVTCHN(evtchn)) + /* events delivered via platform PCI interrupts are always + * routed to vcpu 0 */ + if (!VALID_EVTCHN(evtchn) || + (xen_hvm_domain() && !xen_have_vector_callback)) return -1; /* Send future instances of this interrupt to other vcpu. */ @@ -933,6 +963,44 @@ static struct irq_chip xen_dynamic_chip __read_mostly = { .retrigger = retrigger_dynirq, }; +int xen_set_callback_via(uint64_t via) +{ + struct xen_hvm_param a; + a.domid = DOMID_SELF; + a.index = HVM_PARAM_CALLBACK_IRQ; + a.value = via; + return HYPERVISOR_hvm_op(HVMOP_set_param, &a); +} +EXPORT_SYMBOL_GPL(xen_set_callback_via); + +#ifdef CONFIG_XEN_PVHVM +/* Vector callbacks are better than PCI interrupts to receive event + * channel notifications because we can receive vector callbacks on any + * vcpu and we don't need PCI support or APIC interactions. */ +void xen_callback_vector(void) +{ + int rc; + uint64_t callback_via; + if (xen_have_vector_callback) { + callback_via = HVM_CALLBACK_VECTOR(XEN_HVM_EVTCHN_CALLBACK); + rc = xen_set_callback_via(callback_via); + if (rc) { + printk(KERN_ERR "Request for Xen HVM callback vector" + " failed.\n"); + xen_have_vector_callback = 0; + return; + } + printk(KERN_INFO "Xen HVM callback vector for event delivery is " + "enabled\n"); + /* in the restore case the vector has already been allocated */ + if (!test_bit(XEN_HVM_EVTCHN_CALLBACK, used_vectors)) + alloc_intr_gate(XEN_HVM_EVTCHN_CALLBACK, xen_hvm_callback_vector); + } +} +#else +void xen_callback_vector(void) {} +#endif + void __init xen_init_IRQ(void) { int i; @@ -947,5 +1015,10 @@ void __init xen_init_IRQ(void) for (i = 0; i < NR_EVENT_CHANNELS; i++) mask_evtchn(i); - irq_ctx_init(smp_processor_id()); + if (xen_hvm_domain()) { + xen_callback_vector(); + native_init_IRQ(); + } else { + irq_ctx_init(smp_processor_id()); + } } diff --git a/drivers/xen/grant-table.c b/drivers/xen/grant-table.c index f66db3b..6c45318 100644 --- a/drivers/xen/grant-table.c +++ b/drivers/xen/grant-table.c @@ -37,11 +37,13 @@ #include <linux/slab.h> #include <linux/vmalloc.h> #include <linux/uaccess.h> +#include <linux/io.h> #include <xen/xen.h> #include <xen/interface/xen.h> #include <xen/page.h> #include <xen/grant_table.h> +#include <xen/interface/memory.h> #include <asm/xen/hypercall.h> #include <asm/pgtable.h> @@ -59,6 +61,8 @@ static unsigned int boot_max_nr_grant_frames; static int gnttab_free_count; static grant_ref_t gnttab_free_head; static DEFINE_SPINLOCK(gnttab_list_lock); +unsigned long xen_hvm_resume_frames; +EXPORT_SYMBOL_GPL(xen_hvm_resume_frames); static struct grant_entry *shared; @@ -433,7 +437,7 @@ static unsigned int __max_nr_grant_frames(void) return query.max_nr_frames; } -static inline unsigned int max_nr_grant_frames(void) +unsigned int gnttab_max_grant_frames(void) { unsigned int xen_max = __max_nr_grant_frames(); @@ -441,6 +445,7 @@ static inline unsigned int max_nr_grant_frames(void) return boot_max_nr_grant_frames; return xen_max; } +EXPORT_SYMBOL_GPL(gnttab_max_grant_frames); static int gnttab_map(unsigned int start_idx, unsigned int end_idx) { @@ -449,6 +454,30 @@ static int gnttab_map(unsigned int start_idx, unsigned int end_idx) unsigned int nr_gframes = end_idx + 1; int rc; + if (xen_hvm_domain()) { + struct xen_add_to_physmap xatp; + unsigned int i = end_idx; + rc = 0; + /* + * Loop backwards, so that the first hypercall has the largest + * index, ensuring that the table will grow only once. + */ + do { + xatp.domid = DOMID_SELF; + xatp.idx = i; + xatp.space = XENMAPSPACE_grant_table; + xatp.gpfn = (xen_hvm_resume_frames >> PAGE_SHIFT) + i; + rc = HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp); + if (rc != 0) { + printk(KERN_WARNING + "grant table add_to_physmap failed, err=%d\n", rc); + break; + } + } while (i-- > start_idx); + + return rc; + } + frames = kmalloc(nr_gframes * sizeof(unsigned long), GFP_ATOMIC); if (!frames) return -ENOMEM; @@ -465,7 +494,7 @@ static int gnttab_map(unsigned int start_idx, unsigned int end_idx) BUG_ON(rc || setup.status); - rc = arch_gnttab_map_shared(frames, nr_gframes, max_nr_grant_frames(), + rc = arch_gnttab_map_shared(frames, nr_gframes, gnttab_max_grant_frames(), &shared); BUG_ON(rc); @@ -476,9 +505,27 @@ static int gnttab_map(unsigned int start_idx, unsigned int end_idx) int gnttab_resume(void) { - if (max_nr_grant_frames() < nr_grant_frames) + unsigned int max_nr_gframes; + + max_nr_gframes = gnttab_max_grant_frames(); + if (max_nr_gframes < nr_grant_frames) return -ENOSYS; - return gnttab_map(0, nr_grant_frames - 1); + + if (xen_pv_domain()) + return gnttab_map(0, nr_grant_frames - 1); + + if (!shared) { + shared = ioremap(xen_hvm_resume_frames, PAGE_SIZE * max_nr_gframes); + if (shared == NULL) { + printk(KERN_WARNING + "Failed to ioremap gnttab share frames!"); + return -ENOMEM; + } + } + + gnttab_map(0, nr_grant_frames - 1); + + return 0; } int gnttab_suspend(void) @@ -495,7 +542,7 @@ static int gnttab_expand(unsigned int req_entries) cur = nr_grant_frames; extra = ((req_entries + (GREFS_PER_GRANT_FRAME-1)) / GREFS_PER_GRANT_FRAME); - if (cur + extra > max_nr_grant_frames()) + if (cur + extra > gnttab_max_grant_frames()) return -ENOSPC; rc = gnttab_map(cur, cur + extra - 1); @@ -505,15 +552,12 @@ static int gnttab_expand(unsigned int req_entries) return rc; } -static int __devinit gnttab_init(void) +int gnttab_init(void) { int i; unsigned int max_nr_glist_frames, nr_glist_frames; unsigned int nr_init_grefs; - if (!xen_domain()) - return -ENODEV; - nr_grant_frames = 1; boot_max_nr_grant_frames = __max_nr_grant_frames(); @@ -556,5 +600,18 @@ static int __devinit gnttab_init(void) kfree(gnttab_list); return -ENOMEM; } +EXPORT_SYMBOL_GPL(gnttab_init); + +static int __devinit __gnttab_init(void) +{ + /* Delay grant-table initialization in the PV on HVM case */ + if (xen_hvm_domain()) + return 0; + + if (!xen_pv_domain()) + return -ENODEV; + + return gnttab_init(); +} -core_initcall(gnttab_init); +core_initcall(__gnttab_init); diff --git a/drivers/xen/manage.c b/drivers/xen/manage.c index 07e857b..1799bd8 100644 --- a/drivers/xen/manage.c +++ b/drivers/xen/manage.c @@ -9,6 +9,7 @@ #include <linux/stop_machine.h> #include <linux/freezer.h> +#include <xen/xen.h> #include <xen/xenbus.h> #include <xen/grant_table.h> #include <xen/events.h> @@ -17,6 +18,7 @@ #include <asm/xen/hypercall.h> #include <asm/xen/page.h> +#include <asm/xen/hypervisor.h> enum shutdown_state { SHUTDOWN_INVALID = -1, @@ -33,10 +35,30 @@ enum shutdown_state { static enum shutdown_state shutting_down = SHUTDOWN_INVALID; #ifdef CONFIG_PM_SLEEP -static int xen_suspend(void *data) +static int xen_hvm_suspend(void *data) { + struct sched_shutdown r = { .reason = SHUTDOWN_suspend }; int *cancelled = data; + + BUG_ON(!irqs_disabled()); + + *cancelled = HYPERVISOR_sched_op(SCHEDOP_shutdown, &r); + + xen_hvm_post_suspend(*cancelled); + gnttab_resume(); + + if (!*cancelled) { + xen_irq_resume(); + xen_timer_resume(); + } + + return 0; +} + +static int xen_suspend(void *data) +{ int err; + int *cancelled = data; BUG_ON(!irqs_disabled()); @@ -106,7 +128,10 @@ static void do_suspend(void) goto out_resume; } - err = stop_machine(xen_suspend, &cancelled, cpumask_of(0)); + if (xen_hvm_domain()) + err = stop_machine(xen_hvm_suspend, &cancelled, cpumask_of(0)); + else + err = stop_machine(xen_suspend, &cancelled, cpumask_of(0)); dpm_resume_noirq(PMSG_RESUME); @@ -255,7 +280,19 @@ static int shutdown_event(struct notifier_block *notifier, return NOTIFY_DONE; } -static int __init setup_shutdown_event(void) +static int __init __setup_shutdown_event(void) +{ + /* Delay initialization in the PV on HVM case */ + if (xen_hvm_domain()) + return 0; + + if (!xen_pv_domain()) + return -ENODEV; + + return xen_setup_shutdown_event(); +} + +int xen_setup_shutdown_event(void) { static struct notifier_block xenstore_notifier = { .notifier_call = shutdown_event @@ -264,5 +301,6 @@ static int __init setup_shutdown_event(void) return 0; } +EXPORT_SYMBOL_GPL(xen_setup_shutdown_event); -subsys_initcall(setup_shutdown_event); +subsys_initcall(__setup_shutdown_event); diff --git a/drivers/xen/platform-pci.c b/drivers/xen/platform-pci.c new file mode 100644 index 0000000..c01b5dd --- /dev/null +++ b/drivers/xen/platform-pci.c @@ -0,0 +1,207 @@ +/****************************************************************************** + * platform-pci.c + * + * Xen platform PCI device driver + * Copyright (c) 2005, Intel Corporation. + * Copyright (c) 2007, XenSource Inc. + * Copyright (c) 2010, Citrix + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307 USA. + * + */ + + +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/pci.h> + +#include <xen/platform_pci.h> +#include <xen/grant_table.h> +#include <xen/xenbus.h> +#include <xen/events.h> +#include <xen/hvm.h> +#include <xen/xen-ops.h> + +#define DRV_NAME "xen-platform-pci" + +MODULE_AUTHOR("ssmith@xensource.com and stefano.stabellini@eu.citrix.com"); +MODULE_DESCRIPTION("Xen platform PCI device"); +MODULE_LICENSE("GPL"); + +static unsigned long platform_mmio; +static unsigned long platform_mmio_alloc; +static unsigned long platform_mmiolen; +static uint64_t callback_via; + +unsigned long alloc_xen_mmio(unsigned long len) +{ + unsigned long addr; + + addr = platform_mmio + platform_mmio_alloc; + platform_mmio_alloc += len; + BUG_ON(platform_mmio_alloc > platform_mmiolen); + + return addr; +} + +static uint64_t get_callback_via(struct pci_dev *pdev) +{ + u8 pin; + int irq; + + irq = pdev->irq; + if (irq < 16) + return irq; /* ISA IRQ */ + + pin = pdev->pin; + + /* We don't know the GSI. Specify the PCI INTx line instead. */ + return ((uint64_t)0x01 << 56) | /* PCI INTx identifier */ + ((uint64_t)pci_domain_nr(pdev->bus) << 32) | + ((uint64_t)pdev->bus->number << 16) | + ((uint64_t)(pdev->devfn & 0xff) << 8) | + ((uint64_t)(pin - 1) & 3); +} + +static irqreturn_t do_hvm_evtchn_intr(int irq, void *dev_id) +{ + xen_hvm_evtchn_do_upcall(); + return IRQ_HANDLED; +} + +static int xen_allocate_irq(struct pci_dev *pdev) +{ + return request_irq(pdev->irq, do_hvm_evtchn_intr, + IRQF_DISABLED | IRQF_NOBALANCING | IRQF_TRIGGER_RISING, + "xen-platform-pci", pdev); +} + +static int platform_pci_resume(struct pci_dev *pdev) +{ + int err; + if (xen_have_vector_callback) + return 0; + err = xen_set_callback_via(callback_via); + if (err) { + dev_err(&pdev->dev, "platform_pci_resume failure!\n"); + return err; + } + return 0; +} + +static int __devinit platform_pci_init(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + int i, ret; + long ioaddr, iolen; + long mmio_addr, mmio_len; + unsigned int max_nr_gframes; + + i = pci_enable_device(pdev); + if (i) + return i; + + ioaddr = pci_resource_start(pdev, 0); + iolen = pci_resource_len(pdev, 0); + + mmio_addr = pci_resource_start(pdev, 1); + mmio_len = pci_resource_len(pdev, 1); + + if (mmio_addr == 0 || ioaddr == 0) { + dev_err(&pdev->dev, "no resources found\n"); + ret = -ENOENT; + goto pci_out; + } + + if (request_mem_region(mmio_addr, mmio_len, DRV_NAME) == NULL) { + dev_err(&pdev->dev, "MEM I/O resource 0x%lx @ 0x%lx busy\n", + mmio_addr, mmio_len); + ret = -EBUSY; + goto pci_out; + } + + if (request_region(ioaddr, iolen, DRV_NAME) == NULL) { + dev_err(&pdev->dev, "I/O resource 0x%lx @ 0x%lx busy\n", + iolen, ioaddr); + ret = -EBUSY; + goto mem_out; + } + + platform_mmio = mmio_addr; + platform_mmiolen = mmio_len; + + if (!xen_have_vector_callback) { + ret = xen_allocate_irq(pdev); + if (ret) { + dev_warn(&pdev->dev, "request_irq failed err=%d\n", ret); + goto out; + } + callback_via = get_callback_via(pdev); + ret = xen_set_callback_via(callback_via); + if (ret) { + dev_warn(&pdev->dev, "Unable to set the evtchn callback " + "err=%d\n", ret); + goto out; + } + } + + max_nr_gframes = gnttab_max_grant_frames(); + xen_hvm_resume_frames = alloc_xen_mmio(PAGE_SIZE * max_nr_gframes); + ret = gnttab_init(); + if (ret) + goto out; + xenbus_probe(NULL); + ret = xen_setup_shutdown_event(); + if (ret) + goto out; + return 0; + +out: + release_region(ioaddr, iolen); +mem_out: + release_mem_region(mmio_addr, mmio_len); +pci_out: + pci_disable_device(pdev); + return ret; +} + +static struct pci_device_id platform_pci_tbl[] __devinitdata = { + {PCI_VENDOR_ID_XEN, PCI_DEVICE_ID_XEN_PLATFORM, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {0,} +}; + +MODULE_DEVICE_TABLE(pci, platform_pci_tbl); + +static struct pci_driver platform_driver = { + .name = DRV_NAME, + .probe = platform_pci_init, + .id_table = platform_pci_tbl, +#ifdef CONFIG_PM + .resume_early = platform_pci_resume, +#endif +}; + +static int __init platform_pci_module_init(void) +{ + /* no unplug has been done, IGNORE hasn't been specified: just + * return now */ + if (!xen_platform_pci_unplug) + return -ENODEV; + + return pci_register_driver(&platform_driver); +} + +module_init(platform_pci_module_init); diff --git a/drivers/xen/xenbus/xenbus_probe.c b/drivers/xen/xenbus/xenbus_probe.c index 3479332..29bac51 100644 --- a/drivers/xen/xenbus/xenbus_probe.c +++ b/drivers/xen/xenbus/xenbus_probe.c @@ -56,6 +56,9 @@ #include <xen/events.h> #include <xen/page.h> +#include <xen/platform_pci.h> +#include <xen/hvm.h> + #include "xenbus_comms.h" #include "xenbus_probe.h" @@ -752,10 +755,7 @@ int register_xenstore_notifier(struct notifier_block *nb) { int ret = 0; - if (xenstored_ready > 0) - ret = nb->notifier_call(nb, 0, NULL); - else - blocking_notifier_chain_register(&xenstore_chain, nb); + blocking_notifier_chain_register(&xenstore_chain, nb); return ret; } @@ -779,8 +779,23 @@ void xenbus_probe(struct work_struct *unused) /* Notify others that xenstore is up */ blocking_notifier_call_chain(&xenstore_chain, 0, NULL); } +EXPORT_SYMBOL_GPL(xenbus_probe); + +static int __init xenbus_probe_initcall(void) +{ + if (!xen_domain()) + return -ENODEV; + + if (xen_initial_domain() || xen_hvm_domain()) + return 0; + + xenbus_probe(NULL); + return 0; +} + +device_initcall(xenbus_probe_initcall); -static int __init xenbus_probe_init(void) +static int __init xenbus_init(void) { int err = 0; @@ -805,11 +820,24 @@ static int __init xenbus_probe_init(void) if (xen_initial_domain()) { /* dom0 not yet supported */ } else { + if (xen_hvm_domain()) { + uint64_t v = 0; + err = hvm_get_parameter(HVM_PARAM_STORE_EVTCHN, &v); + if (err) + goto out_error; + xen_store_evtchn = (int)v; + err = hvm_get_parameter(HVM_PARAM_STORE_PFN, &v); + if (err) + goto out_error; + xen_store_mfn = (unsigned long)v; + xen_store_interface = ioremap(xen_store_mfn << PAGE_SHIFT, PAGE_SIZE); + } else { + xen_store_evtchn = xen_start_info->store_evtchn; + xen_store_mfn = xen_start_info->store_mfn; + xen_store_interface = mfn_to_virt(xen_store_mfn); + } xenstored_ready = 1; - xen_store_evtchn = xen_start_info->store_evtchn; - xen_store_mfn = xen_start_info->store_mfn; } - xen_store_interface = mfn_to_virt(xen_store_mfn); /* Initialize the interface to xenstore. */ err = xs_init(); @@ -819,9 +847,6 @@ static int __init xenbus_probe_init(void) goto out_unreg_back; } - if (!xen_initial_domain()) - xenbus_probe(NULL); - #ifdef CONFIG_XEN_COMPAT_XENFS /* * Create xenfs mountpoint in /proc for compatibility with @@ -842,7 +867,7 @@ static int __init xenbus_probe_init(void) return err; } -postcore_initcall(xenbus_probe_init); +postcore_initcall(xenbus_init); MODULE_LICENSE("GPL"); @@ -950,6 +975,9 @@ static void wait_for_devices(struct xenbus_driver *xendrv) #ifndef MODULE static int __init boot_wait_for_devices(void) { + if (xen_hvm_domain() && !xen_platform_pci_unplug) + return -ENODEV; + ready_to_wait_for_devices = 1; wait_for_devices(NULL); return 0; diff --git a/drivers/xen/xenbus/xenbus_xs.c b/drivers/xen/xenbus/xenbus_xs.c index 7b547f5..5534690 100644 --- a/drivers/xen/xenbus/xenbus_xs.c +++ b/drivers/xen/xenbus/xenbus_xs.c @@ -76,6 +76,14 @@ struct xs_handle { /* * Mutex ordering: transaction_mutex -> watch_mutex -> request_mutex. * response_mutex is never taken simultaneously with the other three. + * + * transaction_mutex must be held before incrementing + * transaction_count. The mutex is held when a suspend is in + * progress to prevent new transactions starting. + * + * When decrementing transaction_count to zero the wait queue + * should be woken up, the suspend code waits for count to + * reach zero. */ /* One request at a time. */ @@ -85,7 +93,9 @@ struct xs_handle { struct mutex response_mutex; /* Protect transactions against save/restore. */ - struct rw_semaphore transaction_mutex; + struct mutex transaction_mutex; + atomic_t transaction_count; + wait_queue_head_t transaction_wq; /* Protect watch (de)register against save/restore. */ struct rw_semaphore watch_mutex; @@ -157,6 +167,31 @@ static void *read_reply(enum xsd_sockmsg_type *type, unsigned int *len) return body; } +static void transaction_start(void) +{ + mutex_lock(&xs_state.transaction_mutex); + atomic_inc(&xs_state.transaction_count); + mutex_unlock(&xs_state.transaction_mutex); +} + +static void transaction_end(void) +{ + if (atomic_dec_and_test(&xs_state.transaction_count)) + wake_up(&xs_state.transaction_wq); +} + +static void transaction_suspend(void) +{ + mutex_lock(&xs_state.transaction_mutex); + wait_event(xs_state.transaction_wq, + atomic_read(&xs_state.transaction_count) == 0); +} + +static void transaction_resume(void) +{ + mutex_unlock(&xs_state.transaction_mutex); +} + void *xenbus_dev_request_and_reply(struct xsd_sockmsg *msg) { void *ret; @@ -164,7 +199,7 @@ void *xenbus_dev_request_and_reply(struct xsd_sockmsg *msg) int err; if (req_msg.type == XS_TRANSACTION_START) - down_read(&xs_state.transaction_mutex); + transaction_start(); mutex_lock(&xs_state.request_mutex); @@ -180,7 +215,7 @@ void *xenbus_dev_request_and_reply(struct xsd_sockmsg *msg) if ((msg->type == XS_TRANSACTION_END) || ((req_msg.type == XS_TRANSACTION_START) && (msg->type == XS_ERROR))) - up_read(&xs_state.transaction_mutex); + transaction_end(); return ret; } @@ -432,11 +467,11 @@ int xenbus_transaction_start(struct xenbus_transaction *t) { char *id_str; - down_read(&xs_state.transaction_mutex); + transaction_start(); id_str = xs_single(XBT_NIL, XS_TRANSACTION_START, "", NULL); if (IS_ERR(id_str)) { - up_read(&xs_state.transaction_mutex); + transaction_end(); return PTR_ERR(id_str); } @@ -461,7 +496,7 @@ int xenbus_transaction_end(struct xenbus_transaction t, int abort) err = xs_error(xs_single(t, XS_TRANSACTION_END, abortstr, NULL)); - up_read(&xs_state.transaction_mutex); + transaction_end(); return err; } @@ -662,7 +697,7 @@ EXPORT_SYMBOL_GPL(unregister_xenbus_watch); void xs_suspend(void) { - down_write(&xs_state.transaction_mutex); + transaction_suspend(); down_write(&xs_state.watch_mutex); mutex_lock(&xs_state.request_mutex); mutex_lock(&xs_state.response_mutex); @@ -677,7 +712,7 @@ void xs_resume(void) mutex_unlock(&xs_state.response_mutex); mutex_unlock(&xs_state.request_mutex); - up_write(&xs_state.transaction_mutex); + transaction_resume(); /* No need for watches_lock: the watch_mutex is sufficient. */ list_for_each_entry(watch, &watches, list) { @@ -693,7 +728,7 @@ void xs_suspend_cancel(void) mutex_unlock(&xs_state.response_mutex); mutex_unlock(&xs_state.request_mutex); up_write(&xs_state.watch_mutex); - up_write(&xs_state.transaction_mutex); + mutex_unlock(&xs_state.transaction_mutex); } static int xenwatch_thread(void *unused) @@ -843,8 +878,10 @@ int xs_init(void) mutex_init(&xs_state.request_mutex); mutex_init(&xs_state.response_mutex); - init_rwsem(&xs_state.transaction_mutex); + mutex_init(&xs_state.transaction_mutex); init_rwsem(&xs_state.watch_mutex); + atomic_set(&xs_state.transaction_count, 0); + init_waitqueue_head(&xs_state.transaction_wq); /* Initialize the shared memory rings to talk to xenstored */ err = xb_init_comms(); diff --git a/drivers/xen/xenfs/super.c b/drivers/xen/xenfs/super.c index 8924d93..78bfab0 100644 --- a/drivers/xen/xenfs/super.c +++ b/drivers/xen/xenfs/super.c @@ -65,7 +65,7 @@ static struct file_system_type xenfs_type = { static int __init xenfs_init(void) { - if (xen_pv_domain()) + if (xen_domain()) return register_filesystem(&xenfs_type); printk(KERN_INFO "XENFS: not registering filesystem on non-xen platform\n"); @@ -74,7 +74,7 @@ static int __init xenfs_init(void) static void __exit xenfs_exit(void) { - if (xen_pv_domain()) + if (xen_domain()) unregister_filesystem(&xenfs_type); } diff --git a/drivers/xen/xenfs/xenbus.c b/drivers/xen/xenfs/xenbus.c index f28ece3..3b39c37 100644 --- a/drivers/xen/xenfs/xenbus.c +++ b/drivers/xen/xenfs/xenbus.c @@ -124,6 +124,9 @@ static ssize_t xenbus_file_read(struct file *filp, mutex_lock(&u->reply_mutex); while (list_empty(&u->read_buffers)) { mutex_unlock(&u->reply_mutex); + if (filp->f_flags & O_NONBLOCK) + return -EAGAIN; + ret = wait_event_interruptible(u->read_waitq, !list_empty(&u->read_buffers)); if (ret) |