diff options
Diffstat (limited to 'drivers/gpu/drm')
-rw-r--r-- | drivers/gpu/drm/i915/i915_reg.h | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_i2c.c | 66 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_lvds.c | 18 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/adreno/a3xx_gpu.c | 49 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/hdmi/hdmi.c | 42 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/msm_drv.c | 112 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/msm_drv.h | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/atombios_crtc.c | 8 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/cik.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/ni.c | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_asic.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_asic.h | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_uvd.c | 105 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/rv770d.h | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/si.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/si_dpm.c | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/uvd_v1_0.c | 14 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/uvd_v2_2.c | 29 |
18 files changed, 374 insertions, 91 deletions
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 0c83b3dab58c..5b38bf819b7b 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1181,6 +1181,7 @@ #define GMBUS_CYCLE_INDEX (2<<25) #define GMBUS_CYCLE_STOP (4<<25) #define GMBUS_BYTE_COUNT_SHIFT 16 +#define GMBUS_BYTE_COUNT_MAX 256U #define GMBUS_SLAVE_INDEX_SHIFT 8 #define GMBUS_SLAVE_ADDR_SHIFT 1 #define GMBUS_SLAVE_READ (1<<0) diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c index d33b61d0dd33..1d02970ed395 100644 --- a/drivers/gpu/drm/i915/intel_i2c.c +++ b/drivers/gpu/drm/i915/intel_i2c.c @@ -324,18 +324,17 @@ gmbus_wait_idle(struct drm_i915_private *dev_priv) } static int -gmbus_xfer_read(struct drm_i915_private *dev_priv, struct i2c_msg *msg, - u32 gmbus1_index) +gmbus_xfer_read_chunk(struct drm_i915_private *dev_priv, + unsigned short addr, u8 *buf, unsigned int len, + u32 gmbus1_index) { int reg_offset = dev_priv->gpio_mmio_base; - u16 len = msg->len; - u8 *buf = msg->buf; I915_WRITE(GMBUS1 + reg_offset, gmbus1_index | GMBUS_CYCLE_WAIT | (len << GMBUS_BYTE_COUNT_SHIFT) | - (msg->addr << GMBUS_SLAVE_ADDR_SHIFT) | + (addr << GMBUS_SLAVE_ADDR_SHIFT) | GMBUS_SLAVE_READ | GMBUS_SW_RDY); while (len) { int ret; @@ -357,11 +356,35 @@ gmbus_xfer_read(struct drm_i915_private *dev_priv, struct i2c_msg *msg, } static int -gmbus_xfer_write(struct drm_i915_private *dev_priv, struct i2c_msg *msg) +gmbus_xfer_read(struct drm_i915_private *dev_priv, struct i2c_msg *msg, + u32 gmbus1_index) { - int reg_offset = dev_priv->gpio_mmio_base; - u16 len = msg->len; u8 *buf = msg->buf; + unsigned int rx_size = msg->len; + unsigned int len; + int ret; + + do { + len = min(rx_size, GMBUS_BYTE_COUNT_MAX); + + ret = gmbus_xfer_read_chunk(dev_priv, msg->addr, + buf, len, gmbus1_index); + if (ret) + return ret; + + rx_size -= len; + buf += len; + } while (rx_size != 0); + + return 0; +} + +static int +gmbus_xfer_write_chunk(struct drm_i915_private *dev_priv, + unsigned short addr, u8 *buf, unsigned int len) +{ + int reg_offset = dev_priv->gpio_mmio_base; + unsigned int chunk_size = len; u32 val, loop; val = loop = 0; @@ -373,8 +396,8 @@ gmbus_xfer_write(struct drm_i915_private *dev_priv, struct i2c_msg *msg) I915_WRITE(GMBUS3 + reg_offset, val); I915_WRITE(GMBUS1 + reg_offset, GMBUS_CYCLE_WAIT | - (msg->len << GMBUS_BYTE_COUNT_SHIFT) | - (msg->addr << GMBUS_SLAVE_ADDR_SHIFT) | + (chunk_size << GMBUS_BYTE_COUNT_SHIFT) | + (addr << GMBUS_SLAVE_ADDR_SHIFT) | GMBUS_SLAVE_WRITE | GMBUS_SW_RDY); while (len) { int ret; @@ -391,6 +414,29 @@ gmbus_xfer_write(struct drm_i915_private *dev_priv, struct i2c_msg *msg) if (ret) return ret; } + + return 0; +} + +static int +gmbus_xfer_write(struct drm_i915_private *dev_priv, struct i2c_msg *msg) +{ + u8 *buf = msg->buf; + unsigned int tx_size = msg->len; + unsigned int len; + int ret; + + do { + len = min(tx_size, GMBUS_BYTE_COUNT_MAX); + + ret = gmbus_xfer_write_chunk(dev_priv, msg->addr, buf, len); + if (ret) + return ret; + + buf += len; + tx_size -= len; + } while (tx_size != 0); + return 0; } diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index af49b24d14cb..1eb49941faff 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -815,12 +815,28 @@ static int intel_dual_link_lvds_callback(const struct dmi_system_id *id) static const struct dmi_system_id intel_dual_link_lvds[] = { { .callback = intel_dual_link_lvds_callback, - .ident = "Apple MacBook Pro (Core i5/i7 Series)", + .ident = "Apple MacBook Pro 15\" (2010)", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro6,2"), + }, + }, + { + .callback = intel_dual_link_lvds_callback, + .ident = "Apple MacBook Pro 15\" (2011)", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro8,2"), }, }, + { + .callback = intel_dual_link_lvds_callback, + .ident = "Apple MacBook Pro 15\" (2012)", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro9,1"), + }, + }, { } /* terminating entry */ }; diff --git a/drivers/gpu/drm/msm/adreno/a3xx_gpu.c b/drivers/gpu/drm/msm/adreno/a3xx_gpu.c index 461df93e825e..4f32b34f48d4 100644 --- a/drivers/gpu/drm/msm/adreno/a3xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a3xx_gpu.c @@ -35,8 +35,6 @@ A3XX_INT0_CP_AHB_ERROR_HALT | \ A3XX_INT0_UCHE_OOB_ACCESS) -static struct platform_device *a3xx_pdev; - static void a3xx_me_init(struct msm_gpu *gpu) { struct msm_ringbuffer *ring = gpu->rb; @@ -311,7 +309,6 @@ static void a3xx_destroy(struct msm_gpu *gpu) ocmem_free(OCMEM_GRAPHICS, a3xx_gpu->ocmem_hdl); #endif - put_device(&a3xx_gpu->pdev->dev); kfree(a3xx_gpu); } @@ -439,7 +436,8 @@ struct msm_gpu *a3xx_gpu_init(struct drm_device *dev) struct a3xx_gpu *a3xx_gpu = NULL; struct adreno_gpu *adreno_gpu; struct msm_gpu *gpu; - struct platform_device *pdev = a3xx_pdev; + struct msm_drm_private *priv = dev->dev_private; + struct platform_device *pdev = priv->gpu_pdev; struct adreno_platform_config *config; int ret; @@ -460,7 +458,6 @@ struct msm_gpu *a3xx_gpu_init(struct drm_device *dev) adreno_gpu = &a3xx_gpu->base; gpu = &adreno_gpu->base; - get_device(&pdev->dev); a3xx_gpu->pdev = pdev; gpu->fast_rate = config->fast_rate; @@ -522,17 +519,24 @@ fail: # include <mach/kgsl.h> #endif -static int a3xx_probe(struct platform_device *pdev) +static void set_gpu_pdev(struct drm_device *dev, + struct platform_device *pdev) +{ + struct msm_drm_private *priv = dev->dev_private; + priv->gpu_pdev = pdev; +} + +static int a3xx_bind(struct device *dev, struct device *master, void *data) { static struct adreno_platform_config config = {}; #ifdef CONFIG_OF - struct device_node *child, *node = pdev->dev.of_node; + struct device_node *child, *node = dev->of_node; u32 val; int ret; ret = of_property_read_u32(node, "qcom,chipid", &val); if (ret) { - dev_err(&pdev->dev, "could not find chipid: %d\n", ret); + dev_err(dev, "could not find chipid: %d\n", ret); return ret; } @@ -548,7 +552,7 @@ static int a3xx_probe(struct platform_device *pdev) for_each_child_of_node(child, pwrlvl) { ret = of_property_read_u32(pwrlvl, "qcom,gpu-freq", &val); if (ret) { - dev_err(&pdev->dev, "could not find gpu-freq: %d\n", ret); + dev_err(dev, "could not find gpu-freq: %d\n", ret); return ret; } config.fast_rate = max(config.fast_rate, val); @@ -558,12 +562,12 @@ static int a3xx_probe(struct platform_device *pdev) } if (!config.fast_rate) { - dev_err(&pdev->dev, "could not find clk rates\n"); + dev_err(dev, "could not find clk rates\n"); return -ENXIO; } #else - struct kgsl_device_platform_data *pdata = pdev->dev.platform_data; + struct kgsl_device_platform_data *pdata = dev->platform_data; uint32_t version = socinfo_get_version(); if (cpu_is_apq8064ab()) { config.fast_rate = 450000000; @@ -609,14 +613,30 @@ static int a3xx_probe(struct platform_device *pdev) config.bus_scale_table = pdata->bus_scale_table; # endif #endif - pdev->dev.platform_data = &config; - a3xx_pdev = pdev; + dev->platform_data = &config; + set_gpu_pdev(dev_get_drvdata(master), to_platform_device(dev)); return 0; } +static void a3xx_unbind(struct device *dev, struct device *master, + void *data) +{ + set_gpu_pdev(dev_get_drvdata(master), NULL); +} + +static const struct component_ops a3xx_ops = { + .bind = a3xx_bind, + .unbind = a3xx_unbind, +}; + +static int a3xx_probe(struct platform_device *pdev) +{ + return component_add(&pdev->dev, &a3xx_ops); +} + static int a3xx_remove(struct platform_device *pdev) { - a3xx_pdev = NULL; + component_del(&pdev->dev, &a3xx_ops); return 0; } @@ -624,7 +644,6 @@ static const struct of_device_id dt_match[] = { { .compatible = "qcom,kgsl-3d0" }, {} }; -MODULE_DEVICE_TABLE(of, dt_match); static struct platform_driver a3xx_driver = { .probe = a3xx_probe, diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.c b/drivers/gpu/drm/msm/hdmi/hdmi.c index 6f1588aa9071..8a04a1d206cd 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi.c @@ -17,8 +17,6 @@ #include "hdmi.h" -static struct platform_device *hdmi_pdev; - void hdmi_set_mode(struct hdmi *hdmi, bool power_on) { uint32_t ctrl = 0; @@ -75,7 +73,7 @@ struct hdmi *hdmi_init(struct drm_device *dev, struct drm_encoder *encoder) { struct hdmi *hdmi = NULL; struct msm_drm_private *priv = dev->dev_private; - struct platform_device *pdev = hdmi_pdev; + struct platform_device *pdev = priv->hdmi_pdev; struct hdmi_platform_config *config; int i, ret; @@ -95,8 +93,6 @@ struct hdmi *hdmi_init(struct drm_device *dev, struct drm_encoder *encoder) kref_init(&hdmi->refcount); - get_device(&pdev->dev); - hdmi->dev = dev; hdmi->pdev = pdev; hdmi->config = config; @@ -249,17 +245,24 @@ fail: #include <linux/of_gpio.h> -static int hdmi_dev_probe(struct platform_device *pdev) +static void set_hdmi_pdev(struct drm_device *dev, + struct platform_device *pdev) +{ + struct msm_drm_private *priv = dev->dev_private; + priv->hdmi_pdev = pdev; +} + +static int hdmi_bind(struct device *dev, struct device *master, void *data) { static struct hdmi_platform_config config = {}; #ifdef CONFIG_OF - struct device_node *of_node = pdev->dev.of_node; + struct device_node *of_node = dev->of_node; int get_gpio(const char *name) { int gpio = of_get_named_gpio(of_node, name, 0); if (gpio < 0) { - dev_err(&pdev->dev, "failed to get gpio: %s (%d)\n", + dev_err(dev, "failed to get gpio: %s (%d)\n", name, gpio); gpio = -1; } @@ -336,14 +339,30 @@ static int hdmi_dev_probe(struct platform_device *pdev) config.mux_sel_gpio = -1; } #endif - pdev->dev.platform_data = &config; - hdmi_pdev = pdev; + dev->platform_data = &config; + set_hdmi_pdev(dev_get_drvdata(master), to_platform_device(dev)); return 0; } +static void hdmi_unbind(struct device *dev, struct device *master, + void *data) +{ + set_hdmi_pdev(dev_get_drvdata(master), NULL); +} + +static const struct component_ops hdmi_ops = { + .bind = hdmi_bind, + .unbind = hdmi_unbind, +}; + +static int hdmi_dev_probe(struct platform_device *pdev) +{ + return component_add(&pdev->dev, &hdmi_ops); +} + static int hdmi_dev_remove(struct platform_device *pdev) { - hdmi_pdev = NULL; + component_del(&pdev->dev, &hdmi_ops); return 0; } @@ -351,7 +370,6 @@ static const struct of_device_id dt_match[] = { { .compatible = "qcom,hdmi-tx" }, {} }; -MODULE_DEVICE_TABLE(of, dt_match); static struct platform_driver hdmi_driver = { .probe = hdmi_dev_probe, diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index e6adafc7eff3..e79cfd0b2b04 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -56,6 +56,10 @@ static char *vram; MODULE_PARM_DESC(vram, "Configure VRAM size (for devices without IOMMU/GPUMMU"); module_param(vram, charp, 0); +/* + * Util/helpers: + */ + void __iomem *msm_ioremap(struct platform_device *pdev, const char *name, const char *dbgname) { @@ -143,6 +147,8 @@ static int msm_unload(struct drm_device *dev) priv->vram.paddr, &attrs); } + component_unbind_all(dev->dev, dev); + dev->dev_private = NULL; kfree(priv); @@ -175,6 +181,7 @@ static int msm_load(struct drm_device *dev, unsigned long flags) struct msm_kms *kms; int ret; + priv = kzalloc(sizeof(*priv), GFP_KERNEL); if (!priv) { dev_err(dev->dev, "failed to allocate private data\n"); @@ -226,6 +233,13 @@ static int msm_load(struct drm_device *dev, unsigned long flags) (uint32_t)(priv->vram.paddr + size)); } + platform_set_drvdata(pdev, dev); + + /* Bind all our sub-components: */ + ret = component_bind_all(dev->dev, dev); + if (ret) + return ret; + switch (get_mdp_ver(pdev)) { case 4: kms = mdp4_kms_init(dev); @@ -281,8 +295,6 @@ static int msm_load(struct drm_device *dev, unsigned long flags) goto fail; } - platform_set_drvdata(pdev, dev); - #ifdef CONFIG_DRM_MSM_FBDEV priv->fbdev = msm_fbdev_init(dev); #endif @@ -819,18 +831,110 @@ static const struct dev_pm_ops msm_pm_ops = { }; /* + * Componentized driver support: + */ + +#ifdef CONFIG_OF +/* NOTE: the CONFIG_OF case duplicates the same code as exynos or imx + * (or probably any other).. so probably some room for some helpers + */ +static int compare_of(struct device *dev, void *data) +{ + return dev->of_node == data; +} + +static int msm_drm_add_components(struct device *master, struct master *m) +{ + struct device_node *np = master->of_node; + unsigned i; + int ret; + + for (i = 0; ; i++) { + struct device_node *node; + + node = of_parse_phandle(np, "connectors", i); + if (!node) + break; + + ret = component_master_add_child(m, compare_of, node); + of_node_put(node); + + if (ret) + return ret; + } + return 0; +} +#else +static int compare_dev(struct device *dev, void *data) +{ + return dev == data; +} + +static int msm_drm_add_components(struct device *master, struct master *m) +{ + /* For non-DT case, it kinda sucks. We don't actually have a way + * to know whether or not we are waiting for certain devices (or if + * they are simply not present). But for non-DT we only need to + * care about apq8064/apq8060/etc (all mdp4/a3xx): + */ + static const char *devnames[] = { + "hdmi_msm.0", "kgsl-3d0.0", + }; + int i; + + DBG("Adding components.."); + + for (i = 0; i < ARRAY_SIZE(devnames); i++) { + struct device *dev; + int ret; + + dev = bus_find_device_by_name(&platform_bus_type, + NULL, devnames[i]); + if (!dev) { + dev_info(master, "still waiting for %s\n", devnames[i]); + return -EPROBE_DEFER; + } + + ret = component_master_add_child(m, compare_dev, dev); + if (ret) { + DBG("could not add child: %d", ret); + return ret; + } + } + + return 0; +} +#endif + +static int msm_drm_bind(struct device *dev) +{ + return drm_platform_init(&msm_driver, to_platform_device(dev)); +} + +static void msm_drm_unbind(struct device *dev) +{ + drm_put_dev(platform_get_drvdata(to_platform_device(dev))); +} + +static const struct component_master_ops msm_drm_ops = { + .add_components = msm_drm_add_components, + .bind = msm_drm_bind, + .unbind = msm_drm_unbind, +}; + +/* * Platform driver: */ static int msm_pdev_probe(struct platform_device *pdev) { pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); - return drm_platform_init(&msm_driver, pdev); + return component_master_add(&pdev->dev, &msm_drm_ops); } static int msm_pdev_remove(struct platform_device *pdev) { - drm_put_dev(platform_get_drvdata(pdev)); + component_master_del(&pdev->dev, &msm_drm_ops); return 0; } diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index 3d63269c5b29..9d10ee0b5aac 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h @@ -22,6 +22,7 @@ #include <linux/clk.h> #include <linux/cpufreq.h> #include <linux/module.h> +#include <linux/component.h> #include <linux/platform_device.h> #include <linux/pm.h> #include <linux/pm_runtime.h> @@ -69,6 +70,9 @@ struct msm_drm_private { struct msm_kms *kms; + /* subordinate devices, if present: */ + struct platform_device *hdmi_pdev, *gpu_pdev; + /* when we have more than one 'msm_gpu' these need to be an array: */ struct msm_gpu *gpu; struct msm_file_private *lastctx; diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index 663394f0c166..0db3e208f02a 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -330,8 +330,10 @@ atombios_set_crtc_dtd_timing(struct drm_crtc *crtc, misc |= ATOM_COMPOSITESYNC; if (mode->flags & DRM_MODE_FLAG_INTERLACE) misc |= ATOM_INTERLACE; - if (mode->flags & DRM_MODE_FLAG_DBLSCAN) + if (mode->flags & DRM_MODE_FLAG_DBLCLK) misc |= ATOM_DOUBLE_CLOCK_MODE; + if (mode->flags & DRM_MODE_FLAG_DBLSCAN) + misc |= ATOM_H_REPLICATIONBY2 | ATOM_V_REPLICATIONBY2; args.susModeMiscInfo.usAccess = cpu_to_le16(misc); args.ucCRTC = radeon_crtc->crtc_id; @@ -374,8 +376,10 @@ static void atombios_crtc_set_timing(struct drm_crtc *crtc, misc |= ATOM_COMPOSITESYNC; if (mode->flags & DRM_MODE_FLAG_INTERLACE) misc |= ATOM_INTERLACE; - if (mode->flags & DRM_MODE_FLAG_DBLSCAN) + if (mode->flags & DRM_MODE_FLAG_DBLCLK) misc |= ATOM_DOUBLE_CLOCK_MODE; + if (mode->flags & DRM_MODE_FLAG_DBLSCAN) + misc |= ATOM_H_REPLICATIONBY2 | ATOM_V_REPLICATIONBY2; args.susModeMiscInfo.usAccess = cpu_to_le16(misc); args.ucCRTC = radeon_crtc->crtc_id; diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c index c3664bc05acf..c4558bdb0584 100644 --- a/drivers/gpu/drm/radeon/cik.c +++ b/drivers/gpu/drm/radeon/cik.c @@ -5360,7 +5360,7 @@ static int cik_pcie_gart_enable(struct radeon_device *rdev) */ /* set vm size, must be a multiple of 4 */ WREG32(VM_CONTEXT1_PAGE_TABLE_START_ADDR, 0); - WREG32(VM_CONTEXT1_PAGE_TABLE_END_ADDR, rdev->vm_manager.max_pfn); + WREG32(VM_CONTEXT1_PAGE_TABLE_END_ADDR, rdev->vm_manager.max_pfn - 1); for (i = 1; i < 16; i++) { if (i < 8) WREG32(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (i << 2), diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c index f8c01b8d1594..392d94b94905 100644 --- a/drivers/gpu/drm/radeon/ni.c +++ b/drivers/gpu/drm/radeon/ni.c @@ -1256,7 +1256,8 @@ static int cayman_pcie_gart_enable(struct radeon_device *rdev) */ for (i = 1; i < 8; i++) { WREG32(VM_CONTEXT0_PAGE_TABLE_START_ADDR + (i << 2), 0); - WREG32(VM_CONTEXT0_PAGE_TABLE_END_ADDR + (i << 2), rdev->vm_manager.max_pfn); + WREG32(VM_CONTEXT0_PAGE_TABLE_END_ADDR + (i << 2), + rdev->vm_manager.max_pfn - 1); WREG32(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (i << 2), rdev->gart.table_addr >> 12); } diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c index 64d6cfba9952..d625a14ec038 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.c +++ b/drivers/gpu/drm/radeon/radeon_asic.c @@ -1173,7 +1173,7 @@ static struct radeon_asic rs780_asic = { static struct radeon_asic_ring rv770_uvd_ring = { .ib_execute = &uvd_v1_0_ib_execute, .emit_fence = &uvd_v2_2_fence_emit, - .emit_semaphore = &uvd_v1_0_semaphore_emit, + .emit_semaphore = &uvd_v2_2_semaphore_emit, .cs_parse = &radeon_uvd_cs_parse, .ring_test = &uvd_v1_0_ring_test, .ib_test = &uvd_v1_0_ib_test, diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h index ae637cfda783..f6e19edb1166 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.h +++ b/drivers/gpu/drm/radeon/radeon_asic.h @@ -853,6 +853,10 @@ void uvd_v1_0_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib); int uvd_v2_2_resume(struct radeon_device *rdev); void uvd_v2_2_fence_emit(struct radeon_device *rdev, struct radeon_fence *fence); +bool uvd_v2_2_semaphore_emit(struct radeon_device *rdev, + struct radeon_ring *ring, + struct radeon_semaphore *semaphore, + bool emit_wait); /* uvd v3.1 */ bool uvd_v3_1_semaphore_emit(struct radeon_device *rdev, diff --git a/drivers/gpu/drm/radeon/radeon_uvd.c b/drivers/gpu/drm/radeon/radeon_uvd.c index 414e07928693..bcfac7624550 100644 --- a/drivers/gpu/drm/radeon/radeon_uvd.c +++ b/drivers/gpu/drm/radeon/radeon_uvd.c @@ -350,6 +350,29 @@ static int radeon_uvd_cs_msg_decode(uint32_t *msg, unsigned buf_sizes[]) return 0; } +static int radeon_uvd_validate_codec(struct radeon_cs_parser *p, + unsigned stream_type) +{ + switch (stream_type) { + case 0: /* H264 */ + case 1: /* VC1 */ + /* always supported */ + return 0; + + case 3: /* MPEG2 */ + case 4: /* MPEG4 */ + /* only since UVD 3 */ + if (p->rdev->family >= CHIP_PALM) + return 0; + + /* fall through */ + default: + DRM_ERROR("UVD codec not supported by hardware %d!\n", + stream_type); + return -EINVAL; + } +} + static int radeon_uvd_cs_msg(struct radeon_cs_parser *p, struct radeon_bo *bo, unsigned offset, unsigned buf_sizes[]) { @@ -388,50 +411,70 @@ static int radeon_uvd_cs_msg(struct radeon_cs_parser *p, struct radeon_bo *bo, return -EINVAL; } - if (msg_type == 1) { - /* it's a decode msg, calc buffer sizes */ - r = radeon_uvd_cs_msg_decode(msg, buf_sizes); - /* calc image size (width * height) */ - img_size = msg[6] * msg[7]; + switch (msg_type) { + case 0: + /* it's a create msg, calc image size (width * height) */ + img_size = msg[7] * msg[8]; + + r = radeon_uvd_validate_codec(p, msg[4]); + radeon_bo_kunmap(bo); + if (r) + return r; + + /* try to alloc a new handle */ + for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i) { + if (atomic_read(&p->rdev->uvd.handles[i]) == handle) { + DRM_ERROR("Handle 0x%x already in use!\n", handle); + return -EINVAL; + } + + if (!atomic_cmpxchg(&p->rdev->uvd.handles[i], 0, handle)) { + p->rdev->uvd.filp[i] = p->filp; + p->rdev->uvd.img_size[i] = img_size; + return 0; + } + } + + DRM_ERROR("No more free UVD handles!\n"); + return -EINVAL; + + case 1: + /* it's a decode msg, validate codec and calc buffer sizes */ + r = radeon_uvd_validate_codec(p, msg[4]); + if (!r) + r = radeon_uvd_cs_msg_decode(msg, buf_sizes); radeon_bo_kunmap(bo); if (r) return r; - } else if (msg_type == 2) { + /* validate the handle */ + for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i) { + if (atomic_read(&p->rdev->uvd.handles[i]) == handle) { + if (p->rdev->uvd.filp[i] != p->filp) { + DRM_ERROR("UVD handle collision detected!\n"); + return -EINVAL; + } + return 0; + } + } + + DRM_ERROR("Invalid UVD handle 0x%x!\n", handle); + return -ENOENT; + + case 2: /* it's a destroy msg, free the handle */ for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i) atomic_cmpxchg(&p->rdev->uvd.handles[i], handle, 0); radeon_bo_kunmap(bo); return 0; - } else { - /* it's a create msg, calc image size (width * height) */ - img_size = msg[7] * msg[8]; - radeon_bo_kunmap(bo); - if (msg_type != 0) { - DRM_ERROR("Illegal UVD message type (%d)!\n", msg_type); - return -EINVAL; - } - - /* it's a create msg, no special handling needed */ - } - - /* create or decode, validate the handle */ - for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i) { - if (atomic_read(&p->rdev->uvd.handles[i]) == handle) - return 0; - } + default: - /* handle not found try to alloc a new one */ - for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i) { - if (!atomic_cmpxchg(&p->rdev->uvd.handles[i], 0, handle)) { - p->rdev->uvd.filp[i] = p->filp; - p->rdev->uvd.img_size[i] = img_size; - return 0; - } + DRM_ERROR("Illegal UVD message type (%d)!\n", msg_type); + return -EINVAL; } - DRM_ERROR("No more free UVD handles!\n"); + BUG(); return -EINVAL; } diff --git a/drivers/gpu/drm/radeon/rv770d.h b/drivers/gpu/drm/radeon/rv770d.h index 3cf1e2921545..9ef2064b1c9c 100644 --- a/drivers/gpu/drm/radeon/rv770d.h +++ b/drivers/gpu/drm/radeon/rv770d.h @@ -989,6 +989,9 @@ ((n) & 0x3FFF) << 16) /* UVD */ +#define UVD_SEMA_ADDR_LOW 0xef00 +#define UVD_SEMA_ADDR_HIGH 0xef04 +#define UVD_SEMA_CMD 0xef08 #define UVD_GPCOM_VCPU_CMD 0xef0c #define UVD_GPCOM_VCPU_DATA0 0xef10 #define UVD_GPCOM_VCPU_DATA1 0xef14 diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c index 2f2deccb3b78..49da9fc6b742 100644 --- a/drivers/gpu/drm/radeon/si.c +++ b/drivers/gpu/drm/radeon/si.c @@ -4084,7 +4084,7 @@ static int si_pcie_gart_enable(struct radeon_device *rdev) /* empty context1-15 */ /* set vm size, must be a multiple of 4 */ WREG32(VM_CONTEXT1_PAGE_TABLE_START_ADDR, 0); - WREG32(VM_CONTEXT1_PAGE_TABLE_END_ADDR, rdev->vm_manager.max_pfn); + WREG32(VM_CONTEXT1_PAGE_TABLE_END_ADDR, rdev->vm_manager.max_pfn - 1); /* Assign the pt base to something valid for now; the pts used for * the VMs are determined by the application and setup and assigned * on the fly in the vm part of radeon_gart.c diff --git a/drivers/gpu/drm/radeon/si_dpm.c b/drivers/gpu/drm/radeon/si_dpm.c index 35bf2bba69bf..11804cc1e11f 100644 --- a/drivers/gpu/drm/radeon/si_dpm.c +++ b/drivers/gpu/drm/radeon/si_dpm.c @@ -2913,6 +2913,7 @@ struct si_dpm_quirk { static struct si_dpm_quirk si_dpm_quirk_list[] = { /* PITCAIRN - https://bugs.freedesktop.org/show_bug.cgi?id=76490 */ { PCI_VENDOR_ID_ATI, 0x6810, 0x1462, 0x3036, 0, 120000 }, + { PCI_VENDOR_ID_ATI, 0x6811, 0x174b, 0xe271, 0, 120000 }, { 0, 0, 0, 0 }, }; diff --git a/drivers/gpu/drm/radeon/uvd_v1_0.c b/drivers/gpu/drm/radeon/uvd_v1_0.c index c310a0aeebb9..0fa9009fef64 100644 --- a/drivers/gpu/drm/radeon/uvd_v1_0.c +++ b/drivers/gpu/drm/radeon/uvd_v1_0.c @@ -365,18 +365,8 @@ bool uvd_v1_0_semaphore_emit(struct radeon_device *rdev, struct radeon_semaphore *semaphore, bool emit_wait) { - uint64_t addr = semaphore->gpu_addr; - - radeon_ring_write(ring, PACKET0(UVD_SEMA_ADDR_LOW, 0)); - radeon_ring_write(ring, (addr >> 3) & 0x000FFFFF); - - radeon_ring_write(ring, PACKET0(UVD_SEMA_ADDR_HIGH, 0)); - radeon_ring_write(ring, (addr >> 23) & 0x000FFFFF); - - radeon_ring_write(ring, PACKET0(UVD_SEMA_CMD, 0)); - radeon_ring_write(ring, emit_wait ? 1 : 0); - - return true; + /* disable semaphores for UVD V1 hardware */ + return false; } /** diff --git a/drivers/gpu/drm/radeon/uvd_v2_2.c b/drivers/gpu/drm/radeon/uvd_v2_2.c index d1771004cb52..19ccb2ae7a5d 100644 --- a/drivers/gpu/drm/radeon/uvd_v2_2.c +++ b/drivers/gpu/drm/radeon/uvd_v2_2.c @@ -60,6 +60,35 @@ void uvd_v2_2_fence_emit(struct radeon_device *rdev, } /** + * uvd_v2_2_semaphore_emit - emit semaphore command + * + * @rdev: radeon_device pointer + * @ring: radeon_ring pointer + * @semaphore: semaphore to emit commands for + * @emit_wait: true if we should emit a wait command + * + * Emit a semaphore command (either wait or signal) to the UVD ring. + */ +bool uvd_v2_2_semaphore_emit(struct radeon_device *rdev, + struct radeon_ring *ring, + struct radeon_semaphore *semaphore, + bool emit_wait) +{ + uint64_t addr = semaphore->gpu_addr; + + radeon_ring_write(ring, PACKET0(UVD_SEMA_ADDR_LOW, 0)); + radeon_ring_write(ring, (addr >> 3) & 0x000FFFFF); + + radeon_ring_write(ring, PACKET0(UVD_SEMA_ADDR_HIGH, 0)); + radeon_ring_write(ring, (addr >> 23) & 0x000FFFFF); + + radeon_ring_write(ring, PACKET0(UVD_SEMA_CMD, 0)); + radeon_ring_write(ring, emit_wait ? 1 : 0); + + return true; +} + +/** * uvd_v2_2_resume - memory controller programming * * @rdev: radeon_device pointer |