diff options
Diffstat (limited to 'drivers/gpu/drm')
-rw-r--r-- | drivers/gpu/drm/bridge/ite-it6505.c | 8 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_panic.c | 10 | ||||
-rw-r--r-- | drivers/gpu/drm/mediatek/Kconfig | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/dispnv50/tile.h | 63 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/dispnv50/wndw.c | 129 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_display.c | 59 | ||||
-rw-r--r-- | drivers/gpu/drm/vkms/vkms_output.c | 5 |
7 files changed, 216 insertions, 60 deletions
diff --git a/drivers/gpu/drm/bridge/ite-it6505.c b/drivers/gpu/drm/bridge/ite-it6505.c index 7ff17aa14b01..008d86cc562a 100644 --- a/drivers/gpu/drm/bridge/ite-it6505.c +++ b/drivers/gpu/drm/bridge/ite-it6505.c @@ -2614,9 +2614,9 @@ static int it6505_poweron(struct it6505 *it6505) /* time interval between OVDD and SYSRSTN at least be 10ms */ if (pdata->gpiod_reset) { usleep_range(10000, 20000); - gpiod_set_value_cansleep(pdata->gpiod_reset, 0); - usleep_range(1000, 2000); gpiod_set_value_cansleep(pdata->gpiod_reset, 1); + usleep_range(1000, 2000); + gpiod_set_value_cansleep(pdata->gpiod_reset, 0); usleep_range(25000, 35000); } @@ -2647,7 +2647,7 @@ static int it6505_poweroff(struct it6505 *it6505) disable_irq_nosync(it6505->irq); if (pdata->gpiod_reset) - gpiod_set_value_cansleep(pdata->gpiod_reset, 0); + gpiod_set_value_cansleep(pdata->gpiod_reset, 1); if (pdata->pwr18) { err = regulator_disable(pdata->pwr18); @@ -3135,7 +3135,7 @@ static int it6505_init_pdata(struct it6505 *it6505) return PTR_ERR(pdata->ovdd); } - pdata->gpiod_reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); + pdata->gpiod_reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); if (IS_ERR(pdata->gpiod_reset)) { dev_err(dev, "gpiod_reset gpio not found"); return PTR_ERR(pdata->gpiod_reset); diff --git a/drivers/gpu/drm/drm_panic.c b/drivers/gpu/drm/drm_panic.c index 74412b7bf936..0a9ecc1380d2 100644 --- a/drivers/gpu/drm/drm_panic.c +++ b/drivers/gpu/drm/drm_panic.c @@ -209,6 +209,14 @@ static u32 convert_xrgb8888_to_argb2101010(u32 pix) return GENMASK(31, 30) /* set alpha bits */ | pix | ((pix >> 8) & 0x00300C03); } +static u32 convert_xrgb8888_to_abgr2101010(u32 pix) +{ + pix = ((pix & 0x00FF0000) >> 14) | + ((pix & 0x0000FF00) << 4) | + ((pix & 0x000000FF) << 22); + return GENMASK(31, 30) /* set alpha bits */ | pix | ((pix >> 8) & 0x00300C03); +} + /* * convert_from_xrgb8888 - convert one pixel from xrgb8888 to the desired format * @color: input color, in xrgb8888 format @@ -242,6 +250,8 @@ static u32 convert_from_xrgb8888(u32 color, u32 format) return convert_xrgb8888_to_xrgb2101010(color); case DRM_FORMAT_ARGB2101010: return convert_xrgb8888_to_argb2101010(color); + case DRM_FORMAT_ABGR2101010: + return convert_xrgb8888_to_abgr2101010(color); default: WARN_ONCE(1, "Can't convert to %p4cc\n", &format); return 0; diff --git a/drivers/gpu/drm/mediatek/Kconfig b/drivers/gpu/drm/mediatek/Kconfig index 2e0e7c4079b6..f496e6cfdfe0 100644 --- a/drivers/gpu/drm/mediatek/Kconfig +++ b/drivers/gpu/drm/mediatek/Kconfig @@ -2,7 +2,7 @@ config DRM_MEDIATEK tristate "DRM Support for Mediatek SoCs" depends on DRM - depends on (ARCH_MEDIATEK && ARM) || COMPILE_TEST + depends on ARCH_MEDIATEK || COMPILE_TEST depends on COMMON_CLK depends on HAVE_ARM_SMCCC || COMPILE_TEST depends on OF diff --git a/drivers/gpu/drm/nouveau/dispnv50/tile.h b/drivers/gpu/drm/nouveau/dispnv50/tile.h new file mode 100644 index 000000000000..e2be82830cf7 --- /dev/null +++ b/drivers/gpu/drm/nouveau/dispnv50/tile.h @@ -0,0 +1,63 @@ +/* SPDX-License-Identifier: MIT */ +#ifndef __NV50_TILE_H__ +#define __NV50_TILE_H__ + +#include <linux/types.h> +#include <linux/math.h> + +/* + * Tiling parameters for NV50+. + * GOB = Group of bytes, the main unit for tiling blocks. + * Tiling blocks are a power of 2 number of GOB. + * All GOBs and blocks have the same width: 64 bytes (so 16 pixels in 32bits). + * tile_mode is the log2 of the number of GOB per block. + */ + +#define NV_TILE_GOB_HEIGHT_TESLA 4 /* 4 x 64 bytes = 256 bytes for a GOB on Tesla*/ +#define NV_TILE_GOB_HEIGHT 8 /* 8 x 64 bytes = 512 bytes for a GOB on Fermi and later */ +#define NV_TILE_GOB_WIDTH_BYTES 64 + +/* Number of blocks to cover the width of the framebuffer */ +static inline u32 nouveau_get_width_in_blocks(u32 stride) +{ + return DIV_ROUND_UP(stride, NV_TILE_GOB_WIDTH_BYTES); +} + +/* Return the height in pixel of one GOB */ +static inline u32 nouveau_get_gob_height(u16 family) +{ + if (family == NV_DEVICE_INFO_V0_TESLA) + return NV_TILE_GOB_HEIGHT_TESLA; + else + return NV_TILE_GOB_HEIGHT; +} + +/* Number of blocks to cover the heigth of the framebuffer */ +static inline u32 nouveau_get_height_in_blocks(u32 height, u32 gobs_in_block, u16 family) +{ + return DIV_ROUND_UP(height, nouveau_get_gob_height(family) * gobs_in_block); +} + +/* Return the GOB size in bytes */ +static inline u32 nouveau_get_gob_size(u16 family) +{ + return nouveau_get_gob_height(family) * NV_TILE_GOB_WIDTH_BYTES; +} + +/* Return the number of GOB in a block */ +static inline int nouveau_get_gobs_in_block(u32 tile_mode, u16 chipset) +{ + if (chipset >= 0xc0) + return 1 << (tile_mode >> 4); + return 1 << tile_mode; +} + +/* Return true if tile_mode is invalid */ +static inline bool nouveau_check_tile_mode(u32 tile_mode, u16 chipset) +{ + if (chipset >= 0xc0) + return (tile_mode & 0xfffff0f); + return (tile_mode & 0xfffffff0); +} + +#endif diff --git a/drivers/gpu/drm/nouveau/dispnv50/wndw.c b/drivers/gpu/drm/nouveau/dispnv50/wndw.c index 7a2cceaee6e9..f6be426dd525 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/wndw.c +++ b/drivers/gpu/drm/nouveau/dispnv50/wndw.c @@ -30,14 +30,20 @@ #include <nvhw/class/cl507e.h> #include <nvhw/class/clc37e.h> +#include <linux/iosys-map.h> + #include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_blend.h> -#include <drm/drm_gem_atomic_helper.h> #include <drm/drm_fourcc.h> +#include <drm/drm_framebuffer.h> +#include <drm/drm_gem_atomic_helper.h> +#include <drm/drm_panic.h> +#include <drm/ttm/ttm_bo.h> #include "nouveau_bo.h" #include "nouveau_gem.h" +#include "tile.h" static void nv50_wndw_ctxdma_del(struct nv50_wndw_ctxdma *ctxdma) @@ -577,6 +583,114 @@ nv50_wndw_prepare_fb(struct drm_plane *plane, struct drm_plane_state *state) return 0; } +/* Only used by drm_panic get_scanout_buffer() and set_pixel(), so it is + * protected by the drm panic spinlock + */ +static u32 nv50_panic_blk_h; + +/* Return the framebuffer offset of the start of the block where pixel(x,y) is */ +static u32 +nv50_get_block_off(unsigned int x, unsigned int y, unsigned int pitch) +{ + u32 blk_x, blk_y, blk_columns; + + blk_columns = nouveau_get_width_in_blocks(pitch); + blk_x = (x * 4) / NV_TILE_GOB_WIDTH_BYTES; + blk_y = y / nv50_panic_blk_h; + + return ((blk_y * blk_columns) + blk_x) * NV_TILE_GOB_WIDTH_BYTES * nv50_panic_blk_h; +} + +/* Turing and later have 2 level of tiles inside the block */ +static void +nv50_set_pixel_swizzle(struct drm_scanout_buffer *sb, unsigned int x, + unsigned int y, u32 color) +{ + u32 blk_off, off, swizzle; + + blk_off = nv50_get_block_off(x, y, sb->pitch[0]); + + y = y % nv50_panic_blk_h; + + /* Inside the block, use the fast address swizzle to compute the offset + * For nvidia blocklinear, bit order is yn..y3 x3 y2 x2 y1 y0 x1 x0 + */ + swizzle = (x & 3) | (y & 3) << 2 | (x & 4) << 2 | (y & 4) << 3; + swizzle |= (x & 8) << 3 | (y >> 3) << 7; + off = blk_off + swizzle * 4; + + iosys_map_wr(&sb->map[0], off, u32, color); +} + +static void +nv50_set_pixel(struct drm_scanout_buffer *sb, unsigned int x, unsigned int y, + u32 color) +{ + u32 blk_off, off; + + blk_off = nv50_get_block_off(x, y, sb->width); + + x = x % (NV_TILE_GOB_WIDTH_BYTES / 4); + y = y % nv50_panic_blk_h; + off = blk_off + x * 4 + y * NV_TILE_GOB_WIDTH_BYTES; + + iosys_map_wr(&sb->map[0], off, u32, color); +} + +static int +nv50_wndw_get_scanout_buffer(struct drm_plane *plane, struct drm_scanout_buffer *sb) +{ + struct drm_framebuffer *fb; + struct nouveau_bo *nvbo; + struct nouveau_drm *drm = nouveau_drm(plane->dev); + u16 chipset = drm->client.device.info.chipset; + u8 family = drm->client.device.info.family; + u32 tile_mode; + u8 kind; + + if (!plane->state || !plane->state->fb) + return -EINVAL; + + fb = plane->state->fb; + nvbo = nouveau_gem_object(fb->obj[0]); + + /* Don't support compressed format, or multiplane yet. */ + if (nvbo->comp || fb->format->num_planes != 1) + return -EOPNOTSUPP; + + if (nouveau_bo_map(nvbo)) { + drm_warn(plane->dev, "nouveau bo map failed, panic won't be displayed\n"); + return -ENOMEM; + } + + if (nvbo->kmap.bo_kmap_type & TTM_BO_MAP_IOMEM_MASK) + iosys_map_set_vaddr_iomem(&sb->map[0], (void __iomem *)nvbo->kmap.virtual); + else + iosys_map_set_vaddr(&sb->map[0], nvbo->kmap.virtual); + + sb->height = fb->height; + sb->width = fb->width; + sb->pitch[0] = fb->pitches[0]; + sb->format = fb->format; + + nouveau_framebuffer_get_layout(fb, &tile_mode, &kind); + if (kind) { + /* If tiling is enabled, use set_pixel() to display correctly. + * Only handle 32bits format for now. + */ + if (fb->format->cpp[0] != 4) + return -EOPNOTSUPP; + nv50_panic_blk_h = nouveau_get_gob_height(family) * + nouveau_get_gobs_in_block(tile_mode, chipset); + + if (chipset >= 0x160) + sb->set_pixel = nv50_set_pixel_swizzle; + else + sb->set_pixel = nv50_set_pixel; + } + return 0; +} + static const struct drm_plane_helper_funcs nv50_wndw_helper = { .prepare_fb = nv50_wndw_prepare_fb, @@ -584,6 +698,14 @@ nv50_wndw_helper = { .atomic_check = nv50_wndw_atomic_check, }; +static const struct drm_plane_helper_funcs +nv50_wndw_primary_helper = { + .prepare_fb = nv50_wndw_prepare_fb, + .cleanup_fb = nv50_wndw_cleanup_fb, + .atomic_check = nv50_wndw_atomic_check, + .get_scanout_buffer = nv50_wndw_get_scanout_buffer, +}; + static void nv50_wndw_atomic_destroy_state(struct drm_plane *plane, struct drm_plane_state *state) @@ -732,7 +854,10 @@ nv50_wndw_new_(const struct nv50_wndw_func *func, struct drm_device *dev, return ret; } - drm_plane_helper_add(&wndw->plane, &nv50_wndw_helper); + if (type == DRM_PLANE_TYPE_PRIMARY) + drm_plane_helper_add(&wndw->plane, &nv50_wndw_primary_helper); + else + drm_plane_helper_add(&wndw->plane, &nv50_wndw_helper); if (wndw->func->ilut) { ret = nv50_lut_init(disp, mmu, &wndw->ilut); diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index 619a3efbe8c8..add006fc8d81 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c @@ -44,6 +44,7 @@ #include <nvif/if0011.h> #include <nvif/if0013.h> #include <dispnv50/crc.h> +#include <dispnv50/tile.h> int nouveau_display_vblank_enable(struct drm_crtc *crtc) @@ -220,69 +221,29 @@ nouveau_validate_decode_mod(struct nouveau_drm *drm, return 0; } -static inline uint32_t -nouveau_get_width_in_blocks(uint32_t stride) -{ - /* GOBs per block in the x direction is always one, and GOBs are - * 64 bytes wide - */ - static const uint32_t log_block_width = 6; - - return (stride + (1 << log_block_width) - 1) >> log_block_width; -} - -static inline uint32_t -nouveau_get_height_in_blocks(struct nouveau_drm *drm, - uint32_t height, - uint32_t log_block_height_in_gobs) -{ - uint32_t log_gob_height; - uint32_t log_block_height; - - BUG_ON(drm->client.device.info.family < NV_DEVICE_INFO_V0_TESLA); - - if (drm->client.device.info.family < NV_DEVICE_INFO_V0_FERMI) - log_gob_height = 2; - else - log_gob_height = 3; - - log_block_height = log_block_height_in_gobs + log_gob_height; - - return (height + (1 << log_block_height) - 1) >> log_block_height; -} - static int nouveau_check_bl_size(struct nouveau_drm *drm, struct nouveau_bo *nvbo, uint32_t offset, uint32_t stride, uint32_t h, uint32_t tile_mode) { - uint32_t gob_size, bw, bh; + uint32_t gob_size, bw, bh, gobs_in_block; uint64_t bl_size; BUG_ON(drm->client.device.info.family < NV_DEVICE_INFO_V0_TESLA); - if (drm->client.device.info.chipset >= 0xc0) { - if (tile_mode & 0xF) - return -EINVAL; - tile_mode >>= 4; - } - - if (tile_mode & 0xFFFFFFF0) + if (nouveau_check_tile_mode(tile_mode, drm->client.device.info.chipset)) return -EINVAL; - if (drm->client.device.info.family < NV_DEVICE_INFO_V0_FERMI) - gob_size = 256; - else - gob_size = 512; - + gobs_in_block = nouveau_get_gobs_in_block(tile_mode, drm->client.device.info.chipset); bw = nouveau_get_width_in_blocks(stride); - bh = nouveau_get_height_in_blocks(drm, h, tile_mode); + bh = nouveau_get_height_in_blocks(h, gobs_in_block, drm->client.device.info.family); + gob_size = nouveau_get_gob_size(drm->client.device.info.family); - bl_size = bw * bh * (1 << tile_mode) * gob_size; + bl_size = bw * bh * gobs_in_block * gob_size; - DRM_DEBUG_KMS("offset=%u stride=%u h=%u tile_mode=0x%02x bw=%u bh=%u gob_size=%u bl_size=%llu size=%zu\n", - offset, stride, h, tile_mode, bw, bh, gob_size, bl_size, - nvbo->bo.base.size); + DRM_DEBUG_KMS("offset=%u stride=%u h=%u gobs_in_block=%u bw=%u bh=%u gob_size=%u bl_size=%llu size=%zu\n", + offset, stride, h, gobs_in_block, bw, bh, gob_size, + bl_size, nvbo->bo.base.size); if (bl_size + offset > nvbo->bo.base.size) return -ERANGE; diff --git a/drivers/gpu/drm/vkms/vkms_output.c b/drivers/gpu/drm/vkms/vkms_output.c index 0a5a185aa0b0..25a99fde126c 100644 --- a/drivers/gpu/drm/vkms/vkms_output.c +++ b/drivers/gpu/drm/vkms/vkms_output.c @@ -92,7 +92,7 @@ int vkms_output_init(struct vkms_device *vkmsdev, int index) DRM_MODE_CONNECTOR_VIRTUAL); if (ret) { DRM_ERROR("Failed to init connector\n"); - goto err_connector; + return ret; } drm_connector_helper_add(connector, &vkms_conn_helper_funcs); @@ -131,8 +131,5 @@ err_attach: err_encoder: drm_connector_cleanup(connector); -err_connector: - drm_crtc_cleanup(crtc); - return ret; } |