Merge tag 'drm-for-v4.11-less-shouty' of git://people.freedesktop.org/~airlied/linux
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 24 Feb 2017 02:58:18 +0000 (18:58 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 24 Feb 2017 02:58:18 +0000 (18:58 -0800)
Pull drm updates from Dave Airlie:
 "This is the main drm pull request for v4.11.

  Nothing too major, the tinydrm and mmu-less support should make
  writing smaller drivers easier for some of the simpler platforms, and
  there are a bunch of documentation updates.

  Intel grew displayport MST audio support which is hopefully useful to
  people, and FBC is on by default for GEN9+ (so people know where to
  look for regressions). AMDGPU has a lot of fixes that would like new
  firmware files installed for some GPUs.

  Other than that it's pretty scattered all over.

  I may have a follow up pull request as I know BenH has a bunch of AST
  rework and fixes and I'd like to get those in once they've been tested
  by AST, and I've got at least one pull request I'm just trying to get
  the author to fix up.

  Core:
   - drm_mm reworked
   - Connector list locking and iterators
   - Documentation updates
   - Format handling rework
   - MMU-less support for fbdev helpers
   - drm_crtc_from_index helper
   - Core CRC API
   - Remove drm_framebuffer_unregister_private
   - Debugfs cleanup
   - EDID/Infoframe fixes
   - Release callback
   - Tinydrm support (smaller drivers for simple hw)

  panel:
   - Add support for some new simple panels

  i915:
   - FBC by default for gen9+
   - Shared dpll cleanups and docs
   - GEN8 powerdomain cleanup
   - DMC support on GLK
   - DP MST audio support
   - HuC loading support
   - GVT init ordering fixes
   - GVT IOMMU workaround fix

  amdgpu/radeon:
   - Power/clockgating improvements
   - Preliminary SR-IOV support
   - TTM buffer priority and eviction fixes
   - SI DPM quirks removed due to firmware fixes
   - Powerplay improvements
   - VCE/UVD powergating fixes
   - Cleanup SI GFX code to match CI/VI
   - Support for > 2 displays on 3/5 crtc asics
   - SI headless fixes

  nouveau:
   - Rework securre boot code in prep for GP10x secure boot
   - Channel recovery improvements
   - Initial power budget code
   - MMU rework preperation

  vmwgfx:
   - Bunch of fixes and cleanups

  exynos:
   - Runtime PM support for MIC driver
   - Cleanups to use atomic helpers
   - UHD Support for TM2/TM2E boards
   - Trigger mode fix for Rinato board

  etnaviv:
   - Shader performance fix
   - Command stream validator fixes
   - Command buffer suballocator

  rockchip:
   - CDN DisplayPort support
   - IOMMU support for arm64 platform

  imx-drm:
   - Fix i.MX5 TV encoder probing
   - Remove lower fb size limits

  msm:
   - Support for HW cursor on MDP5 devices
   - DSI encoder cleanup
   - GPU DT bindings cleanup

  sti:
   - stih410 cleanups
   - Create fbdev at binding
   - HQVDP fixes
   - Remove stih416 chip functionality
   - DVI/HDMI mode selection fixes
   - FPS statistic reporting

  omapdrm:
   - IRQ code cleanup

  dwi-hdmi bridge:
   - Cleanups and fixes

  adv-bridge:
   - Updates for nexus

  sii8520 bridge:
   - Add interlace mode support
   - Rework HDMI and lots of fixes

  qxl:
   - probing/teardown cleanups

  ZTE drm:
   - HDMI audio via SPDIF interface
   - Video Layer overlay plane support
   - Add TV encoder output device

  atmel-hlcdc:
   - Rework fbdev creation logic

  tegra:
   - OF node fix

  fsl-dcu:
   - Minor fixes

  mali-dp:
   - Assorted fixes

  sunxi:
   - Minor fix"

[ This was the "fixed" pull, that still had build warnings due to people
  not even having build tested the result. I'm not a happy camper

  I've fixed the things I noticed up in this merge.      - Linus ]

* tag 'drm-for-v4.11-less-shouty' of git://people.freedesktop.org/~airlied/linux: (1177 commits)
  lib/Kconfig: make PRIME_NUMBERS not user selectable
  drm/tinydrm: helpers: Properly fix backlight dependency
  drm/tinydrm: mipi-dbi: Fix field width specifier warning
  drm/tinydrm: mipi-dbi: Silence: ‘cmd’ may be used uninitialized
  drm/sti: fix build warnings in sti_drv.c and sti_vtg.c files
  drm/amd/powerplay: fix PSI feature on Polars12
  drm/amdgpu: refuse to reserve io mem for split VRAM buffers
  drm/ttm: fix use-after-free races in vm fault handling
  drm/tinydrm: Add support for Multi-Inno MI0283QT display
  dt-bindings: Add Multi-Inno MI0283QT binding
  dt-bindings: display/panel: Add common rotation property
  of: Add vendor prefix for Multi-Inno
  drm/tinydrm: Add MIPI DBI support
  drm/tinydrm: Add helper functions
  drm: Add DRM support for tiny LCD displays
  drm/amd/amdgpu: post card if there is real hw resetting performed
  drm/nouveau/tmr: provide backtrace when a timeout is hit
  drm/nouveau/pci/g92: Fix rearm
  drm/nouveau/drm/therm/fan: add a fallback if no fan control is specified in the vbios
  drm/nouveau/hwmon: expose power_max and power_crit
  ..

26 files changed:
1  2 
Documentation/devicetree/bindings/vendor-prefixes.txt
Documentation/gpu/i915.rst
MAINTAINERS
drivers/gpu/drm/drm_dp_mst_topology.c
drivers/gpu/drm/drm_gem_cma_helper.c
drivers/gpu/drm/drm_mode_object.c
drivers/gpu/drm/i915/Makefile
drivers/gpu/drm/i915/i915_drv.c
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_gem_object.h
drivers/gpu/drm/i915/i915_irq.c
drivers/gpu/drm/i915/i915_reg.h
drivers/gpu/drm/i915/intel_audio.c
drivers/gpu/drm/i915/intel_drv.h
drivers/gpu/drm/i915/intel_hdmi.c
drivers/gpu/drm/msm/msm_gem.c
drivers/gpu/drm/nouveau/nouveau_fence.c
drivers/gpu/drm/tinydrm/mipi-dbi.c
drivers/gpu/drm/ttm/ttm_bo.c
include/drm/drm_edid.h
include/drm/drm_framebuffer.h
include/drm/ttm/ttm_bo_api.h
include/drm/ttm/ttm_bo_driver.h
include/uapi/linux/Kbuild
lib/Kconfig
lib/Makefile

Simple merge
diff --cc MAINTAINERS
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
index 029d5c3c81efd8547e997fad34801b9110c69fa7,e44c598ecb82d1a891841bb6bd069fb69957b20e..bcc81912b5e5afa23ec9833e5991e835e202e540
@@@ -3393,17 -3597,9 +3603,17 @@@ extern int i915_restore_state(struct dr
  void i915_setup_sysfs(struct drm_i915_private *dev_priv);
  void i915_teardown_sysfs(struct drm_i915_private *dev_priv);
  
 +/* intel_lpe_audio.c */
 +int  intel_lpe_audio_init(struct drm_i915_private *dev_priv);
 +void intel_lpe_audio_teardown(struct drm_i915_private *dev_priv);
 +void intel_lpe_audio_irq_handler(struct drm_i915_private *dev_priv);
 +void intel_lpe_audio_notify(struct drm_i915_private *dev_priv,
 +                          void *eld, int port, int pipe, int tmds_clk_speed,
 +                          bool dp_output, int link_rate);
 +
  /* intel_i2c.c */
- extern int intel_setup_gmbus(struct drm_device *dev);
- extern void intel_teardown_gmbus(struct drm_device *dev);
+ extern int intel_setup_gmbus(struct drm_i915_private *dev_priv);
+ extern void intel_teardown_gmbus(struct drm_i915_private *dev_priv);
  extern bool intel_gmbus_is_valid_pin(struct drm_i915_private *dev_priv,
                                     unsigned int pin);
  
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
index 0000000000000000000000000000000000000000,2d21b490005cd5fdcff62cf4ced4ae638ee76147..29c0939f52478011930957b7f0654d3f5a88ef1b
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,1005 +1,1005 @@@
 -              DRM_DEBUG_DRIVER("cmd=%02x, len=%zu\n", cmd, (int)len); \
+ /*
+  * MIPI Display Bus Interface (DBI) LCD controller support
+  *
+  * Copyright 2016 Noralf Trønnes
+  *
+  * 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.
+  */
+ #include <drm/tinydrm/mipi-dbi.h>
+ #include <drm/tinydrm/tinydrm-helpers.h>
+ #include <linux/debugfs.h>
+ #include <linux/dma-buf.h>
+ #include <linux/gpio/consumer.h>
+ #include <linux/module.h>
+ #include <linux/regulator/consumer.h>
+ #include <linux/spi/spi.h>
+ #include <video/mipi_display.h>
+ #define MIPI_DBI_MAX_SPI_READ_SPEED 2000000 /* 2MHz */
+ #define DCS_POWER_MODE_DISPLAY                        BIT(2)
+ #define DCS_POWER_MODE_DISPLAY_NORMAL_MODE    BIT(3)
+ #define DCS_POWER_MODE_SLEEP_MODE             BIT(4)
+ #define DCS_POWER_MODE_PARTIAL_MODE           BIT(5)
+ #define DCS_POWER_MODE_IDLE_MODE              BIT(6)
+ #define DCS_POWER_MODE_RESERVED_MASK          (BIT(0) | BIT(1) | BIT(7))
+ /**
+  * DOC: overview
+  *
+  * This library provides helpers for MIPI Display Bus Interface (DBI)
+  * compatible display controllers.
+  *
+  * Many controllers for tiny lcd displays are MIPI compliant and can use this
+  * library. If a controller uses registers 0x2A and 0x2B to set the area to
+  * update and uses register 0x2C to write to frame memory, it is most likely
+  * MIPI compliant.
+  *
+  * Only MIPI Type 1 displays are supported since a full frame memory is needed.
+  *
+  * There are 3 MIPI DBI implementation types:
+  *
+  * A. Motorola 6800 type parallel bus
+  *
+  * B. Intel 8080 type parallel bus
+  *
+  * C. SPI type with 3 options:
+  *
+  *    1. 9-bit with the Data/Command signal as the ninth bit
+  *    2. Same as above except it's sent as 16 bits
+  *    3. 8-bit with the Data/Command signal as a separate D/CX pin
+  *
+  * Currently mipi_dbi only supports Type C options 1 and 3 with
+  * mipi_dbi_spi_init().
+  */
+ #define MIPI_DBI_DEBUG_COMMAND(cmd, data, len) \
+ ({ \
+       if (!len) \
+               DRM_DEBUG_DRIVER("cmd=%02x\n", cmd); \
+       else if (len <= 32) \
+               DRM_DEBUG_DRIVER("cmd=%02x, par=%*ph\n", cmd, (int)len, data);\
+       else \
++              DRM_DEBUG_DRIVER("cmd=%02x, len=%zu\n", cmd, len); \
+ })
+ static const u8 mipi_dbi_dcs_read_commands[] = {
+       MIPI_DCS_GET_DISPLAY_ID,
+       MIPI_DCS_GET_RED_CHANNEL,
+       MIPI_DCS_GET_GREEN_CHANNEL,
+       MIPI_DCS_GET_BLUE_CHANNEL,
+       MIPI_DCS_GET_DISPLAY_STATUS,
+       MIPI_DCS_GET_POWER_MODE,
+       MIPI_DCS_GET_ADDRESS_MODE,
+       MIPI_DCS_GET_PIXEL_FORMAT,
+       MIPI_DCS_GET_DISPLAY_MODE,
+       MIPI_DCS_GET_SIGNAL_MODE,
+       MIPI_DCS_GET_DIAGNOSTIC_RESULT,
+       MIPI_DCS_READ_MEMORY_START,
+       MIPI_DCS_READ_MEMORY_CONTINUE,
+       MIPI_DCS_GET_SCANLINE,
+       MIPI_DCS_GET_DISPLAY_BRIGHTNESS,
+       MIPI_DCS_GET_CONTROL_DISPLAY,
+       MIPI_DCS_GET_POWER_SAVE,
+       MIPI_DCS_GET_CABC_MIN_BRIGHTNESS,
+       MIPI_DCS_READ_DDB_START,
+       MIPI_DCS_READ_DDB_CONTINUE,
+       0, /* sentinel */
+ };
+ static bool mipi_dbi_command_is_read(struct mipi_dbi *mipi, u8 cmd)
+ {
+       unsigned int i;
+       if (!mipi->read_commands)
+               return false;
+       for (i = 0; i < 0xff; i++) {
+               if (!mipi->read_commands[i])
+                       return false;
+               if (cmd == mipi->read_commands[i])
+                       return true;
+       }
+       return false;
+ }
+ /**
+  * mipi_dbi_command_read - MIPI DCS read command
+  * @mipi: MIPI structure
+  * @cmd: Command
+  * @val: Value read
+  *
+  * Send MIPI DCS read command to the controller.
+  *
+  * Returns:
+  * Zero on success, negative error code on failure.
+  */
+ int mipi_dbi_command_read(struct mipi_dbi *mipi, u8 cmd, u8 *val)
+ {
+       if (!mipi->read_commands)
+               return -EACCES;
+       if (!mipi_dbi_command_is_read(mipi, cmd))
+               return -EINVAL;
+       return mipi_dbi_command_buf(mipi, cmd, val, 1);
+ }
+ EXPORT_SYMBOL(mipi_dbi_command_read);
+ /**
+  * mipi_dbi_command_buf - MIPI DCS command with parameter(s) in an array
+  * @mipi: MIPI structure
+  * @cmd: Command
+  * @data: Parameter buffer
+  * @len: Buffer length
+  *
+  * Returns:
+  * Zero on success, negative error code on failure.
+  */
+ int mipi_dbi_command_buf(struct mipi_dbi *mipi, u8 cmd, u8 *data, size_t len)
+ {
+       int ret;
+       mutex_lock(&mipi->cmdlock);
+       ret = mipi->command(mipi, cmd, data, len);
+       mutex_unlock(&mipi->cmdlock);
+       return ret;
+ }
+ EXPORT_SYMBOL(mipi_dbi_command_buf);
+ static int mipi_dbi_buf_copy(void *dst, struct drm_framebuffer *fb,
+                               struct drm_clip_rect *clip, bool swap)
+ {
+       struct drm_gem_cma_object *cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
+       struct dma_buf_attachment *import_attach = cma_obj->base.import_attach;
+       struct drm_format_name_buf format_name;
+       void *src = cma_obj->vaddr;
+       int ret = 0;
+       if (import_attach) {
+               ret = dma_buf_begin_cpu_access(import_attach->dmabuf,
+                                              DMA_FROM_DEVICE);
+               if (ret)
+                       return ret;
+       }
+       switch (fb->format->format) {
+       case DRM_FORMAT_RGB565:
+               if (swap)
+                       tinydrm_swab16(dst, src, fb, clip);
+               else
+                       tinydrm_memcpy(dst, src, fb, clip);
+               break;
+       case DRM_FORMAT_XRGB8888:
+               tinydrm_xrgb8888_to_rgb565(dst, src, fb, clip, swap);
+               break;
+       default:
+               dev_err_once(fb->dev->dev, "Format is not supported: %s\n",
+                            drm_get_format_name(fb->format->format,
+                                                &format_name));
+               return -EINVAL;
+       }
+       if (import_attach)
+               ret = dma_buf_end_cpu_access(import_attach->dmabuf,
+                                            DMA_FROM_DEVICE);
+       return ret;
+ }
+ static int mipi_dbi_fb_dirty(struct drm_framebuffer *fb,
+                            struct drm_file *file_priv,
+                            unsigned int flags, unsigned int color,
+                            struct drm_clip_rect *clips,
+                            unsigned int num_clips)
+ {
+       struct drm_gem_cma_object *cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
+       struct tinydrm_device *tdev = fb->dev->dev_private;
+       struct mipi_dbi *mipi = mipi_dbi_from_tinydrm(tdev);
+       bool swap = mipi->swap_bytes;
+       struct drm_clip_rect clip;
+       int ret = 0;
+       bool full;
+       void *tr;
+       mutex_lock(&tdev->dirty_lock);
+       if (!mipi->enabled)
+               goto out_unlock;
+       /* fbdev can flush even when we're not interested */
+       if (tdev->pipe.plane.fb != fb)
+               goto out_unlock;
+       full = tinydrm_merge_clips(&clip, clips, num_clips, flags,
+                                  fb->width, fb->height);
+       DRM_DEBUG("Flushing [FB:%d] x1=%u, x2=%u, y1=%u, y2=%u\n", fb->base.id,
+                 clip.x1, clip.x2, clip.y1, clip.y2);
+       if (!mipi->dc || !full || swap ||
+           fb->format->format == DRM_FORMAT_XRGB8888) {
+               tr = mipi->tx_buf;
+               ret = mipi_dbi_buf_copy(mipi->tx_buf, fb, &clip, swap);
+               if (ret)
+                       goto out_unlock;
+       } else {
+               tr = cma_obj->vaddr;
+       }
+       mipi_dbi_command(mipi, MIPI_DCS_SET_COLUMN_ADDRESS,
+                        (clip.x1 >> 8) & 0xFF, clip.x1 & 0xFF,
+                        (clip.x2 >> 8) & 0xFF, (clip.x2 - 1) & 0xFF);
+       mipi_dbi_command(mipi, MIPI_DCS_SET_PAGE_ADDRESS,
+                        (clip.y1 >> 8) & 0xFF, clip.y1 & 0xFF,
+                        (clip.y2 >> 8) & 0xFF, (clip.y2 - 1) & 0xFF);
+       ret = mipi_dbi_command_buf(mipi, MIPI_DCS_WRITE_MEMORY_START, tr,
+                               (clip.x2 - clip.x1) * (clip.y2 - clip.y1) * 2);
+ out_unlock:
+       mutex_unlock(&tdev->dirty_lock);
+       if (ret)
+               dev_err_once(fb->dev->dev, "Failed to update display %d\n",
+                            ret);
+       return ret;
+ }
+ static const struct drm_framebuffer_funcs mipi_dbi_fb_funcs = {
+       .destroy        = drm_fb_cma_destroy,
+       .create_handle  = drm_fb_cma_create_handle,
+       .dirty          = mipi_dbi_fb_dirty,
+ };
+ /**
+  * mipi_dbi_pipe_enable - MIPI DBI pipe enable helper
+  * @pipe: Display pipe
+  * @crtc_state: CRTC state
+  *
+  * This function enables backlight. Drivers can use this as their
+  * &drm_simple_display_pipe_funcs->enable callback.
+  */
+ void mipi_dbi_pipe_enable(struct drm_simple_display_pipe *pipe,
+                         struct drm_crtc_state *crtc_state)
+ {
+       struct tinydrm_device *tdev = pipe_to_tinydrm(pipe);
+       struct mipi_dbi *mipi = mipi_dbi_from_tinydrm(tdev);
+       struct drm_framebuffer *fb = pipe->plane.fb;
+       DRM_DEBUG_KMS("\n");
+       mipi->enabled = true;
+       if (fb)
+               fb->funcs->dirty(fb, NULL, 0, 0, NULL, 0);
+       tinydrm_enable_backlight(mipi->backlight);
+ }
+ EXPORT_SYMBOL(mipi_dbi_pipe_enable);
+ static void mipi_dbi_blank(struct mipi_dbi *mipi)
+ {
+       struct drm_device *drm = mipi->tinydrm.drm;
+       u16 height = drm->mode_config.min_height;
+       u16 width = drm->mode_config.min_width;
+       size_t len = width * height * 2;
+       memset(mipi->tx_buf, 0, len);
+       mipi_dbi_command(mipi, MIPI_DCS_SET_COLUMN_ADDRESS, 0, 0,
+                        (width >> 8) & 0xFF, (width - 1) & 0xFF);
+       mipi_dbi_command(mipi, MIPI_DCS_SET_PAGE_ADDRESS, 0, 0,
+                        (height >> 8) & 0xFF, (height - 1) & 0xFF);
+       mipi_dbi_command_buf(mipi, MIPI_DCS_WRITE_MEMORY_START,
+                            (u8 *)mipi->tx_buf, len);
+ }
+ /**
+  * mipi_dbi_pipe_disable - MIPI DBI pipe disable helper
+  * @pipe: Display pipe
+  *
+  * This function disables backlight if present or if not the
+  * display memory is blanked. Drivers can use this as their
+  * &drm_simple_display_pipe_funcs->disable callback.
+  */
+ void mipi_dbi_pipe_disable(struct drm_simple_display_pipe *pipe)
+ {
+       struct tinydrm_device *tdev = pipe_to_tinydrm(pipe);
+       struct mipi_dbi *mipi = mipi_dbi_from_tinydrm(tdev);
+       DRM_DEBUG_KMS("\n");
+       mipi->enabled = false;
+       if (mipi->backlight)
+               tinydrm_disable_backlight(mipi->backlight);
+       else
+               mipi_dbi_blank(mipi);
+ }
+ EXPORT_SYMBOL(mipi_dbi_pipe_disable);
+ static const uint32_t mipi_dbi_formats[] = {
+       DRM_FORMAT_RGB565,
+       DRM_FORMAT_XRGB8888,
+ };
+ /**
+  * mipi_dbi_init - MIPI DBI initialization
+  * @dev: Parent device
+  * @mipi: &mipi_dbi structure to initialize
+  * @pipe_funcs: Display pipe functions
+  * @driver: DRM driver
+  * @mode: Display mode
+  * @rotation: Initial rotation in degrees Counter Clock Wise
+  *
+  * This function initializes a &mipi_dbi structure and it's underlying
+  * @tinydrm_device. It also sets up the display pipeline.
+  *
+  * Supported formats: Native RGB565 and emulated XRGB8888.
+  *
+  * Objects created by this function will be automatically freed on driver
+  * detach (devres).
+  *
+  * Returns:
+  * Zero on success, negative error code on failure.
+  */
+ int mipi_dbi_init(struct device *dev, struct mipi_dbi *mipi,
+                 const struct drm_simple_display_pipe_funcs *pipe_funcs,
+                 struct drm_driver *driver,
+                 const struct drm_display_mode *mode, unsigned int rotation)
+ {
+       size_t bufsize = mode->vdisplay * mode->hdisplay * sizeof(u16);
+       struct tinydrm_device *tdev = &mipi->tinydrm;
+       int ret;
+       if (!mipi->command)
+               return -EINVAL;
+       mutex_init(&mipi->cmdlock);
+       mipi->tx_buf = devm_kmalloc(dev, bufsize, GFP_KERNEL);
+       if (!mipi->tx_buf)
+               return -ENOMEM;
+       ret = devm_tinydrm_init(dev, tdev, &mipi_dbi_fb_funcs, driver);
+       if (ret)
+               return ret;
+       /* TODO: Maybe add DRM_MODE_CONNECTOR_SPI */
+       ret = tinydrm_display_pipe_init(tdev, pipe_funcs,
+                                       DRM_MODE_CONNECTOR_VIRTUAL,
+                                       mipi_dbi_formats,
+                                       ARRAY_SIZE(mipi_dbi_formats), mode,
+                                       rotation);
+       if (ret)
+               return ret;
+       tdev->drm->mode_config.preferred_depth = 16;
+       mipi->rotation = rotation;
+       drm_mode_config_reset(tdev->drm);
+       DRM_DEBUG_KMS("preferred_depth=%u, rotation = %u\n",
+                     tdev->drm->mode_config.preferred_depth, rotation);
+       return 0;
+ }
+ EXPORT_SYMBOL(mipi_dbi_init);
+ /**
+  * mipi_dbi_hw_reset - Hardware reset of controller
+  * @mipi: MIPI DBI structure
+  *
+  * Reset controller if the &mipi_dbi->reset gpio is set.
+  */
+ void mipi_dbi_hw_reset(struct mipi_dbi *mipi)
+ {
+       if (!mipi->reset)
+               return;
+       gpiod_set_value_cansleep(mipi->reset, 0);
+       msleep(20);
+       gpiod_set_value_cansleep(mipi->reset, 1);
+       msleep(120);
+ }
+ EXPORT_SYMBOL(mipi_dbi_hw_reset);
+ /**
+  * mipi_dbi_display_is_on - Check if display is on
+  * @mipi: MIPI DBI structure
+  *
+  * This function checks the Power Mode register (if readable) to see if
+  * display output is turned on. This can be used to see if the bootloader
+  * has already turned on the display avoiding flicker when the pipeline is
+  * enabled.
+  *
+  * Returns:
+  * true if the display can be verified to be on, false otherwise.
+  */
+ bool mipi_dbi_display_is_on(struct mipi_dbi *mipi)
+ {
+       u8 val;
+       if (mipi_dbi_command_read(mipi, MIPI_DCS_GET_POWER_MODE, &val))
+               return false;
+       val &= ~DCS_POWER_MODE_RESERVED_MASK;
+       if (val != (DCS_POWER_MODE_DISPLAY |
+           DCS_POWER_MODE_DISPLAY_NORMAL_MODE | DCS_POWER_MODE_SLEEP_MODE))
+               return false;
+       DRM_DEBUG_DRIVER("Display is ON\n");
+       return true;
+ }
+ EXPORT_SYMBOL(mipi_dbi_display_is_on);
+ #if IS_ENABLED(CONFIG_SPI)
+ /*
+  * Many controllers have a max speed of 10MHz, but can be pushed way beyond
+  * that. Increase reliability by running pixel data at max speed and the rest
+  * at 10MHz, preventing transfer glitches from messing up the init settings.
+  */
+ static u32 mipi_dbi_spi_cmd_max_speed(struct spi_device *spi, size_t len)
+ {
+       if (len > 64)
+               return 0; /* use default */
+       return min_t(u32, 10000000, spi->max_speed_hz);
+ }
+ /*
+  * MIPI DBI Type C Option 1
+  *
+  * If the SPI controller doesn't have 9 bits per word support,
+  * use blocks of 9 bytes to send 8x 9-bit words using a 8-bit SPI transfer.
+  * Pad partial blocks with MIPI_DCS_NOP (zero).
+  * This is how the D/C bit (x) is added:
+  *     x7654321
+  *     0x765432
+  *     10x76543
+  *     210x7654
+  *     3210x765
+  *     43210x76
+  *     543210x7
+  *     6543210x
+  *     76543210
+  */
+ static int mipi_dbi_spi1e_transfer(struct mipi_dbi *mipi, int dc,
+                                  const void *buf, size_t len,
+                                  unsigned int bpw)
+ {
+       bool swap_bytes = (bpw == 16 && tinydrm_machine_little_endian());
+       size_t chunk, max_chunk = mipi->tx_buf9_len;
+       struct spi_device *spi = mipi->spi;
+       struct spi_transfer tr = {
+               .tx_buf = mipi->tx_buf9,
+               .bits_per_word = 8,
+       };
+       struct spi_message m;
+       const u8 *src = buf;
+       int i, ret;
+       u8 *dst;
+       if (drm_debug & DRM_UT_DRIVER)
+               pr_debug("[drm:%s] dc=%d, max_chunk=%zu, transfers:\n",
+                        __func__, dc, max_chunk);
+       tr.speed_hz = mipi_dbi_spi_cmd_max_speed(spi, len);
+       spi_message_init_with_transfers(&m, &tr, 1);
+       if (!dc) {
+               if (WARN_ON_ONCE(len != 1))
+                       return -EINVAL;
+               /* Command: pad no-op's (zeroes) at beginning of block */
+               dst = mipi->tx_buf9;
+               memset(dst, 0, 9);
+               dst[8] = *src;
+               tr.len = 9;
+               tinydrm_dbg_spi_message(spi, &m);
+               return spi_sync(spi, &m);
+       }
+       /* max with room for adding one bit per byte */
+       max_chunk = max_chunk / 9 * 8;
+       /* but no bigger than len */
+       max_chunk = min(max_chunk, len);
+       /* 8 byte blocks */
+       max_chunk = max_t(size_t, 8, max_chunk & ~0x7);
+       while (len) {
+               size_t added = 0;
+               chunk = min(len, max_chunk);
+               len -= chunk;
+               dst = mipi->tx_buf9;
+               if (chunk < 8) {
+                       u8 val, carry = 0;
+                       /* Data: pad no-op's (zeroes) at end of block */
+                       memset(dst, 0, 9);
+                       if (swap_bytes) {
+                               for (i = 1; i < (chunk + 1); i++) {
+                                       val = src[1];
+                                       *dst++ = carry | BIT(8 - i) | (val >> i);
+                                       carry = val << (8 - i);
+                                       i++;
+                                       val = src[0];
+                                       *dst++ = carry | BIT(8 - i) | (val >> i);
+                                       carry = val << (8 - i);
+                                       src += 2;
+                               }
+                               *dst++ = carry;
+                       } else {
+                               for (i = 1; i < (chunk + 1); i++) {
+                                       val = *src++;
+                                       *dst++ = carry | BIT(8 - i) | (val >> i);
+                                       carry = val << (8 - i);
+                               }
+                               *dst++ = carry;
+                       }
+                       chunk = 8;
+                       added = 1;
+               } else {
+                       for (i = 0; i < chunk; i += 8) {
+                               if (swap_bytes) {
+                                       *dst++ =                 BIT(7) | (src[1] >> 1);
+                                       *dst++ = (src[1] << 7) | BIT(6) | (src[0] >> 2);
+                                       *dst++ = (src[0] << 6) | BIT(5) | (src[3] >> 3);
+                                       *dst++ = (src[3] << 5) | BIT(4) | (src[2] >> 4);
+                                       *dst++ = (src[2] << 4) | BIT(3) | (src[5] >> 5);
+                                       *dst++ = (src[5] << 3) | BIT(2) | (src[4] >> 6);
+                                       *dst++ = (src[4] << 2) | BIT(1) | (src[7] >> 7);
+                                       *dst++ = (src[7] << 1) | BIT(0);
+                                       *dst++ = src[6];
+                               } else {
+                                       *dst++ =                 BIT(7) | (src[0] >> 1);
+                                       *dst++ = (src[0] << 7) | BIT(6) | (src[1] >> 2);
+                                       *dst++ = (src[1] << 6) | BIT(5) | (src[2] >> 3);
+                                       *dst++ = (src[2] << 5) | BIT(4) | (src[3] >> 4);
+                                       *dst++ = (src[3] << 4) | BIT(3) | (src[4] >> 5);
+                                       *dst++ = (src[4] << 3) | BIT(2) | (src[5] >> 6);
+                                       *dst++ = (src[5] << 2) | BIT(1) | (src[6] >> 7);
+                                       *dst++ = (src[6] << 1) | BIT(0);
+                                       *dst++ = src[7];
+                               }
+                               src += 8;
+                               added++;
+                       }
+               }
+               tr.len = chunk + added;
+               tinydrm_dbg_spi_message(spi, &m);
+               ret = spi_sync(spi, &m);
+               if (ret)
+                       return ret;
+       };
+       return 0;
+ }
+ static int mipi_dbi_spi1_transfer(struct mipi_dbi *mipi, int dc,
+                                 const void *buf, size_t len,
+                                 unsigned int bpw)
+ {
+       struct spi_device *spi = mipi->spi;
+       struct spi_transfer tr = {
+               .bits_per_word = 9,
+       };
+       const u16 *src16 = buf;
+       const u8 *src8 = buf;
+       struct spi_message m;
+       size_t max_chunk;
+       u16 *dst16;
+       int ret;
+       if (!tinydrm_spi_bpw_supported(spi, 9))
+               return mipi_dbi_spi1e_transfer(mipi, dc, buf, len, bpw);
+       tr.speed_hz = mipi_dbi_spi_cmd_max_speed(spi, len);
+       max_chunk = mipi->tx_buf9_len;
+       dst16 = mipi->tx_buf9;
+       if (drm_debug & DRM_UT_DRIVER)
+               pr_debug("[drm:%s] dc=%d, max_chunk=%zu, transfers:\n",
+                        __func__, dc, max_chunk);
+       max_chunk = min(max_chunk / 2, len);
+       spi_message_init_with_transfers(&m, &tr, 1);
+       tr.tx_buf = dst16;
+       while (len) {
+               size_t chunk = min(len, max_chunk);
+               unsigned int i;
+               if (bpw == 16 && tinydrm_machine_little_endian()) {
+                       for (i = 0; i < (chunk * 2); i += 2) {
+                               dst16[i]     = *src16 >> 8;
+                               dst16[i + 1] = *src16++ & 0xFF;
+                               if (dc) {
+                                       dst16[i]     |= 0x0100;
+                                       dst16[i + 1] |= 0x0100;
+                               }
+                       }
+               } else {
+                       for (i = 0; i < chunk; i++) {
+                               dst16[i] = *src8++;
+                               if (dc)
+                                       dst16[i] |= 0x0100;
+                       }
+               }
+               tr.len = chunk;
+               len -= chunk;
+               tinydrm_dbg_spi_message(spi, &m);
+               ret = spi_sync(spi, &m);
+               if (ret)
+                       return ret;
+       };
+       return 0;
+ }
+ static int mipi_dbi_typec1_command(struct mipi_dbi *mipi, u8 cmd,
+                                  u8 *parameters, size_t num)
+ {
+       unsigned int bpw = (cmd == MIPI_DCS_WRITE_MEMORY_START) ? 16 : 8;
+       int ret;
+       if (mipi_dbi_command_is_read(mipi, cmd))
+               return -ENOTSUPP;
+       MIPI_DBI_DEBUG_COMMAND(cmd, parameters, num);
+       ret = mipi_dbi_spi1_transfer(mipi, 0, &cmd, 1, 8);
+       if (ret || !num)
+               return ret;
+       return mipi_dbi_spi1_transfer(mipi, 1, parameters, num, bpw);
+ }
+ /* MIPI DBI Type C Option 3 */
+ static int mipi_dbi_typec3_command_read(struct mipi_dbi *mipi, u8 cmd,
+                                       u8 *data, size_t len)
+ {
+       struct spi_device *spi = mipi->spi;
+       u32 speed_hz = min_t(u32, MIPI_DBI_MAX_SPI_READ_SPEED,
+                            spi->max_speed_hz / 2);
+       struct spi_transfer tr[2] = {
+               {
+                       .speed_hz = speed_hz,
+                       .tx_buf = &cmd,
+                       .len = 1,
+               }, {
+                       .speed_hz = speed_hz,
+                       .len = len,
+               },
+       };
+       struct spi_message m;
+       u8 *buf;
+       int ret;
+       if (!len)
+               return -EINVAL;
+       /*
+        * Support non-standard 24-bit and 32-bit Nokia read commands which
+        * start with a dummy clock, so we need to read an extra byte.
+        */
+       if (cmd == MIPI_DCS_GET_DISPLAY_ID ||
+           cmd == MIPI_DCS_GET_DISPLAY_STATUS) {
+               if (!(len == 3 || len == 4))
+                       return -EINVAL;
+               tr[1].len = len + 1;
+       }
+       buf = kmalloc(tr[1].len, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+       tr[1].rx_buf = buf;
+       gpiod_set_value_cansleep(mipi->dc, 0);
+       spi_message_init_with_transfers(&m, tr, ARRAY_SIZE(tr));
+       ret = spi_sync(spi, &m);
+       if (ret)
+               goto err_free;
+       tinydrm_dbg_spi_message(spi, &m);
+       if (tr[1].len == len) {
+               memcpy(data, buf, len);
+       } else {
+               unsigned int i;
+               for (i = 0; i < len; i++)
+                       data[i] = (buf[i] << 1) | !!(buf[i + 1] & BIT(7));
+       }
+       MIPI_DBI_DEBUG_COMMAND(cmd, data, len);
+ err_free:
+       kfree(buf);
+       return ret;
+ }
+ static int mipi_dbi_typec3_command(struct mipi_dbi *mipi, u8 cmd,
+                                  u8 *par, size_t num)
+ {
+       struct spi_device *spi = mipi->spi;
+       unsigned int bpw = 8;
+       u32 speed_hz;
+       int ret;
+       if (mipi_dbi_command_is_read(mipi, cmd))
+               return mipi_dbi_typec3_command_read(mipi, cmd, par, num);
+       MIPI_DBI_DEBUG_COMMAND(cmd, par, num);
+       gpiod_set_value_cansleep(mipi->dc, 0);
+       speed_hz = mipi_dbi_spi_cmd_max_speed(spi, 1);
+       ret = tinydrm_spi_transfer(spi, speed_hz, NULL, 8, &cmd, 1);
+       if (ret || !num)
+               return ret;
+       if (cmd == MIPI_DCS_WRITE_MEMORY_START && !mipi->swap_bytes)
+               bpw = 16;
+       gpiod_set_value_cansleep(mipi->dc, 1);
+       speed_hz = mipi_dbi_spi_cmd_max_speed(spi, num);
+       return tinydrm_spi_transfer(spi, speed_hz, NULL, bpw, par, num);
+ }
+ /**
+  * mipi_dbi_spi_init - Initialize MIPI DBI SPI interfaced controller
+  * @spi: SPI device
+  * @dc: D/C gpio (optional)
+  * @mipi: &mipi_dbi structure to initialize
+  * @pipe_funcs: Display pipe functions
+  * @driver: DRM driver
+  * @mode: Display mode
+  * @rotation: Initial rotation in degrees Counter Clock Wise
+  *
+  * This function sets &mipi_dbi->command, enables &mipi->read_commands for the
+  * usual read commands and initializes @mipi using mipi_dbi_init().
+  *
+  * If @dc is set, a Type C Option 3 interface is assumed, if not
+  * Type C Option 1.
+  *
+  * If the SPI master driver doesn't support the necessary bits per word,
+  * the following transformation is used:
+  *
+  * - 9-bit: reorder buffer as 9x 8-bit words, padded with no-op command.
+  * - 16-bit: if big endian send as 8-bit, if little endian swap bytes
+  *
+  * Returns:
+  * Zero on success, negative error code on failure.
+  */
+ int mipi_dbi_spi_init(struct spi_device *spi, struct mipi_dbi *mipi,
+                     struct gpio_desc *dc,
+                     const struct drm_simple_display_pipe_funcs *pipe_funcs,
+                     struct drm_driver *driver,
+                     const struct drm_display_mode *mode,
+                     unsigned int rotation)
+ {
+       size_t tx_size = tinydrm_spi_max_transfer_size(spi, 0);
+       struct device *dev = &spi->dev;
+       int ret;
+       if (tx_size < 16) {
+               DRM_ERROR("SPI transmit buffer too small: %zu\n", tx_size);
+               return -EINVAL;
+       }
+       /*
+        * Even though it's not the SPI device that does DMA (the master does),
+        * the dma mask is necessary for the dma_alloc_wc() in
+        * drm_gem_cma_create(). The dma_addr returned will be a physical
+        * adddress which might be different from the bus address, but this is
+        * not a problem since the address will not be used.
+        * The virtual address is used in the transfer and the SPI core
+        * re-maps it on the SPI master device using the DMA streaming API
+        * (spi_map_buf()).
+        */
+       if (!dev->coherent_dma_mask) {
+               ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(32));
+               if (ret) {
+                       dev_warn(dev, "Failed to set dma mask %d\n", ret);
+                       return ret;
+               }
+       }
+       mipi->spi = spi;
+       mipi->read_commands = mipi_dbi_dcs_read_commands;
+       if (dc) {
+               mipi->command = mipi_dbi_typec3_command;
+               mipi->dc = dc;
+               if (tinydrm_machine_little_endian() &&
+                   !tinydrm_spi_bpw_supported(spi, 16))
+                       mipi->swap_bytes = true;
+       } else {
+               mipi->command = mipi_dbi_typec1_command;
+               mipi->tx_buf9_len = tx_size;
+               mipi->tx_buf9 = devm_kmalloc(dev, tx_size, GFP_KERNEL);
+               if (!mipi->tx_buf9)
+                       return -ENOMEM;
+       }
+       return mipi_dbi_init(dev, mipi, pipe_funcs, driver, mode, rotation);
+ }
+ EXPORT_SYMBOL(mipi_dbi_spi_init);
+ #endif /* CONFIG_SPI */
+ #ifdef CONFIG_DEBUG_FS
+ static ssize_t mipi_dbi_debugfs_command_write(struct file *file,
+                                             const char __user *ubuf,
+                                             size_t count, loff_t *ppos)
+ {
+       struct seq_file *m = file->private_data;
+       struct mipi_dbi *mipi = m->private;
+       u8 val, cmd = 0, parameters[64];
+       char *buf, *pos, *token;
+       unsigned int i;
+       int ret;
+       buf = memdup_user_nul(ubuf, count);
+       if (IS_ERR(buf))
+               return PTR_ERR(buf);
+       /* strip trailing whitespace */
+       for (i = count - 1; i > 0; i--)
+               if (isspace(buf[i]))
+                       buf[i] = '\0';
+               else
+                       break;
+       i = 0;
+       pos = buf;
+       while (pos) {
+               token = strsep(&pos, " ");
+               if (!token) {
+                       ret = -EINVAL;
+                       goto err_free;
+               }
+               ret = kstrtou8(token, 16, &val);
+               if (ret < 0)
+                       goto err_free;
+               if (token == buf)
+                       cmd = val;
+               else
+                       parameters[i++] = val;
+               if (i == 64) {
+                       ret = -E2BIG;
+                       goto err_free;
+               }
+       }
+       ret = mipi_dbi_command_buf(mipi, cmd, parameters, i);
+ err_free:
+       kfree(buf);
+       return ret < 0 ? ret : count;
+ }
+ static int mipi_dbi_debugfs_command_show(struct seq_file *m, void *unused)
+ {
+       struct mipi_dbi *mipi = m->private;
+       u8 cmd, val[4];
+       size_t len, i;
+       int ret;
+       for (cmd = 0; cmd < 255; cmd++) {
+               if (!mipi_dbi_command_is_read(mipi, cmd))
+                       continue;
+               switch (cmd) {
+               case MIPI_DCS_READ_MEMORY_START:
+               case MIPI_DCS_READ_MEMORY_CONTINUE:
+                       len = 2;
+                       break;
+               case MIPI_DCS_GET_DISPLAY_ID:
+                       len = 3;
+                       break;
+               case MIPI_DCS_GET_DISPLAY_STATUS:
+                       len = 4;
+                       break;
+               default:
+                       len = 1;
+                       break;
+               }
+               seq_printf(m, "%02x: ", cmd);
+               ret = mipi_dbi_command_buf(mipi, cmd, val, len);
+               if (ret) {
+                       seq_puts(m, "XX\n");
+                       continue;
+               }
+               for (i = 0; i < len; i++)
+                       seq_printf(m, "%02x", val[i]);
+               seq_puts(m, "\n");
+       }
+       return 0;
+ }
+ static int mipi_dbi_debugfs_command_open(struct inode *inode,
+                                        struct file *file)
+ {
+       return single_open(file, mipi_dbi_debugfs_command_show,
+                          inode->i_private);
+ }
+ static const struct file_operations mipi_dbi_debugfs_command_fops = {
+       .owner = THIS_MODULE,
+       .open = mipi_dbi_debugfs_command_open,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = single_release,
+       .write = mipi_dbi_debugfs_command_write,
+ };
+ static const struct drm_info_list mipi_dbi_debugfs_list[] = {
+       { "fb",   drm_fb_cma_debugfs_show, 0 },
+ };
+ /**
+  * mipi_dbi_debugfs_init - Create debugfs entries
+  * @minor: DRM minor
+  *
+  * This function creates a 'command' debugfs file for sending commands to the
+  * controller or getting the read command values.
+  * Drivers can use this as their &drm_driver->debugfs_init callback.
+  *
+  * Returns:
+  * Zero on success, negative error code on failure.
+  */
+ int mipi_dbi_debugfs_init(struct drm_minor *minor)
+ {
+       struct tinydrm_device *tdev = minor->dev->dev_private;
+       struct mipi_dbi *mipi = mipi_dbi_from_tinydrm(tdev);
+       umode_t mode = S_IFREG | S_IWUSR;
+       if (mipi->read_commands)
+               mode |= S_IRUGO;
+       debugfs_create_file("command", mode, minor->debugfs_root, mipi,
+                           &mipi_dbi_debugfs_command_fops);
+       return drm_debugfs_create_files(mipi_dbi_debugfs_list,
+                                       ARRAY_SIZE(mipi_dbi_debugfs_list),
+                                       minor->debugfs_root, minor);
+ }
+ EXPORT_SYMBOL(mipi_dbi_debugfs_init);
+ #endif
+ MODULE_LICENSE("GPL");
index ffc6cb55c78c149a1c53314847e2cf8076050a29,4562e53c8244d0007dd50866a66638b1d10e35bc..17478f38dea35b933ce95bb8e2d52874aed277e3
@@@ -181,26 -184,37 +184,26 @@@ void ttm_bo_add_to_lru(struct ttm_buffe
  }
  EXPORT_SYMBOL(ttm_bo_add_to_lru);
  
 -int ttm_bo_del_from_lru(struct ttm_buffer_object *bo)
 +static void ttm_bo_ref_bug(struct kref *list_kref)
  {
 -      int put_count = 0;
 +      BUG();
 +}
  
-       struct ttm_bo_device *bdev = bo->bdev;
-       if (bdev->driver->lru_removal)
-               bdev->driver->lru_removal(bo);
 +void ttm_bo_del_from_lru(struct ttm_buffer_object *bo)
 +{
        if (!list_empty(&bo->swap)) {
                list_del_init(&bo->swap);
 -              ++put_count;
 +              kref_put(&bo->list_kref, ttm_bo_ref_bug);
        }
        if (!list_empty(&bo->lru)) {
                list_del_init(&bo->lru);
 -              ++put_count;
 +              kref_put(&bo->list_kref, ttm_bo_ref_bug);
        }
 -
 -      return put_count;
 -}
 -
 -static void ttm_bo_ref_bug(struct kref *list_kref)
 -{
 -      BUG();
 -}
 -
 -void ttm_bo_list_ref_sub(struct ttm_buffer_object *bo, int count,
 -                       bool never_free)
 -{
 -      kref_sub(&bo->list_kref, count,
 -               (never_free) ? ttm_bo_ref_bug : ttm_bo_release_list);
+       /*
+        * TODO: Add a driver hook to delete from
+        * driver-specific LRU's here.
+        */
  }
  
  void ttm_bo_del_sub_from_lru(struct ttm_buffer_object *bo)
@@@ -213,14 -230,12 +216,9 @@@ EXPORT_SYMBOL(ttm_bo_del_sub_from_lru)
  
  void ttm_bo_move_to_lru_tail(struct ttm_buffer_object *bo)
  {
-       struct ttm_bo_device *bdev = bo->bdev;
 -      int put_count = 0;
--
        lockdep_assert_held(&bo->resv->lock.base);
  
-       if (bdev->driver->lru_removal)
-               bdev->driver->lru_removal(bo);
 -      put_count = ttm_bo_del_from_lru(bo);
 -      ttm_bo_list_ref_sub(bo, put_count, true);
 +      ttm_bo_del_from_lru(bo);
        ttm_bo_add_to_lru(bo);
  }
  EXPORT_SYMBOL(ttm_bo_move_to_lru_tail);
@@@ -718,21 -728,28 +704,28 @@@ static int ttm_mem_evict_first(struct t
        struct ttm_bo_global *glob = bdev->glob;
        struct ttm_mem_type_manager *man = &bdev->man[mem_type];
        struct ttm_buffer_object *bo;
 -      int ret = -EBUSY, put_count;
 +      int ret = -EBUSY;
+       unsigned i;
  
        spin_lock(&glob->lru_lock);
-       list_for_each_entry(bo, &man->lru, lru) {
-               ret = __ttm_bo_reserve(bo, false, true, NULL);
-               if (ret)
-                       continue;
+       for (i = 0; i < TTM_MAX_BO_PRIORITY; ++i) {
+               list_for_each_entry(bo, &man->lru[i], lru) {
+                       ret = __ttm_bo_reserve(bo, false, true, NULL);
+                       if (ret)
+                               continue;
  
-               if (place && !bdev->driver->eviction_valuable(bo, place)) {
-                       __ttm_bo_unreserve(bo);
-                       ret = -EBUSY;
-                       continue;
+                       if (place && !bdev->driver->eviction_valuable(bo,
+                                                                     place)) {
+                               __ttm_bo_unreserve(bo);
+                               ret = -EBUSY;
+                               continue;
+                       }
+                       break;
                }
  
-               break;
+               if (!ret)
+                       break;
        }
  
        if (ret) {
@@@ -1645,11 -1667,16 +1641,15 @@@ static int ttm_bo_swapout(struct ttm_me
            container_of(shrink, struct ttm_bo_global, shrink);
        struct ttm_buffer_object *bo;
        int ret = -EBUSY;
-       uint32_t swap_placement = (TTM_PL_FLAG_CACHED | TTM_PL_FLAG_SYSTEM);
 -      int put_count;
+       unsigned i;
  
        spin_lock(&glob->lru_lock);
-       list_for_each_entry(bo, &glob->swap_lru, swap) {
-               ret = __ttm_bo_reserve(bo, false, true, NULL);
+       for (i = 0; i < TTM_MAX_BO_PRIORITY; ++i) {
+               list_for_each_entry(bo, &glob->swap_lru[i], swap) {
+                       ret = __ttm_bo_reserve(bo, false, true, NULL);
+                       if (!ret)
+                               break;
+               }
                if (!ret)
                        break;
        }
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
diff --cc lib/Kconfig
index f3552604e47a0db9afef9a26bb26d736cd4dc54c,f4193a3d9301fa6955fc8932a49e643cdcf45b3d..87ecd41031bd2ea8a78c43821a3c30957f1313fc
@@@ -550,7 -550,11 +550,10 @@@ config STACKDEPO
  config SBITMAP
        bool
  
 -      default n
 -      help
 -        Provides a helper module to generate prime numbers. Useful for writing
 -        test code, especially when checking multiplication and divison.
 +config PARMAN
 +      tristate
 +
+ config PRIME_NUMBERS
+       tristate
  endmenu
diff --cc lib/Makefile
Simple merge