diff options
Diffstat (limited to 'drivers/gpu')
31 files changed, 782 insertions, 563 deletions
diff --git a/drivers/gpu/drm/drm_modeset_lock.c b/drivers/gpu/drm/drm_modeset_lock.c index 0dc57d5ecd10..3a02e5e3e9f3 100644 --- a/drivers/gpu/drm/drm_modeset_lock.c +++ b/drivers/gpu/drm/drm_modeset_lock.c @@ -35,7 +35,7 @@ * of extra utility/tracking out of our acquire-ctx. This is provided * by drm_modeset_lock / drm_modeset_acquire_ctx. * - * For basic principles of ww_mutex, see: Documentation/ww-mutex-design.txt + * For basic principles of ww_mutex, see: Documentation/locking/ww-mutex-design.txt * * The basic usage pattern is to: * diff --git a/drivers/gpu/drm/i915/i915_cmd_parser.c b/drivers/gpu/drm/i915/i915_cmd_parser.c index dea99d92fb4a..4b7ed5289217 100644 --- a/drivers/gpu/drm/i915/i915_cmd_parser.c +++ b/drivers/gpu/drm/i915/i915_cmd_parser.c @@ -709,11 +709,13 @@ int i915_cmd_parser_init_ring(struct intel_engine_cs *ring) BUG_ON(!validate_cmds_sorted(ring, cmd_tables, cmd_table_count)); BUG_ON(!validate_regs_sorted(ring)); - ret = init_hash_table(ring, cmd_tables, cmd_table_count); - if (ret) { - DRM_ERROR("CMD: cmd_parser_init failed!\n"); - fini_hash_table(ring); - return ret; + if (hash_empty(ring->cmd_hash)) { + ret = init_hash_table(ring, cmd_tables, cmd_table_count); + if (ret) { + DRM_ERROR("CMD: cmd_parser_init failed!\n"); + fini_hash_table(ring); + return ret; + } } ring->needs_cmd_parser = true; diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 1411613f2174..e42925f76b4b 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -1310,6 +1310,16 @@ void i915_check_and_clear_faults(struct drm_device *dev) POSTING_READ(RING_FAULT_REG(&dev_priv->ring[RCS])); } +static void i915_ggtt_flush(struct drm_i915_private *dev_priv) +{ + if (INTEL_INFO(dev_priv->dev)->gen < 6) { + intel_gtt_chipset_flush(); + } else { + I915_WRITE(GFX_FLSH_CNTL_GEN6, GFX_FLSH_CNTL_EN); + POSTING_READ(GFX_FLSH_CNTL_GEN6); + } +} + void i915_gem_suspend_gtt_mappings(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -1326,6 +1336,8 @@ void i915_gem_suspend_gtt_mappings(struct drm_device *dev) dev_priv->gtt.base.start, dev_priv->gtt.base.total, true); + + i915_ggtt_flush(dev_priv); } void i915_gem_restore_gtt_mappings(struct drm_device *dev) @@ -1378,7 +1390,7 @@ void i915_gem_restore_gtt_mappings(struct drm_device *dev) gen6_write_pdes(container_of(vm, struct i915_hw_ppgtt, base)); } - i915_gem_chipset_flush(dev); + i915_ggtt_flush(dev_priv); } int i915_gem_gtt_prepare_object(struct drm_i915_gem_object *obj) diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c index 7f84dd263ee8..9842fd2e742a 100644 --- a/drivers/gpu/drm/i915/i915_params.c +++ b/drivers/gpu/drm/i915/i915_params.c @@ -66,12 +66,12 @@ module_param_named(powersave, i915.powersave, int, 0600); MODULE_PARM_DESC(powersave, "Enable powersavings, fbc, downclocking, etc. (default: true)"); -module_param_named(semaphores, i915.semaphores, int, 0400); +module_param_named_unsafe(semaphores, i915.semaphores, int, 0400); MODULE_PARM_DESC(semaphores, "Use semaphores for inter-ring sync " "(default: -1 (use per-chip defaults))"); -module_param_named(enable_rc6, i915.enable_rc6, int, 0400); +module_param_named_unsafe(enable_rc6, i915.enable_rc6, int, 0400); MODULE_PARM_DESC(enable_rc6, "Enable power-saving render C-state 6. " "Different stages can be selected via bitmask values " @@ -79,7 +79,7 @@ MODULE_PARM_DESC(enable_rc6, "For example, 3 would enable rc6 and deep rc6, and 7 would enable everything. " "default: -1 (use per-chip default)"); -module_param_named(enable_fbc, i915.enable_fbc, int, 0600); +module_param_named_unsafe(enable_fbc, i915.enable_fbc, int, 0600); MODULE_PARM_DESC(enable_fbc, "Enable frame buffer compression for power savings " "(default: -1 (use per-chip default))"); @@ -113,7 +113,7 @@ MODULE_PARM_DESC(enable_hangcheck, "WARNING: Disabling this can cause system wide hangs. " "(default: true)"); -module_param_named(enable_ppgtt, i915.enable_ppgtt, int, 0400); +module_param_named_unsafe(enable_ppgtt, i915.enable_ppgtt, int, 0400); MODULE_PARM_DESC(enable_ppgtt, "Override PPGTT usage. " "(-1=auto [default], 0=disabled, 1=aliasing, 2=full)"); diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index eee79e1c3222..afcc8dd40bdd 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -946,7 +946,7 @@ static void parse_ddi_port(struct drm_i915_private *dev_priv, enum port port, DRM_DEBUG_KMS("Analog port %c is also DP or TMDS compatible\n", port_name(port)); if (is_dvi && (port == PORT_A || port == PORT_E)) - DRM_DEBUG_KMS("Port %c is TMDS compabile\n", port_name(port)); + DRM_DEBUG_KMS("Port %c is TMDS compatible\n", port_name(port)); if (!is_dvi && !is_dp && !is_crt) DRM_DEBUG_KMS("Port %c is not DP/TMDS/CRT compatible\n", port_name(port)); diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index ca34de7f6a7b..5a9de21637b7 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -732,7 +732,7 @@ static void intel_hdmi_get_config(struct intel_encoder *encoder, if (tmp & HDMI_MODE_SELECT_HDMI) pipe_config->has_hdmi_sink = true; - if (tmp & HDMI_MODE_SELECT_HDMI) + if (tmp & SDVO_AUDIO_ENABLE) pipe_config->has_audio = true; if (!HAS_PCH_SPLIT(dev) && diff --git a/drivers/gpu/drm/i915/intel_opregion.c b/drivers/gpu/drm/i915/intel_opregion.c index ca52ad2ae7d1..d8de1d5140a7 100644 --- a/drivers/gpu/drm/i915/intel_opregion.c +++ b/drivers/gpu/drm/i915/intel_opregion.c @@ -396,6 +396,16 @@ int intel_opregion_notify_adapter(struct drm_device *dev, pci_power_t state) return -EINVAL; } +/* + * If the vendor backlight interface is not in use and ACPI backlight interface + * is broken, do not bother processing backlight change requests from firmware. + */ +static bool should_ignore_backlight_request(void) +{ + return acpi_video_backlight_support() && + !acpi_video_verify_backlight_support(); +} + static u32 asle_set_backlight(struct drm_device *dev, u32 bclp) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -404,11 +414,7 @@ static u32 asle_set_backlight(struct drm_device *dev, u32 bclp) DRM_DEBUG_DRIVER("bclp = 0x%08x\n", bclp); - /* - * If the acpi_video interface is not supposed to be used, don't - * bother processing backlight level change requests from firmware. - */ - if (!acpi_video_verify_backlight_support()) { + if (should_ignore_backlight_request()) { DRM_DEBUG_KMS("opregion backlight request ignored\n"); return 0; } diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c index 4b5bb5d58a54..f8cbb512132f 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c @@ -1763,9 +1763,10 @@ nv50_disp_intr_unk40_0_tmds(struct nv50_disp_priv *priv, struct dcb_output *outp const int or = ffs(outp->or) - 1; const u32 loff = (or * 0x800) + (link * 0x80); const u16 mask = (outp->sorconf.link << 6) | outp->or; + struct dcb_output match; u8 ver, hdr; - if (dcb_outp_match(bios, DCB_OUTPUT_DP, mask, &ver, &hdr, outp)) + if (dcb_outp_match(bios, DCB_OUTPUT_DP, mask, &ver, &hdr, &match)) nv_mask(priv, 0x61c10c + loff, 0x00000001, 0x00000000); } diff --git a/drivers/gpu/drm/nouveau/nouveau_chan.c b/drivers/gpu/drm/nouveau/nouveau_chan.c index 99cd9e4a2aa6..3440fc999f2f 100644 --- a/drivers/gpu/drm/nouveau/nouveau_chan.c +++ b/drivers/gpu/drm/nouveau/nouveau_chan.c @@ -285,6 +285,7 @@ nouveau_channel_init(struct nouveau_channel *chan, u32 vram, u32 gart) struct nouveau_software_chan *swch; struct nv_dma_v0 args = {}; int ret, i; + bool save; nvif_object_map(chan->object); @@ -386,7 +387,11 @@ nouveau_channel_init(struct nouveau_channel *chan, u32 vram, u32 gart) } /* initialise synchronisation */ - return nouveau_fence(chan->drm)->context_new(chan); + save = cli->base.super; + cli->base.super = true; /* hack until fencenv50 fixed */ + ret = nouveau_fence(chan->drm)->context_new(chan); + cli->base.super = save; + return ret; } int diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index 65b4fd53dd4e..4a21b2b06ce2 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c @@ -550,14 +550,12 @@ nouveau_display_destroy(struct drm_device *dev) } int -nouveau_display_suspend(struct drm_device *dev) +nouveau_display_suspend(struct drm_device *dev, bool runtime) { - struct nouveau_drm *drm = nouveau_drm(dev); struct drm_crtc *crtc; nouveau_display_fini(dev); - NV_INFO(drm, "unpinning framebuffer(s)...\n"); list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { struct nouveau_framebuffer *nouveau_fb; @@ -579,12 +577,13 @@ nouveau_display_suspend(struct drm_device *dev) } void -nouveau_display_repin(struct drm_device *dev) +nouveau_display_resume(struct drm_device *dev, bool runtime) { struct nouveau_drm *drm = nouveau_drm(dev); struct drm_crtc *crtc; - int ret; + int ret, head; + /* re-pin fb/cursors */ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { struct nouveau_framebuffer *nouveau_fb; @@ -606,13 +605,6 @@ nouveau_display_repin(struct drm_device *dev) if (ret) NV_ERROR(drm, "Could not pin/map cursor.\n"); } -} - -void -nouveau_display_resume(struct drm_device *dev) -{ - struct drm_crtc *crtc; - int head; nouveau_display_init(dev); @@ -627,6 +619,13 @@ nouveau_display_resume(struct drm_device *dev) for (head = 0; head < dev->mode_config.num_crtc; head++) drm_vblank_on(dev, head); + /* This should ensure we don't hit a locking problem when someone + * wakes us up via a connector. We should never go into suspend + * while the display is on anyways. + */ + if (runtime) + return; + drm_helper_resume_force_mode(dev); list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { diff --git a/drivers/gpu/drm/nouveau/nouveau_display.h b/drivers/gpu/drm/nouveau/nouveau_display.h index 88ca177cb1c7..be3d5947c6be 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.h +++ b/drivers/gpu/drm/nouveau/nouveau_display.h @@ -63,9 +63,8 @@ int nouveau_display_create(struct drm_device *dev); void nouveau_display_destroy(struct drm_device *dev); int nouveau_display_init(struct drm_device *dev); void nouveau_display_fini(struct drm_device *dev); -int nouveau_display_suspend(struct drm_device *dev); -void nouveau_display_repin(struct drm_device *dev); -void nouveau_display_resume(struct drm_device *dev); +int nouveau_display_suspend(struct drm_device *dev, bool runtime); +void nouveau_display_resume(struct drm_device *dev, bool runtime); int nouveau_display_vblank_enable(struct drm_device *, int); void nouveau_display_vblank_disable(struct drm_device *, int); int nouveau_display_scanoutpos(struct drm_device *, int, unsigned int, diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index 9c3af96a7153..3ed32dd90303 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c @@ -547,9 +547,11 @@ nouveau_do_suspend(struct drm_device *dev, bool runtime) struct nouveau_cli *cli; int ret; - if (dev->mode_config.num_crtc && !runtime) { + if (dev->mode_config.num_crtc) { + NV_INFO(drm, "suspending console...\n"); + nouveau_fbcon_set_suspend(dev, 1); NV_INFO(drm, "suspending display...\n"); - ret = nouveau_display_suspend(dev); + ret = nouveau_display_suspend(dev, runtime); if (ret) return ret; } @@ -603,7 +605,7 @@ fail_client: fail_display: if (dev->mode_config.num_crtc) { NV_INFO(drm, "resuming display...\n"); - nouveau_display_resume(dev); + nouveau_display_resume(dev, runtime); } return ret; } @@ -618,9 +620,6 @@ int nouveau_pmops_suspend(struct device *dev) drm_dev->switch_power_state == DRM_SWITCH_POWER_DYNAMIC_OFF) return 0; - if (drm_dev->mode_config.num_crtc) - nouveau_fbcon_set_suspend(drm_dev, 1); - ret = nouveau_do_suspend(drm_dev, false); if (ret) return ret; @@ -633,7 +632,7 @@ int nouveau_pmops_suspend(struct device *dev) } static int -nouveau_do_resume(struct drm_device *dev) +nouveau_do_resume(struct drm_device *dev, bool runtime) { struct nouveau_drm *drm = nouveau_drm(dev); struct nouveau_cli *cli; @@ -658,7 +657,9 @@ nouveau_do_resume(struct drm_device *dev) if (dev->mode_config.num_crtc) { NV_INFO(drm, "resuming display...\n"); - nouveau_display_repin(dev); + nouveau_display_resume(dev, runtime); + NV_INFO(drm, "resuming console...\n"); + nouveau_fbcon_set_suspend(dev, 0); } return 0; @@ -681,47 +682,21 @@ int nouveau_pmops_resume(struct device *dev) return ret; pci_set_master(pdev); - ret = nouveau_do_resume(drm_dev); - if (ret) - return ret; - - if (drm_dev->mode_config.num_crtc) { - nouveau_display_resume(drm_dev); - nouveau_fbcon_set_suspend(drm_dev, 0); - } - - return 0; + return nouveau_do_resume(drm_dev, false); } static int nouveau_pmops_freeze(struct device *dev) { struct pci_dev *pdev = to_pci_dev(dev); struct drm_device *drm_dev = pci_get_drvdata(pdev); - int ret; - - if (drm_dev->mode_config.num_crtc) - nouveau_fbcon_set_suspend(drm_dev, 1); - - ret = nouveau_do_suspend(drm_dev, false); - return ret; + return nouveau_do_suspend(drm_dev, false); } static int nouveau_pmops_thaw(struct device *dev) { struct pci_dev *pdev = to_pci_dev(dev); struct drm_device *drm_dev = pci_get_drvdata(pdev); - int ret; - - ret = nouveau_do_resume(drm_dev); - if (ret) - return ret; - - if (drm_dev->mode_config.num_crtc) { - nouveau_display_resume(drm_dev); - nouveau_fbcon_set_suspend(drm_dev, 0); - } - - return 0; + return nouveau_do_resume(drm_dev, false); } @@ -977,7 +952,7 @@ static int nouveau_pmops_runtime_resume(struct device *dev) return ret; pci_set_master(pdev); - ret = nouveau_do_resume(drm_dev); + ret = nouveau_do_resume(drm_dev, true); drm_kms_helper_poll_enable(drm_dev); /* do magic */ nvif_mask(device, 0x88488, (1 << 25), (1 << 25)); diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c index 8bdd27091db8..49fe6075cc7c 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c +++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c @@ -486,6 +486,16 @@ static const struct drm_fb_helper_funcs nouveau_fbcon_helper_funcs = { .fb_probe = nouveau_fbcon_create, }; +static void +nouveau_fbcon_set_suspend_work(struct work_struct *work) +{ + struct nouveau_fbdev *fbcon = container_of(work, typeof(*fbcon), work); + console_lock(); + nouveau_fbcon_accel_restore(fbcon->dev); + nouveau_fbcon_zfill(fbcon->dev, fbcon); + fb_set_suspend(fbcon->helper.fbdev, FBINFO_STATE_RUNNING); + console_unlock(); +} int nouveau_fbcon_init(struct drm_device *dev) @@ -503,6 +513,7 @@ nouveau_fbcon_init(struct drm_device *dev) if (!fbcon) return -ENOMEM; + INIT_WORK(&fbcon->work, nouveau_fbcon_set_suspend_work); fbcon->dev = dev; drm->fbcon = fbcon; @@ -551,14 +562,14 @@ nouveau_fbcon_set_suspend(struct drm_device *dev, int state) { struct nouveau_drm *drm = nouveau_drm(dev); if (drm->fbcon) { - console_lock(); - if (state == 0) { - nouveau_fbcon_accel_restore(dev); - nouveau_fbcon_zfill(dev, drm->fbcon); + if (state == FBINFO_STATE_RUNNING) { + schedule_work(&drm->fbcon->work); + return; } + flush_work(&drm->fbcon->work); + console_lock(); fb_set_suspend(drm->fbcon->helper.fbdev, state); - if (state == 1) - nouveau_fbcon_accel_save_disable(dev); + nouveau_fbcon_accel_save_disable(dev); console_unlock(); } } diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.h b/drivers/gpu/drm/nouveau/nouveau_fbcon.h index 34658cfa8f5d..0b465c7d3907 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fbcon.h +++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.h @@ -36,6 +36,7 @@ struct nouveau_fbdev { struct nouveau_framebuffer nouveau_fb; struct list_head fbdev_list; struct drm_device *dev; + struct work_struct work; unsigned int saved_flags; struct nvif_object surf2d; struct nvif_object clip; diff --git a/drivers/gpu/drm/nouveau/nouveau_nvif.c b/drivers/gpu/drm/nouveau/nouveau_nvif.c index 47ca88623753..6544b84f0303 100644 --- a/drivers/gpu/drm/nouveau/nouveau_nvif.c +++ b/drivers/gpu/drm/nouveau/nouveau_nvif.c @@ -40,12 +40,12 @@ #include "nouveau_usif.h" static void -nvkm_client_unmap(void *priv, void *ptr, u32 size) +nvkm_client_unmap(void *priv, void __iomem *ptr, u32 size) { iounmap(ptr); } -static void * +static void __iomem * nvkm_client_map(void *priv, u64 handle, u32 size) { return ioremap(handle, size); diff --git a/drivers/gpu/drm/nouveau/nvif/driver.h b/drivers/gpu/drm/nouveau/nvif/driver.h index b72a8f0c2758..ac4bdb3ea506 100644 --- a/drivers/gpu/drm/nouveau/nvif/driver.h +++ b/drivers/gpu/drm/nouveau/nvif/driver.h @@ -9,8 +9,8 @@ struct nvif_driver { int (*suspend)(void *priv); int (*resume)(void *priv); int (*ioctl)(void *priv, bool super, void *data, u32 size, void **hack); - void *(*map)(void *priv, u64 handle, u32 size); - void (*unmap)(void *priv, void *ptr, u32 size); + void __iomem *(*map)(void *priv, u64 handle, u32 size); + void (*unmap)(void *priv, void __iomem *ptr, u32 size); bool keep; }; diff --git a/drivers/gpu/drm/nouveau/nvif/object.h b/drivers/gpu/drm/nouveau/nvif/object.h index fac3a3bbec44..fe519179b76c 100644 --- a/drivers/gpu/drm/nouveau/nvif/object.h +++ b/drivers/gpu/drm/nouveau/nvif/object.h @@ -14,7 +14,7 @@ struct nvif_object { void *priv; /*XXX: hack */ void (*dtor)(struct nvif_object *); struct { - void *ptr; + void __iomem *ptr; u32 size; } map; }; @@ -42,7 +42,7 @@ void nvif_object_unmap(struct nvif_object *); struct nvif_object *_object = nvif_object(a); \ u32 _data; \ if (likely(_object->map.ptr)) \ - _data = ioread##b##_native((u8 *)_object->map.ptr + (c)); \ + _data = ioread##b##_native((u8 __iomem *)_object->map.ptr + (c)); \ else \ _data = nvif_object_rd(_object, (b) / 8, (c)); \ _data; \ @@ -50,7 +50,7 @@ void nvif_object_unmap(struct nvif_object *); #define nvif_wr(a,b,c,d) ({ \ struct nvif_object *_object = nvif_object(a); \ if (likely(_object->map.ptr)) \ - iowrite##b##_native((d), (u8 *)_object->map.ptr + (c)); \ + iowrite##b##_native((d), (u8 __iomem *)_object->map.ptr + (c)); \ else \ nvif_object_wr(_object, (b) / 8, (c), (d)); \ }) diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c index fa9565957f9d..3d546c606b43 100644 --- a/drivers/gpu/drm/radeon/cik.c +++ b/drivers/gpu/drm/radeon/cik.c @@ -4803,7 +4803,7 @@ struct bonaire_mqd */ static int cik_cp_compute_resume(struct radeon_device *rdev) { - int r, i, idx; + int r, i, j, idx; u32 tmp; bool use_doorbell = true; u64 hqd_gpu_addr; @@ -4922,7 +4922,7 @@ static int cik_cp_compute_resume(struct radeon_device *rdev) mqd->queue_state.cp_hqd_pq_wptr= 0; if (RREG32(CP_HQD_ACTIVE) & 1) { WREG32(CP_HQD_DEQUEUE_REQUEST, 1); - for (i = 0; i < rdev->usec_timeout; i++) { + for (j = 0; j < rdev->usec_timeout; j++) { if (!(RREG32(CP_HQD_ACTIVE) & 1)) break; udelay(1); @@ -7751,17 +7751,17 @@ static inline u32 cik_get_ih_wptr(struct radeon_device *rdev) wptr = RREG32(IH_RB_WPTR); if (wptr & RB_OVERFLOW) { + wptr &= ~RB_OVERFLOW; /* When a ring buffer overflow happen start parsing interrupt * from the last not overwritten vector (wptr + 16). Hopefully * this should allow us to catchup. */ - dev_warn(rdev->dev, "IH ring buffer overflow (0x%08X, %d, %d)\n", - wptr, rdev->ih.rptr, (wptr + 16) + rdev->ih.ptr_mask); + dev_warn(rdev->dev, "IH ring buffer overflow (0x%08X, 0x%08X, 0x%08X)\n", + wptr, rdev->ih.rptr, (wptr + 16) & rdev->ih.ptr_mask); rdev->ih.rptr = (wptr + 16) & rdev->ih.ptr_mask; tmp = RREG32(IH_RB_CNTL); tmp |= IH_WPTR_OVERFLOW_CLEAR; WREG32(IH_RB_CNTL, tmp); - wptr &= ~RB_OVERFLOW; } return (wptr & rdev->ih.ptr_mask); } @@ -8251,6 +8251,7 @@ restart_ih: /* wptr/rptr are in bytes! */ rptr += 16; rptr &= rdev->ih.ptr_mask; + WREG32(IH_RB_RPTR, rptr); } if (queue_hotplug) schedule_work(&rdev->hotplug_work); @@ -8259,7 +8260,6 @@ restart_ih: if (queue_thermal) schedule_work(&rdev->pm.dpm.thermal.work); rdev->ih.rptr = rptr; - WREG32(IH_RB_RPTR, rdev->ih.rptr); atomic_set(&rdev->ih.lock, 0); /* make sure wptr hasn't changed while processing */ diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index dbca60c7d097..e50807c29f69 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -4749,17 +4749,17 @@ static u32 evergreen_get_ih_wptr(struct radeon_device *rdev) wptr = RREG32(IH_RB_WPTR); if (wptr & RB_OVERFLOW) { + wptr &= ~RB_OVERFLOW; /* When a ring buffer overflow happen start parsing interrupt * from the last not overwritten vector (wptr + 16). Hopefully * this should allow us to catchup. */ - dev_warn(rdev->dev, "IH ring buffer overflow (0x%08X, %d, %d)\n", - wptr, rdev->ih.rptr, (wptr + 16) + rdev->ih.ptr_mask); + dev_warn(rdev->dev, "IH ring buffer overflow (0x%08X, 0x%08X, 0x%08X)\n", + wptr, rdev->ih.rptr, (wptr + 16) & rdev->ih.ptr_mask); rdev->ih.rptr = (wptr + 16) & rdev->ih.ptr_mask; tmp = RREG32(IH_RB_CNTL); tmp |= IH_WPTR_OVERFLOW_CLEAR; WREG32(IH_RB_CNTL, tmp); - wptr &= ~RB_OVERFLOW; } return (wptr & rdev->ih.ptr_mask); } @@ -5137,6 +5137,7 @@ restart_ih: /* wptr/rptr are in bytes! */ rptr += 16; rptr &= rdev->ih.ptr_mask; + WREG32(IH_RB_RPTR, rptr); } if (queue_hotplug) schedule_work(&rdev->hotplug_work); @@ -5145,7 +5146,6 @@ restart_ih: if (queue_thermal && rdev->pm.dpm_enabled) schedule_work(&rdev->pm.dpm.thermal.work); rdev->ih.rptr = rptr; - WREG32(IH_RB_RPTR, rdev->ih.rptr); atomic_set(&rdev->ih.lock, 0); /* make sure wptr hasn't changed while processing */ diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 3cfb50056f7a..ea5c9af722ef 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -3792,17 +3792,17 @@ static u32 r600_get_ih_wptr(struct radeon_device *rdev) wptr = RREG32(IH_RB_WPTR); if (wptr & RB_OVERFLOW) { + wptr &= ~RB_OVERFLOW; /* When a ring buffer overflow happen start parsing interrupt * from the last not overwritten vector (wptr + 16). Hopefully * this should allow us to catchup. */ - dev_warn(rdev->dev, "IH ring buffer overflow (0x%08X, %d, %d)\n", - wptr, rdev->ih.rptr, (wptr + 16) + rdev->ih.ptr_mask); + dev_warn(rdev->dev, "IH ring buffer overflow (0x%08X, 0x%08X, 0x%08X)\n", + wptr, rdev->ih.rptr, (wptr + 16) & rdev->ih.ptr_mask); rdev->ih.rptr = (wptr + 16) & rdev->ih.ptr_mask; tmp = RREG32(IH_RB_CNTL); tmp |= IH_WPTR_OVERFLOW_CLEAR; WREG32(IH_RB_CNTL, tmp); - wptr &= ~RB_OVERFLOW; } return (wptr & rdev->ih.ptr_mask); } @@ -4048,6 +4048,7 @@ restart_ih: /* wptr/rptr are in bytes! */ rptr += 16; rptr &= rdev->ih.ptr_mask; + WREG32(IH_RB_RPTR, rptr); } if (queue_hotplug) schedule_work(&rdev->hotplug_work); @@ -4056,7 +4057,6 @@ restart_ih: if (queue_thermal && rdev->pm.dpm_enabled) schedule_work(&rdev->pm.dpm.thermal.work); rdev->ih.rptr = rptr; - WREG32(IH_RB_RPTR, rdev->ih.rptr); atomic_set(&rdev->ih.lock, 0); /* make sure wptr hasn't changed while processing */ diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 5f05b4c84338..3247bfd14410 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -106,6 +106,7 @@ extern int radeon_vm_block_size; extern int radeon_deep_color; extern int radeon_use_pflipirq; extern int radeon_bapm; +extern int radeon_backlight; /* * Copy from radeon_drv.h so we don't have to include both and have conflicting diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index 75223dd3a8a3..12c8329644c4 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -123,6 +123,10 @@ static struct radeon_px_quirk radeon_px_quirk_list[] = { * https://bugzilla.kernel.org/show_bug.cgi?id=51381 */ { PCI_VENDOR_ID_ATI, 0x6741, 0x1043, 0x108c, RADEON_PX_QUIRK_DISABLE_PX }, + /* Asus K53TK laptop with AMD A6-3420M APU and Radeon 7670m GPU + * https://bugzilla.kernel.org/show_bug.cgi?id=51381 + */ + { PCI_VENDOR_ID_ATI, 0x6840, 0x1043, 0x2122, RADEON_PX_QUIRK_DISABLE_PX }, /* macbook pro 8.2 */ { PCI_VENDOR_ID_ATI, 0x6741, PCI_VENDOR_ID_APPLE, 0x00e2, RADEON_PX_QUIRK_LONG_WAKEUP }, { 0, 0, 0, 0, 0 }, diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c index 4126fd0937a2..f9d17b29b343 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.c +++ b/drivers/gpu/drm/radeon/radeon_drv.c @@ -181,6 +181,7 @@ int radeon_vm_block_size = -1; int radeon_deep_color = 0; int radeon_use_pflipirq = 2; int radeon_bapm = -1; +int radeon_backlight = -1; MODULE_PARM_DESC(no_wb, "Disable AGP writeback for scratch registers"); module_param_named(no_wb, radeon_no_wb, int, 0444); @@ -263,6 +264,9 @@ module_param_named(use_pflipirq, radeon_use_pflipirq, int, 0444); MODULE_PARM_DESC(bapm, "BAPM support (1 = enable, 0 = disable, -1 = auto)"); module_param_named(bapm, radeon_bapm, int, 0444); +MODULE_PARM_DESC(backlight, "backlight support (1 = enable, 0 = disable, -1 = auto)"); +module_param_named(backlight, radeon_backlight, int, 0444); + static struct pci_device_id pciidlist[] = { radeon_PCI_IDS }; diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c index 3c2094c25b53..15edf23b465c 100644 --- a/drivers/gpu/drm/radeon/radeon_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_encoders.c @@ -158,10 +158,43 @@ radeon_get_encoder_enum(struct drm_device *dev, uint32_t supported_device, uint8 return ret; } +static void radeon_encoder_add_backlight(struct radeon_encoder *radeon_encoder, + struct drm_connector *connector) +{ + struct drm_device *dev = radeon_encoder->base.dev; + struct radeon_device *rdev = dev->dev_private; + bool use_bl = false; + + if (!(radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT))) + return; + + if (radeon_backlight == 0) { + return; + } else if (radeon_backlight == 1) { + use_bl = true; + } else if (radeon_backlight == -1) { + /* Quirks */ + /* Amilo Xi 2550 only works with acpi bl */ + if ((rdev->pdev->device == 0x9583) && + (rdev->pdev->subsystem_vendor == 0x1734) && + (rdev->pdev->subsystem_device == 0x1107)) + use_bl = false; + else + use_bl = true; + } + + if (use_bl) { + if (rdev->is_atom_bios) + radeon_atom_backlight_init(radeon_encoder, connector); + else + radeon_legacy_backlight_init(radeon_encoder, connector); + rdev->mode_info.bl_encoder = radeon_encoder; + } +} + void radeon_link_encoder_connector(struct drm_device *dev) { - struct radeon_device *rdev = dev->dev_private; struct drm_connector *connector; struct radeon_connector *radeon_connector; struct drm_encoder *encoder; @@ -174,13 +207,8 @@ radeon_link_encoder_connector(struct drm_device *dev) radeon_encoder = to_radeon_encoder(encoder); if (radeon_encoder->devices & radeon_connector->devices) { drm_mode_connector_attach_encoder(connector, encoder); - if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { - if (rdev->is_atom_bios) - radeon_atom_backlight_init(radeon_encoder, connector); - else - radeon_legacy_backlight_init(radeon_encoder, connector); - rdev->mode_info.bl_encoder = radeon_encoder; - } + if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) + radeon_encoder_add_backlight(radeon_encoder, connector); } } } diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c index 6bce40847753..3a0b973e8a96 100644 --- a/drivers/gpu/drm/radeon/si.c +++ b/drivers/gpu/drm/radeon/si.c @@ -6316,17 +6316,17 @@ static inline u32 si_get_ih_wptr(struct radeon_device *rdev) wptr = RREG32(IH_RB_WPTR); if (wptr & RB_OVERFLOW) { + wptr &= ~RB_OVERFLOW; /* When a ring buffer overflow happen start parsing interrupt * from the last not overwritten vector (wptr + 16). Hopefully * this should allow us to catchup. */ - dev_warn(rdev->dev, "IH ring buffer overflow (0x%08X, %d, %d)\n", - wptr, rdev->ih.rptr, (wptr + 16) + rdev->ih.ptr_mask); + dev_warn(rdev->dev, "IH ring buffer overflow (0x%08X, 0x%08X, 0x%08X)\n", + wptr, rdev->ih.rptr, (wptr + 16) & rdev->ih.ptr_mask); rdev->ih.rptr = (wptr + 16) & rdev->ih.ptr_mask; tmp = RREG32(IH_RB_CNTL); tmp |= IH_WPTR_OVERFLOW_CLEAR; WREG32(IH_RB_CNTL, tmp); - wptr &= ~RB_OVERFLOW; } return (wptr & rdev->ih.ptr_mask); } @@ -6664,13 +6664,13 @@ restart_ih: /* wptr/rptr are in bytes! */ rptr += 16; rptr &= rdev->ih.ptr_mask; + WREG32(IH_RB_RPTR, rptr); } if (queue_hotplug) schedule_work(&rdev->hotplug_work); if (queue_thermal && rdev->pm.dpm_enabled) schedule_work(&rdev->pm.dpm.thermal.work); rdev->ih.rptr = rptr; - WREG32(IH_RB_RPTR, rdev->ih.rptr); atomic_set(&rdev->ih.lock, 0); /* make sure wptr hasn't changed while processing */ diff --git a/drivers/gpu/drm/vmwgfx/svga_reg.h b/drivers/gpu/drm/vmwgfx/svga_reg.h index 11323dd5196f..e4259c2c1acc 100644 --- a/drivers/gpu/drm/vmwgfx/svga_reg.h +++ b/drivers/gpu/drm/vmwgfx/svga_reg.h @@ -35,7 +35,6 @@ /* * PCI device IDs. */ -#define PCI_VENDOR_ID_VMWARE 0x15AD #define PCI_DEVICE_ID_VMWARE_SVGA2 0x0405 /* diff --git a/drivers/gpu/ipu-v3/Makefile b/drivers/gpu/ipu-v3/Makefile index 1887972b4ac2..0b42836caae1 100644 --- a/drivers/gpu/ipu-v3/Makefile +++ b/drivers/gpu/ipu-v3/Makefile @@ -1,3 +1,4 @@ obj-$(CONFIG_IMX_IPUV3_CORE) += imx-ipu-v3.o -imx-ipu-v3-objs := ipu-common.o ipu-dc.o ipu-di.o ipu-dp.o ipu-dmfc.o ipu-smfc.o +imx-ipu-v3-objs := ipu-common.o ipu-cpmem.o ipu-dc.o ipu-di.o \ + ipu-dp.o ipu-dmfc.o ipu-smfc.o diff --git a/drivers/gpu/ipu-v3/ipu-common.c b/drivers/gpu/ipu-v3/ipu-common.c index 04e7b2eafbdd..5978e7aab8ed 100644 --- a/drivers/gpu/ipu-v3/ipu-common.c +++ b/drivers/gpu/ipu-v3/ipu-common.c @@ -44,17 +44,6 @@ static inline void ipu_cm_write(struct ipu_soc *ipu, u32 value, unsigned offset) writel(value, ipu->cm_reg + offset); } -static inline u32 ipu_idmac_read(struct ipu_soc *ipu, unsigned offset) -{ - return readl(ipu->idmac_reg + offset); -} - -static inline void ipu_idmac_write(struct ipu_soc *ipu, u32 value, - unsigned offset) -{ - writel(value, ipu->idmac_reg + offset); -} - void ipu_srm_dp_sync_update(struct ipu_soc *ipu) { u32 val; @@ -65,379 +54,6 @@ void ipu_srm_dp_sync_update(struct ipu_soc *ipu) } EXPORT_SYMBOL_GPL(ipu_srm_dp_sync_update); -struct ipu_ch_param __iomem *ipu_get_cpmem(struct ipuv3_channel *channel) -{ - struct ipu_soc *ipu = channel->ipu; - - return ipu->cpmem_base + channel->num; -} -EXPORT_SYMBOL_GPL(ipu_get_cpmem); - -void ipu_cpmem_set_high_priority(struct ipuv3_channel *channel) -{ - struct ipu_soc *ipu = channel->ipu; - struct ipu_ch_param __iomem *p = ipu_get_cpmem(channel); - u32 val; - - if (ipu->ipu_type == IPUV3EX) - ipu_ch_param_write_field(p, IPU_FIELD_ID, 1); - - val = ipu_idmac_read(ipu, IDMAC_CHA_PRI(channel->num)); - val |= 1 << (channel->num % 32); - ipu_idmac_write(ipu, val, IDMAC_CHA_PRI(channel->num)); -}; -EXPORT_SYMBOL_GPL(ipu_cpmem_set_high_priority); - -void ipu_ch_param_write_field(struct ipu_ch_param __iomem *base, u32 wbs, u32 v) -{ - u32 bit = (wbs >> 8) % 160; - u32 size = wbs & 0xff; - u32 word = (wbs >> 8) / 160; - u32 i = bit / 32; - u32 ofs = bit % 32; - u32 mask = (1 << size) - 1; - u32 val; - - pr_debug("%s %d %d %d\n", __func__, word, bit , size); - - val = readl(&base->word[word].data[i]); - val &= ~(mask << ofs); - val |= v << ofs; - writel(val, &base->word[word].data[i]); - - if ((bit + size - 1) / 32 > i) { - val = readl(&base->word[word].data[i + 1]); - val &= ~(mask >> (ofs ? (32 - ofs) : 0)); - val |= v >> (ofs ? (32 - ofs) : 0); - writel(val, &base->word[word].data[i + 1]); - } -} -EXPORT_SYMBOL_GPL(ipu_ch_param_write_field); - -u32 ipu_ch_param_read_field(struct ipu_ch_param __iomem *base, u32 wbs) -{ - u32 bit = (wbs >> 8) % 160; - u32 size = wbs & 0xff; - u32 word = (wbs >> 8) / 160; - u32 i = bit / 32; - u32 ofs = bit % 32; - u32 mask = (1 << size) - 1; - u32 val = 0; - - pr_debug("%s %d %d %d\n", __func__, word, bit , size); - - val = (readl(&base->word[word].data[i]) >> ofs) & mask; - - if ((bit + size - 1) / 32 > i) { - u32 tmp; - tmp = readl(&base->word[word].data[i + 1]); - tmp &= mask >> (ofs ? (32 - ofs) : 0); - val |= tmp << (ofs ? (32 - ofs) : 0); - } - - return val; -} -EXPORT_SYMBOL_GPL(ipu_ch_param_read_field); - -int ipu_cpmem_set_format_rgb(struct ipu_ch_param __iomem *p, - const struct ipu_rgb *rgb) -{ - int bpp = 0, npb = 0, ro, go, bo, to; - - ro = rgb->bits_per_pixel - rgb->red.length - rgb->red.offset; - go = rgb->bits_per_pixel - rgb->green.length - rgb->green.offset; - bo = rgb->bits_per_pixel - rgb->blue.length - rgb->blue.offset; - to = rgb->bits_per_pixel - rgb->transp.length - rgb->transp.offset; - - ipu_ch_param_write_field(p, IPU_FIELD_WID0, rgb->red.length - 1); - ipu_ch_param_write_field(p, IPU_FIELD_OFS0, ro); - ipu_ch_param_write_field(p, IPU_FIELD_WID1, rgb->green.length - 1); - ipu_ch_param_write_field(p, IPU_FIELD_OFS1, go); - ipu_ch_param_write_field(p, IPU_FIELD_WID2, rgb->blue.length - 1); - ipu_ch_param_write_field(p, IPU_FIELD_OFS2, bo); - - if (rgb->transp.length) { - ipu_ch_param_write_field(p, IPU_FIELD_WID3, - rgb->transp.length - 1); - ipu_ch_param_write_field(p, IPU_FIELD_OFS3, to); - } else { - ipu_ch_param_write_field(p, IPU_FIELD_WID3, 7); - ipu_ch_param_write_field(p, IPU_FIELD_OFS3, - rgb->bits_per_pixel); - } - - switch (rgb->bits_per_pixel) { - case 32: - bpp = 0; - npb = 15; - break; - case 24: - bpp = 1; - npb = 19; - break; - case 16: - bpp = 3; - npb = 31; - break; - case 8: - bpp = 5; - npb = 63; - break; - default: - return -EINVAL; - } - ipu_ch_param_write_field(p, IPU_FIELD_BPP, bpp); - ipu_ch_param_write_field(p, IPU_FIELD_NPB, npb); - ipu_ch_param_write_field(p, IPU_FIELD_PFS, 7); /* rgb mode */ - - return 0; -} -EXPORT_SYMBOL_GPL(ipu_cpmem_set_format_rgb); - -int ipu_cpmem_set_format_passthrough(struct ipu_ch_param __iomem *p, - int width) -{ - int bpp = 0, npb = 0; - - switch (width) { - case 32: - bpp = 0; - npb = 15; - break; - case 24: - bpp = 1; - npb = 19; - break; - case 16: - bpp = 3; - npb = 31; - break; - case 8: - bpp = 5; - npb = 63; - break; - default: - return -EINVAL; - } - - ipu_ch_param_write_field(p, IPU_FIELD_BPP, bpp); - ipu_ch_param_write_field(p, IPU_FIELD_NPB, npb); - ipu_ch_param_write_field(p, IPU_FIELD_PFS, 6); /* raw mode */ - - return 0; -} -EXPORT_SYMBOL_GPL(ipu_cpmem_set_format_passthrough); - -void ipu_cpmem_set_yuv_interleaved(struct ipu_ch_param __iomem *p, - u32 pixel_format) -{ - switch (pixel_format) { - case V4L2_PIX_FMT_UYVY: - ipu_ch_param_write_field(p, IPU_FIELD_BPP, 3); /* bits/pixel */ - ipu_ch_param_write_field(p, IPU_FIELD_PFS, 0xA); /* pix format */ - ipu_ch_param_write_field(p, IPU_FIELD_NPB, 31); /* burst size */ - break; - case V4L2_PIX_FMT_YUYV: - ipu_ch_param_write_field(p, IPU_FIELD_BPP, 3); /* bits/pixel */ - ipu_ch_param_write_field(p, IPU_FIELD_PFS, 0x8); /* pix format */ - ipu_ch_param_write_field(p, IPU_FIELD_NPB, 31); /* burst size */ - break; - } -} -EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_interleaved); - -void ipu_cpmem_set_yuv_planar_full(struct ipu_ch_param __iomem *p, - u32 pixel_format, int stride, int u_offset, int v_offset) -{ - switch (pixel_format) { - case V4L2_PIX_FMT_YUV420: - ipu_ch_param_write_field(p, IPU_FIELD_SLUV, (stride / 2) - 1); - ipu_ch_param_write_field(p, IPU_FIELD_UBO, u_offset / 8); - ipu_ch_param_write_field(p, IPU_FIELD_VBO, v_offset / 8); - break; - case V4L2_PIX_FMT_YVU420: - ipu_ch_param_write_field(p, IPU_FIELD_SLUV, (stride / 2) - 1); - ipu_ch_param_write_field(p, IPU_FIELD_UBO, v_offset / 8); - ipu_ch_param_write_field(p, IPU_FIELD_VBO, u_offset / 8); - break; - } -} -EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_planar_full); - -void ipu_cpmem_set_yuv_planar(struct ipu_ch_param __iomem *p, u32 pixel_format, - int stride, int height) -{ - int u_offset, v_offset; - int uv_stride = 0; - - switch (pixel_format) { - case V4L2_PIX_FMT_YUV420: - case V4L2_PIX_FMT_YVU420: - uv_stride = stride / 2; - u_offset = stride * height; - v_offset = u_offset + (uv_stride * height / 2); - ipu_cpmem_set_yuv_planar_full(p, pixel_format, stride, - u_offset, v_offset); - break; - } -} -EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_planar); - -static const struct ipu_rgb def_rgb_32 = { - .red = { .offset = 16, .length = 8, }, - .green = { .offset = 8, .length = 8, }, - .blue = { .offset = 0, .length = 8, }, - .transp = { .offset = 24, .length = 8, }, - .bits_per_pixel = 32, -}; - -static const struct ipu_rgb def_bgr_32 = { - .red = { .offset = 0, .length = 8, }, - .green = { .offset = 8, .length = 8, }, - .blue = { .offset = 16, .length = 8, }, - .transp = { .offset = 24, .length = 8, }, - .bits_per_pixel = 32, -}; - -static const struct ipu_rgb def_rgb_24 = { - .red = { .offset = 16, .length = 8, }, - .green = { .offset = 8, .length = 8, }, - .blue = { .offset = 0, .length = 8, }, - .transp = { .offset = 0, .length = 0, }, - .bits_per_pixel = 24, -}; - -static const struct ipu_rgb def_bgr_24 = { - .red = { .offset = 0, .length = 8, }, - .green = { .offset = 8, .length = 8, }, - .blue = { .offset = 16, .length = 8, }, - .transp = { .offset = 0, .length = 0, }, - .bits_per_pixel = 24, -}; - -static const struct ipu_rgb def_rgb_16 = { - .red = { .offset = 11, .length = 5, }, - .green = { .offset = 5, .length = 6, }, - .blue = { .offset = 0, .length = 5, }, - .transp = { .offset = 0, .length = 0, }, - .bits_per_pixel = 16, -}; - -static const struct ipu_rgb def_bgr_16 = { - .red = { .offset = 0, .length = 5, }, - .green = { .offset = 5, .length = 6, }, - .blue = { .offset = 11, .length = 5, }, - .transp = { .offset = 0, .length = 0, }, - .bits_per_pixel = 16, -}; - -#define Y_OFFSET(pix, x, y) ((x) + pix->width * (y)) -#define U_OFFSET(pix, x, y) ((pix->width * pix->height) + \ - (pix->width * (y) / 4) + (x) / 2) -#define V_OFFSET(pix, x, y) ((pix->width * pix->height) + \ - (pix->width * pix->height / 4) + \ - (pix->width * (y) / 4) + (x) / 2) - -int ipu_cpmem_set_fmt(struct ipu_ch_param __iomem *cpmem, u32 drm_fourcc) -{ - switch (drm_fourcc) { - case DRM_FORMAT_YUV420: - case DRM_FORMAT_YVU420: - /* pix format */ - ipu_ch_param_write_field(cpmem, IPU_FIELD_PFS, 2); - /* burst size */ - ipu_ch_param_write_field(cpmem, IPU_FIELD_NPB, 63); - break; - case DRM_FORMAT_UYVY: - /* bits/pixel */ - ipu_ch_param_write_field(cpmem, IPU_FIELD_BPP, 3); - /* pix format */ - ipu_ch_param_write_field(cpmem, IPU_FIELD_PFS, 0xA); - /* burst size */ - ipu_ch_param_write_field(cpmem, IPU_FIELD_NPB, 31); - break; - case DRM_FORMAT_YUYV: - /* bits/pixel */ - ipu_ch_param_write_field(cpmem, IPU_FIELD_BPP, 3); - /* pix format */ - ipu_ch_param_write_field(cpmem, IPU_FIELD_PFS, 0x8); - /* burst size */ - ipu_ch_param_write_field(cpmem, IPU_FIELD_NPB, 31); - break; - case DRM_FORMAT_ABGR8888: - case DRM_FORMAT_XBGR8888: - ipu_cpmem_set_format_rgb(cpmem, &def_bgr_32); - break; - case DRM_FORMAT_ARGB8888: - case DRM_FORMAT_XRGB8888: - ipu_cpmem_set_format_rgb(cpmem, &def_rgb_32); - break; - case DRM_FORMAT_BGR888: - ipu_cpmem_set_format_rgb(cpmem, &def_bgr_24); - break; - case DRM_FORMAT_RGB888: - ipu_cpmem_set_format_rgb(cpmem, &def_rgb_24); - break; - case DRM_FORMAT_RGB565: - ipu_cpmem_set_format_rgb(cpmem, &def_rgb_16); - break; - case DRM_FORMAT_BGR565: - ipu_cpmem_set_format_rgb(cpmem, &def_bgr_16); - break; - default: - return -EINVAL; - } - - return 0; -} -EXPORT_SYMBOL_GPL(ipu_cpmem_set_fmt); - -/* - * The V4L2 spec defines packed RGB formats in memory byte order, which from - * point of view of the IPU corresponds to little-endian words with the first - * component in the least significant bits. - * The DRM pixel formats and IPU internal representation are ordered the other - * way around, with the first named component ordered at the most significant - * bits. Further, V4L2 formats are not well defined: - * http://linuxtv.org/downloads/v4l-dvb-apis/packed-rgb.html - * We choose the interpretation which matches GStreamer behavior. - */ -static int v4l2_pix_fmt_to_drm_fourcc(u32 pixelformat) -{ - switch (pixelformat) { - case V4L2_PIX_FMT_RGB565: - /* - * Here we choose the 'corrected' interpretation of RGBP, a - * little-endian 16-bit word with the red component at the most - * significant bits: - * g[2:0]b[4:0] r[4:0]g[5:3] <=> [16:0] R:G:B - */ - return DRM_FORMAT_RGB565; - case V4L2_PIX_FMT_BGR24: - /* B G R <=> [24:0] R:G:B */ - return DRM_FORMAT_RGB888; - case V4L2_PIX_FMT_RGB24: - /* R G B <=> [24:0] B:G:R */ - return DRM_FORMAT_BGR888; - case V4L2_PIX_FMT_BGR32: - /* B G R A <=> [32:0] A:B:G:R */ - return DRM_FORMAT_XRGB8888; - case V4L2_PIX_FMT_RGB32: - /* R G B A <=> [32:0] A:B:G:R */ - return DRM_FORMAT_XBGR8888; - case V4L2_PIX_FMT_UYVY: - return DRM_FORMAT_UYVY; - case V4L2_PIX_FMT_YUYV: - return DRM_FORMAT_YUYV; - case V4L2_PIX_FMT_YUV420: - return DRM_FORMAT_YUV420; - case V4L2_PIX_FMT_YVU420: - return DRM_FORMAT_YVU420; - } - - return -EINVAL; -} - enum ipu_color_space ipu_drm_fourcc_to_colorspace(u32 drm_fourcc) { switch (drm_fourcc) { @@ -465,66 +81,6 @@ enum ipu_color_space ipu_drm_fourcc_to_colorspace(u32 drm_fourcc) } EXPORT_SYMBOL_GPL(ipu_drm_fourcc_to_colorspace); -int ipu_cpmem_set_image(struct ipu_ch_param __iomem *cpmem, - struct ipu_image *image) -{ - struct v4l2_pix_format *pix = &image->pix; - int y_offset, u_offset, v_offset; - - pr_debug("%s: resolution: %dx%d stride: %d\n", - __func__, pix->width, pix->height, - pix->bytesperline); - - ipu_cpmem_set_resolution(cpmem, image->rect.width, - image->rect.height); - ipu_cpmem_set_stride(cpmem, pix->bytesperline); - - ipu_cpmem_set_fmt(cpmem, v4l2_pix_fmt_to_drm_fourcc(pix->pixelformat)); - - switch (pix->pixelformat) { - case V4L2_PIX_FMT_YUV420: - case V4L2_PIX_FMT_YVU420: - y_offset = Y_OFFSET(pix, image->rect.left, image->rect.top); - u_offset = U_OFFSET(pix, image->rect.left, - image->rect.top) - y_offset; - v_offset = V_OFFSET(pix, image->rect.left, - image->rect.top) - y_offset; - - ipu_cpmem_set_yuv_planar_full(cpmem, pix->pixelformat, - pix->bytesperline, u_offset, v_offset); - ipu_cpmem_set_buffer(cpmem, 0, image->phys + y_offset); - break; - case V4L2_PIX_FMT_UYVY: - case V4L2_PIX_FMT_YUYV: - ipu_cpmem_set_buffer(cpmem, 0, image->phys + - image->rect.left * 2 + - image->rect.top * image->pix.bytesperline); - break; - case V4L2_PIX_FMT_RGB32: - case V4L2_PIX_FMT_BGR32: - ipu_cpmem_set_buffer(cpmem, 0, image->phys + - image->rect.left * 4 + - image->rect.top * image->pix.bytesperline); - break; - case V4L2_PIX_FMT_RGB565: - ipu_cpmem_set_buffer(cpmem, 0, image->phys + - image->rect.left * 2 + - image->rect.top * image->pix.bytesperline); - break; - case V4L2_PIX_FMT_RGB24: - case V4L2_PIX_FMT_BGR24: - ipu_cpmem_set_buffer(cpmem, 0, image->phys + - image->rect.left * 3 + - image->rect.top * image->pix.bytesperline); - break; - default: - return -EINVAL; - } - - return 0; -} -EXPORT_SYMBOL_GPL(ipu_cpmem_set_image); - enum ipu_color_space ipu_pixelformat_to_colorspace(u32 pixelformat) { switch (pixelformat) { @@ -895,6 +451,12 @@ static int ipu_submodules_init(struct ipu_soc *ipu, struct device *dev = &pdev->dev; const struct ipu_devtype *devtype = ipu->devtype; + ret = ipu_cpmem_init(ipu, dev, ipu_base + devtype->cpmem_ofs); + if (ret) { + unit = "cpmem"; + goto err_cpmem; + } + ret = ipu_di_init(ipu, dev, 0, ipu_base + devtype->disp0_ofs, IPU_CONF_DI0_EN, ipu_clk); if (ret) { @@ -949,6 +511,8 @@ err_dc: err_di_1: ipu_di_exit(ipu, 0); err_di_0: + ipu_cpmem_exit(ipu); +err_cpmem: dev_err(&pdev->dev, "init %s failed with %d\n", unit, ret); return ret; } @@ -1025,6 +589,7 @@ static void ipu_submodules_exit(struct ipu_soc *ipu) ipu_dc_exit(ipu); ipu_di_exit(ipu, 1); ipu_di_exit(ipu, 0); + ipu_cpmem_exit(ipu); } static int platform_remove_devices_fn(struct device *dev, void *unused) @@ -1265,10 +830,8 @@ static int ipu_probe(struct platform_device *pdev) ipu->idmac_reg = devm_ioremap(&pdev->dev, ipu_base + devtype->cm_ofs + IPU_CM_IDMAC_REG_OFS, PAGE_SIZE); - ipu->cpmem_base = devm_ioremap(&pdev->dev, - ipu_base + devtype->cpmem_ofs, PAGE_SIZE); - if (!ipu->cm_reg || !ipu->idmac_reg || !ipu->cpmem_base) + if (!ipu->cm_reg || !ipu->idmac_reg) return -ENOMEM; ipu->clk = devm_clk_get(&pdev->dev, "bus"); diff --git a/drivers/gpu/ipu-v3/ipu-cpmem.c b/drivers/gpu/ipu-v3/ipu-cpmem.c new file mode 100644 index 000000000000..7adfa78a48bc --- /dev/null +++ b/drivers/gpu/ipu-v3/ipu-cpmem.c @@ -0,0 +1,597 @@ +/* + * Copyright (C) 2012 Mentor Graphics Inc. + * Copyright 2005-2012 Freescale Semiconductor, Inc. All Rights Reserved. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#include <linux/types.h> +#include <linux/bitrev.h> +#include <linux/io.h> +#include <drm/drm_fourcc.h> +#include "ipu-prv.h" + +struct ipu_cpmem_word { + u32 data[5]; + u32 res[3]; +}; + +struct ipu_ch_param { + struct ipu_cpmem_word word[2]; +}; + +struct ipu_cpmem { + struct ipu_ch_param __iomem *base; + u32 module; + spinlock_t lock; + int use_count; + struct ipu_soc *ipu; +}; + +#define IPU_CPMEM_WORD(word, ofs, size) ((((word) * 160 + (ofs)) << 8) | (size)) + +#define IPU_FIELD_UBO IPU_CPMEM_WORD(0, 46, 22) +#define IPU_FIELD_VBO IPU_CPMEM_WORD(0, 68, 22) +#define IPU_FIELD_IOX IPU_CPMEM_WORD(0, 90, 4) +#define IPU_FIELD_RDRW IPU_CPMEM_WORD(0, 94, 1) +#define IPU_FIELD_SO IPU_CPMEM_WORD(0, 113, 1) +#define IPU_FIELD_SLY IPU_CPMEM_WORD(1, 102, 14) +#define IPU_FIELD_SLUV IPU_CPMEM_WORD(1, 128, 14) + +#define IPU_FIELD_XV IPU_CPMEM_WORD(0, 0, 10) +#define IPU_FIELD_YV IPU_CPMEM_WORD(0, 10, 9) +#define IPU_FIELD_XB IPU_CPMEM_WORD(0, 19, 13) +#define IPU_FIELD_YB IPU_CPMEM_WORD(0, 32, 12) +#define IPU_FIELD_NSB_B IPU_CPMEM_WORD(0, 44, 1) +#define IPU_FIELD_CF IPU_CPMEM_WORD(0, 45, 1) +#define IPU_FIELD_SX IPU_CPMEM_WORD(0, 46, 12) +#define IPU_FIELD_SY IPU_CPMEM_WORD(0, 58, 11) +#define IPU_FIELD_NS IPU_CPMEM_WORD(0, 69, 10) +#define IPU_FIELD_SDX IPU_CPMEM_WORD(0, 79, 7) +#define IPU_FIELD_SM IPU_CPMEM_WORD(0, 86, 10) +#define IPU_FIELD_SCC IPU_CPMEM_WORD(0, 96, 1) +#define IPU_FIELD_SCE IPU_CPMEM_WORD(0, 97, 1) +#define IPU_FIELD_SDY IPU_CPMEM_WORD(0, 98, 7) +#define IPU_FIELD_SDRX IPU_CPMEM_WORD(0, 105, 1) +#define IPU_FIELD_SDRY IPU_CPMEM_WORD(0, 106, 1) +#define IPU_FIELD_BPP IPU_CPMEM_WORD(0, 107, 3) +#define IPU_FIELD_DEC_SEL IPU_CPMEM_WORD(0, 110, 2) +#define IPU_FIELD_DIM IPU_CPMEM_WORD(0, 112, 1) +#define IPU_FIELD_BNDM IPU_CPMEM_WORD(0, 114, 3) +#define IPU_FIELD_BM IPU_CPMEM_WORD(0, 117, 2) +#define IPU_FIELD_ROT IPU_CPMEM_WORD(0, 119, 1) +#define IPU_FIELD_HF IPU_CPMEM_WORD(0, 120, 1) +#define IPU_FIELD_VF IPU_CPMEM_WORD(0, 121, 1) +#define IPU_FIELD_THE IPU_CPMEM_WORD(0, 122, 1) +#define IPU_FIELD_CAP IPU_CPMEM_WORD(0, 123, 1) +#define IPU_FIELD_CAE IPU_CPMEM_WORD(0, 124, 1) +#define IPU_FIELD_FW IPU_CPMEM_WORD(0, 125, 13) +#define IPU_FIELD_FH IPU_CPMEM_WORD(0, 138, 12) +#define IPU_FIELD_EBA0 IPU_CPMEM_WORD(1, 0, 29) +#define IPU_FIELD_EBA1 IPU_CPMEM_WORD(1, 29, 29) +#define IPU_FIELD_ILO IPU_CPMEM_WORD(1, 58, 20) +#define IPU_FIELD_NPB IPU_CPMEM_WORD(1, 78, 7) +#define IPU_FIELD_PFS IPU_CPMEM_WORD(1, 85, 4) +#define IPU_FIELD_ALU IPU_CPMEM_WORD(1, 89, 1) +#define IPU_FIELD_ALBM IPU_CPMEM_WORD(1, 90, 3) +#define IPU_FIELD_ID IPU_CPMEM_WORD(1, 93, 2) +#define IPU_FIELD_TH IPU_CPMEM_WORD(1, 95, 7) +#define IPU_FIELD_SL IPU_CPMEM_WORD(1, 102, 14) +#define IPU_FIELD_WID0 IPU_CPMEM_WORD(1, 116, 3) +#define IPU_FIELD_WID1 IPU_CPMEM_WORD(1, 119, 3) +#define IPU_FIELD_WID2 IPU_CPMEM_WORD(1, 122, 3) +#define IPU_FIELD_WID3 IPU_CPMEM_WORD(1, 125, 3) +#define IPU_FIELD_OFS0 IPU_CPMEM_WORD(1, 128, 5) +#define IPU_FIELD_OFS1 IPU_CPMEM_WORD(1, 133, 5) +#define IPU_FIELD_OFS2 IPU_CPMEM_WORD(1, 138, 5) +#define IPU_FIELD_OFS3 IPU_CPMEM_WORD(1, 143, 5) +#define IPU_FIELD_SXYS IPU_CPMEM_WORD(1, 148, 1) +#define IPU_FIELD_CRE IPU_CPMEM_WORD(1, 149, 1) +#define IPU_FIELD_DEC_SEL2 IPU_CPMEM_WORD(1, 150, 1) + +static inline struct ipu_ch_param __iomem * +ipu_get_cpmem(struct ipuv3_channel *ch) +{ + struct ipu_cpmem *cpmem = ch->ipu->cpmem_priv; + + return cpmem->base + ch->num; +} + +static void ipu_ch_param_write_field(struct ipuv3_channel *ch, u32 wbs, u32 v) +{ + struct ipu_ch_param __iomem *base = ipu_get_cpmem(ch); + u32 bit = (wbs >> 8) % 160; + u32 size = wbs & 0xff; + u32 word = (wbs >> 8) / 160; + u32 i = bit / 32; + u32 ofs = bit % 32; + u32 mask = (1 << size) - 1; + u32 val; + + pr_debug("%s %d %d %d\n", __func__, word, bit , size); + + val = readl(&base->word[word].data[i]); + val &= ~(mask << ofs); + val |= v << ofs; + writel(val, &base->word[word].data[i]); + + if ((bit + size - 1) / 32 > i) { + val = readl(&base->word[word].data[i + 1]); + val &= ~(mask >> (ofs ? (32 - ofs) : 0)); + val |= v >> (ofs ? (32 - ofs) : 0); + writel(val, &base->word[word].data[i + 1]); + } +} + +static u32 ipu_ch_param_read_field(struct ipuv3_channel *ch, u32 wbs) +{ + struct ipu_ch_param __iomem *base = ipu_get_cpmem(ch); + u32 bit = (wbs >> 8) % 160; + u32 size = wbs & 0xff; + u32 word = (wbs >> 8) / 160; + u32 i = bit / 32; + u32 ofs = bit % 32; + u32 mask = (1 << size) - 1; + u32 val = 0; + + pr_debug("%s %d %d %d\n", __func__, word, bit , size); + + val = (readl(&base->word[word].data[i]) >> ofs) & mask; + + if ((bit + size - 1) / 32 > i) { + u32 tmp; + + tmp = readl(&base->word[word].data[i + 1]); + tmp &= mask >> (ofs ? (32 - ofs) : 0); + val |= tmp << (ofs ? (32 - ofs) : 0); + } + + return val; +} + +/* + * The V4L2 spec defines packed RGB formats in memory byte order, which from + * point of view of the IPU corresponds to little-endian words with the first + * component in the least significant bits. + * The DRM pixel formats and IPU internal representation are ordered the other + * way around, with the first named component ordered at the most significant + * bits. Further, V4L2 formats are not well defined: + * http://linuxtv.org/downloads/v4l-dvb-apis/packed-rgb.html + * We choose the interpretation which matches GStreamer behavior. + */ +static int v4l2_pix_fmt_to_drm_fourcc(u32 pixelformat) +{ + switch (pixelformat) { + case V4L2_PIX_FMT_RGB565: + /* + * Here we choose the 'corrected' interpretation of RGBP, a + * little-endian 16-bit word with the red component at the most + * significant bits: + * g[2:0]b[4:0] r[4:0]g[5:3] <=> [16:0] R:G:B + */ + return DRM_FORMAT_RGB565; + case V4L2_PIX_FMT_BGR24: + /* B G R <=> [24:0] R:G:B */ + return DRM_FORMAT_RGB888; + case V4L2_PIX_FMT_RGB24: + /* R G B <=> [24:0] B:G:R */ + return DRM_FORMAT_BGR888; + case V4L2_PIX_FMT_BGR32: + /* B G R A <=> [32:0] A:B:G:R */ + return DRM_FORMAT_XRGB8888; + case V4L2_PIX_FMT_RGB32: + /* R G B A <=> [32:0] A:B:G:R */ + return DRM_FORMAT_XBGR8888; + case V4L2_PIX_FMT_UYVY: + return DRM_FORMAT_UYVY; + case V4L2_PIX_FMT_YUYV: + return DRM_FORMAT_YUYV; + case V4L2_PIX_FMT_YUV420: + return DRM_FORMAT_YUV420; + case V4L2_PIX_FMT_YVU420: + return DRM_FORMAT_YVU420; + } + + return -EINVAL; +} + +void ipu_cpmem_zero(struct ipuv3_channel *ch) +{ + struct ipu_ch_param __iomem *p = ipu_get_cpmem(ch); + void __iomem *base = p; + int i; + + for (i = 0; i < sizeof(*p) / sizeof(u32); i++) + writel(0, base + i * sizeof(u32)); +} +EXPORT_SYMBOL_GPL(ipu_cpmem_zero); + +void ipu_cpmem_set_resolution(struct ipuv3_channel *ch, int xres, int yres) +{ + ipu_ch_param_write_field(ch, IPU_FIELD_FW, xres - 1); + ipu_ch_param_write_field(ch, IPU_FIELD_FH, yres - 1); +} +EXPORT_SYMBOL_GPL(ipu_cpmem_set_resolution); + +void ipu_cpmem_set_stride(struct ipuv3_channel *ch, int stride) +{ + ipu_ch_param_write_field(ch, IPU_FIELD_SLY, stride - 1); +} +EXPORT_SYMBOL_GPL(ipu_cpmem_set_stride); + +void ipu_cpmem_set_high_priority(struct ipuv3_channel *ch) +{ + struct ipu_soc *ipu = ch->ipu; + u32 val; + + if (ipu->ipu_type == IPUV3EX) + ipu_ch_param_write_field(ch, IPU_FIELD_ID, 1); + + val = ipu_idmac_read(ipu, IDMAC_CHA_PRI(ch->num)); + val |= 1 << (ch->num % 32); + ipu_idmac_write(ipu, val, IDMAC_CHA_PRI(ch->num)); +}; +EXPORT_SYMBOL_GPL(ipu_cpmem_set_high_priority); + +void ipu_cpmem_set_buffer(struct ipuv3_channel *ch, int bufnum, dma_addr_t buf) +{ + if (bufnum) + ipu_ch_param_write_field(ch, IPU_FIELD_EBA1, buf >> 3); + else + ipu_ch_param_write_field(ch, IPU_FIELD_EBA0, buf >> 3); +} +EXPORT_SYMBOL_GPL(ipu_cpmem_set_buffer); + +void ipu_cpmem_interlaced_scan(struct ipuv3_channel *ch, int stride) +{ + ipu_ch_param_write_field(ch, IPU_FIELD_SO, 1); + ipu_ch_param_write_field(ch, IPU_FIELD_ILO, stride / 8); + ipu_ch_param_write_field(ch, IPU_FIELD_SLY, (stride * 2) - 1); +}; +EXPORT_SYMBOL_GPL(ipu_cpmem_interlaced_scan); + +void ipu_cpmem_set_burstsize(struct ipuv3_channel *ch, int burstsize) +{ + ipu_ch_param_write_field(ch, IPU_FIELD_NPB, burstsize - 1); +}; +EXPORT_SYMBOL_GPL(ipu_cpmem_set_burstsize); + +int ipu_cpmem_set_format_rgb(struct ipuv3_channel *ch, + const struct ipu_rgb *rgb) +{ + int bpp = 0, npb = 0, ro, go, bo, to; + + ro = rgb->bits_per_pixel - rgb->red.length - rgb->red.offset; + go = rgb->bits_per_pixel - rgb->green.length - rgb->green.offset; + bo = rgb->bits_per_pixel - rgb->blue.length - rgb->blue.offset; + to = rgb->bits_per_pixel - rgb->transp.length - rgb->transp.offset; + + ipu_ch_param_write_field(ch, IPU_FIELD_WID0, rgb->red.length - 1); + ipu_ch_param_write_field(ch, IPU_FIELD_OFS0, ro); + ipu_ch_param_write_field(ch, IPU_FIELD_WID1, rgb->green.length - 1); + ipu_ch_param_write_field(ch, IPU_FIELD_OFS1, go); + ipu_ch_param_write_field(ch, IPU_FIELD_WID2, rgb->blue.length - 1); + ipu_ch_param_write_field(ch, IPU_FIELD_OFS2, bo); + + if (rgb->transp.length) { + ipu_ch_param_write_field(ch, IPU_FIELD_WID3, + rgb->transp.length - 1); + ipu_ch_param_write_field(ch, IPU_FIELD_OFS3, to); + } else { + ipu_ch_param_write_field(ch, IPU_FIELD_WID3, 7); + ipu_ch_param_write_field(ch, IPU_FIELD_OFS3, + rgb->bits_per_pixel); + } + + switch (rgb->bits_per_pixel) { + case 32: + bpp = 0; + npb = 15; + break; + case 24: + bpp = 1; + npb = 19; + break; + case 16: + bpp = 3; + npb = 31; + break; + case 8: + bpp = 5; + npb = 63; + break; + default: + return -EINVAL; + } + ipu_ch_param_write_field(ch, IPU_FIELD_BPP, bpp); + ipu_ch_param_write_field(ch, IPU_FIELD_NPB, npb); + ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 7); /* rgb mode */ + + return 0; +} +EXPORT_SYMBOL_GPL(ipu_cpmem_set_format_rgb); + +int ipu_cpmem_set_format_passthrough(struct ipuv3_channel *ch, int width) +{ + int bpp = 0, npb = 0; + + switch (width) { + case 32: + bpp = 0; + npb = 15; + break; + case 24: + bpp = 1; + npb = 19; + break; + case 16: + bpp = 3; + npb = 31; + break; + case 8: + bpp = 5; + npb = 63; + break; + default: + return -EINVAL; + } + + ipu_ch_param_write_field(ch, IPU_FIELD_BPP, bpp); + ipu_ch_param_write_field(ch, IPU_FIELD_NPB, npb); + ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 6); /* raw mode */ + + return 0; +} +EXPORT_SYMBOL_GPL(ipu_cpmem_set_format_passthrough); + +void ipu_cpmem_set_yuv_interleaved(struct ipuv3_channel *ch, u32 pixel_format) +{ + switch (pixel_format) { + case V4L2_PIX_FMT_UYVY: + ipu_ch_param_write_field(ch, IPU_FIELD_BPP, 3); /* bits/pixel */ + ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0xA);/* pix fmt */ + ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);/* burst size */ + break; + case V4L2_PIX_FMT_YUYV: + ipu_ch_param_write_field(ch, IPU_FIELD_BPP, 3); /* bits/pixel */ + ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0x8);/* pix fmt */ + ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31);/* burst size */ + break; + } +} +EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_interleaved); + +void ipu_cpmem_set_yuv_planar_full(struct ipuv3_channel *ch, + u32 pixel_format, int stride, + int u_offset, int v_offset) +{ + switch (pixel_format) { + case V4L2_PIX_FMT_YUV420: + ipu_ch_param_write_field(ch, IPU_FIELD_SLUV, (stride / 2) - 1); + ipu_ch_param_write_field(ch, IPU_FIELD_UBO, u_offset / 8); + ipu_ch_param_write_field(ch, IPU_FIELD_VBO, v_offset / 8); + break; + case V4L2_PIX_FMT_YVU420: + ipu_ch_param_write_field(ch, IPU_FIELD_SLUV, (stride / 2) - 1); + ipu_ch_param_write_field(ch, IPU_FIELD_UBO, v_offset / 8); + ipu_ch_param_write_field(ch, IPU_FIELD_VBO, u_offset / 8); + break; + } +} +EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_planar_full); + +void ipu_cpmem_set_yuv_planar(struct ipuv3_channel *ch, + u32 pixel_format, int stride, int height) +{ + int u_offset, v_offset; + int uv_stride = 0; + + switch (pixel_format) { + case V4L2_PIX_FMT_YUV420: + case V4L2_PIX_FMT_YVU420: + uv_stride = stride / 2; + u_offset = stride * height; + v_offset = u_offset + (uv_stride * height / 2); + ipu_cpmem_set_yuv_planar_full(ch, pixel_format, stride, + u_offset, v_offset); + break; + } +} +EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_planar); + +static const struct ipu_rgb def_rgb_32 = { + .red = { .offset = 16, .length = 8, }, + .green = { .offset = 8, .length = 8, }, + .blue = { .offset = 0, .length = 8, }, + .transp = { .offset = 24, .length = 8, }, + .bits_per_pixel = 32, +}; + +static const struct ipu_rgb def_bgr_32 = { + .red = { .offset = 0, .length = 8, }, + .green = { .offset = 8, .length = 8, }, + .blue = { .offset = 16, .length = 8, }, + .transp = { .offset = 24, .length = 8, }, + .bits_per_pixel = 32, +}; + +static const struct ipu_rgb def_rgb_24 = { + .red = { .offset = 16, .length = 8, }, + .green = { .offset = 8, .length = 8, }, + .blue = { .offset = 0, .length = 8, }, + .transp = { .offset = 0, .length = 0, }, + .bits_per_pixel = 24, +}; + +static const struct ipu_rgb def_bgr_24 = { + .red = { .offset = 0, .length = 8, }, + .green = { .offset = 8, .length = 8, }, + .blue = { .offset = 16, .length = 8, }, + .transp = { .offset = 0, .length = 0, }, + .bits_per_pixel = 24, +}; + +static const struct ipu_rgb def_rgb_16 = { + .red = { .offset = 11, .length = 5, }, + .green = { .offset = 5, .length = 6, }, + .blue = { .offset = 0, .length = 5, }, + .transp = { .offset = 0, .length = 0, }, + .bits_per_pixel = 16, +}; + +static const struct ipu_rgb def_bgr_16 = { + .red = { .offset = 0, .length = 5, }, + .green = { .offset = 5, .length = 6, }, + .blue = { .offset = 11, .length = 5, }, + .transp = { .offset = 0, .length = 0, }, + .bits_per_pixel = 16, +}; + +#define Y_OFFSET(pix, x, y) ((x) + pix->width * (y)) +#define U_OFFSET(pix, x, y) ((pix->width * pix->height) + \ + (pix->width * (y) / 4) + (x) / 2) +#define V_OFFSET(pix, x, y) ((pix->width * pix->height) + \ + (pix->width * pix->height / 4) + \ + (pix->width * (y) / 4) + (x) / 2) + +int ipu_cpmem_set_fmt(struct ipuv3_channel *ch, u32 drm_fourcc) +{ + switch (drm_fourcc) { + case DRM_FORMAT_YUV420: + case DRM_FORMAT_YVU420: + /* pix format */ + ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 2); + /* burst size */ + ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31); + break; + case DRM_FORMAT_UYVY: + /* bits/pixel */ + ipu_ch_param_write_field(ch, IPU_FIELD_BPP, 3); + /* pix format */ + ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0xA); + /* burst size */ + ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31); + break; + case DRM_FORMAT_YUYV: + /* bits/pixel */ + ipu_ch_param_write_field(ch, IPU_FIELD_BPP, 3); + /* pix format */ + ipu_ch_param_write_field(ch, IPU_FIELD_PFS, 0x8); + /* burst size */ + ipu_ch_param_write_field(ch, IPU_FIELD_NPB, 31); + break; + case DRM_FORMAT_ABGR8888: + case DRM_FORMAT_XBGR8888: + ipu_cpmem_set_format_rgb(ch, &def_bgr_32); + break; + case DRM_FORMAT_ARGB8888: + case DRM_FORMAT_XRGB8888: + ipu_cpmem_set_format_rgb(ch, &def_rgb_32); + break; + case DRM_FORMAT_BGR888: + ipu_cpmem_set_format_rgb(ch, &def_bgr_24); + break; + case DRM_FORMAT_RGB888: + ipu_cpmem_set_format_rgb(ch, &def_rgb_24); + break; + case DRM_FORMAT_RGB565: + ipu_cpmem_set_format_rgb(ch, &def_rgb_16); + break; + case DRM_FORMAT_BGR565: + ipu_cpmem_set_format_rgb(ch, &def_bgr_16); + break; + default: + return -EINVAL; + } + + return 0; +} +EXPORT_SYMBOL_GPL(ipu_cpmem_set_fmt); + +int ipu_cpmem_set_image(struct ipuv3_channel *ch, struct ipu_image *image) +{ + struct v4l2_pix_format *pix = &image->pix; + int y_offset, u_offset, v_offset; + + pr_debug("%s: resolution: %dx%d stride: %d\n", + __func__, pix->width, pix->height, + pix->bytesperline); + + ipu_cpmem_set_resolution(ch, image->rect.width, image->rect.height); + ipu_cpmem_set_stride(ch, pix->bytesperline); + + ipu_cpmem_set_fmt(ch, v4l2_pix_fmt_to_drm_fourcc(pix->pixelformat)); + + switch (pix->pixelformat) { + case V4L2_PIX_FMT_YUV420: + case V4L2_PIX_FMT_YVU420: + y_offset = Y_OFFSET(pix, image->rect.left, image->rect.top); + u_offset = U_OFFSET(pix, image->rect.left, + image->rect.top) - y_offset; + v_offset = V_OFFSET(pix, image->rect.left, + image->rect.top) - y_offset; + + ipu_cpmem_set_yuv_planar_full(ch, pix->pixelformat, + pix->bytesperline, u_offset, v_offset); + ipu_cpmem_set_buffer(ch, 0, image->phys + y_offset); + break; + case V4L2_PIX_FMT_UYVY: + case V4L2_PIX_FMT_YUYV: + ipu_cpmem_set_buffer(ch, 0, image->phys + + image->rect.left * 2 + + image->rect.top * image->pix.bytesperline); + break; + case V4L2_PIX_FMT_RGB32: + case V4L2_PIX_FMT_BGR32: + ipu_cpmem_set_buffer(ch, 0, image->phys + + image->rect.left * 4 + + image->rect.top * image->pix.bytesperline); + break; + case V4L2_PIX_FMT_RGB565: + ipu_cpmem_set_buffer(ch, 0, image->phys + + image->rect.left * 2 + + image->rect.top * image->pix.bytesperline); + break; + case V4L2_PIX_FMT_RGB24: + case V4L2_PIX_FMT_BGR24: + ipu_cpmem_set_buffer(ch, 0, image->phys + + image->rect.left * 3 + + image->rect.top * image->pix.bytesperline); + break; + default: + return -EINVAL; + } + + return 0; +} +EXPORT_SYMBOL_GPL(ipu_cpmem_set_image); + +int ipu_cpmem_init(struct ipu_soc *ipu, struct device *dev, unsigned long base) +{ + struct ipu_cpmem *cpmem; + + cpmem = devm_kzalloc(dev, sizeof(*cpmem), GFP_KERNEL); + if (!cpmem) + return -ENOMEM; + + ipu->cpmem_priv = cpmem; + + spin_lock_init(&cpmem->lock); + cpmem->base = devm_ioremap(dev, base, SZ_128K); + if (!cpmem->base) + return -ENOMEM; + + dev_dbg(dev, "CPMEM base: 0x%08lx remapped to %p\n", + base, cpmem->base); + cpmem->ipu = ipu; + + return 0; +} + +void ipu_cpmem_exit(struct ipu_soc *ipu) +{ +} diff --git a/drivers/gpu/ipu-v3/ipu-prv.h b/drivers/gpu/ipu-v3/ipu-prv.h index c93f50ec04f7..0a7b2adaba39 100644 --- a/drivers/gpu/ipu-v3/ipu-prv.h +++ b/drivers/gpu/ipu-v3/ipu-prv.h @@ -148,6 +148,7 @@ struct ipuv3_channel { struct ipu_soc *ipu; }; +struct ipu_cpmem; struct ipu_dc_priv; struct ipu_dmfc_priv; struct ipu_di; @@ -164,7 +165,6 @@ struct ipu_soc { void __iomem *cm_reg; void __iomem *idmac_reg; - struct ipu_ch_param __iomem *cpmem_base; int usecount; @@ -176,6 +176,7 @@ struct ipu_soc { int irq_err; struct irq_domain *domain; + struct ipu_cpmem *cpmem_priv; struct ipu_dc_priv *dc_priv; struct ipu_dp_priv *dp_priv; struct ipu_dmfc_priv *dmfc_priv; @@ -183,6 +184,17 @@ struct ipu_soc { struct ipu_smfc_priv *smfc_priv; }; +static inline u32 ipu_idmac_read(struct ipu_soc *ipu, unsigned offset) +{ + return readl(ipu->idmac_reg + offset); +} + +static inline void ipu_idmac_write(struct ipu_soc *ipu, u32 value, + unsigned offset) +{ + writel(value, ipu->idmac_reg + offset); +} + void ipu_srm_dp_sync_update(struct ipu_soc *ipu); int ipu_module_enable(struct ipu_soc *ipu, u32 mask); diff --git a/drivers/gpu/vga/vgaarb.c b/drivers/gpu/vga/vgaarb.c index 77711623b973..7bcbf863656e 100644 --- a/drivers/gpu/vga/vgaarb.c +++ b/drivers/gpu/vga/vgaarb.c @@ -400,7 +400,6 @@ int vga_get(struct pci_dev *pdev, unsigned int rsrc, int interruptible) } schedule(); remove_wait_queue(&vga_wait_queue, &wait); - set_current_state(TASK_RUNNING); } return rc; } |