Merge tag 'drm-misc-next-2025-08-28' of https://gitlab.freedesktop.org/drm/misc/kernel into drm-next

drm-misc-next for v6.18:

UAPI Changes:

atomic:
- Reallow no-op async page flips

Cross-subsystem Changes:

hid:
- i2c-hid: Make elan touch controllers power on after panel is enabled

video:
- Improve pixel-format handling for struct screen_info

Core Changes:

display:
- dp: Fix command length

Driver Changes:

amdxdna:
- Fixes

bridge:
- Add support for Radxa Ra620 plus DT bindings

msm:
- Fix VMA allocation

panel:
- ilitek-ili9881c: Refactor mode setting; Add support for Bestar
  BSD1218-A101KL68 LCD plus DT bindings
- lvds: Add support for Ampire AMP19201200B5TZQW-T03 to DT bindings

rockchip:
- dsi2: Add support for RK3576 plus DT bindings

stm:
- Clean up logging

vesadrm:
- Support 8-bit palette mode

Signed-off-by: Dave Airlie <airlied@redhat.com>

From: Thomas Zimmermann <tzimmermann@suse.de>
Link: https://lore.kernel.org/r/20250828065714.GA11906@linux.fritz.box
This commit is contained in:
Dave Airlie
2025-08-29 08:55:29 +10:00
31 changed files with 817 additions and 221 deletions

View File

@@ -223,13 +223,13 @@ Userspace components
Compiler
--------
Peano is an LLVM based open-source compiler for AMD XDNA Array compute tile
available at:
Peano is an LLVM based open-source single core compiler for AMD XDNA Array
compute tile. Peano is available at:
https://github.com/Xilinx/llvm-aie
The open-source IREE compiler supports graph compilation of ML models for AMD
NPU and uses Peano underneath. It is available at:
https://github.com/nod-ai/iree-amd-aie
IRON is an open-source array compiler for AMD XDNA Array based NPU which uses
Peano underneath. IRON is available at:
https://github.com/Xilinx/mlir-aie
Usermode Driver (UMD)
---------------------

View File

@@ -28,6 +28,7 @@ properties:
- enum:
- adi,adv7123
- dumb-vga-dac
- radxa,ra620
- ti,opa362
- ti,ths8134
- ti,ths8135

View File

@@ -18,6 +18,7 @@ properties:
- enum:
- ampire,am8001280g
- bananapi,lhr050h41
- bestar,bsd1218-a101kl68
- feixin,k101-im2byl02
- raspberrypi,dsi-7inch
- startek,kd050hdfia020

View File

@@ -41,6 +41,8 @@ properties:
- enum:
# Admatec 9904379 10.1" 1024x600 LVDS panel
- admatec,9904379
# Ampire AMP19201200B5TZQW-T03 10.1" WUXGA (1920x1200) color TFT LCD panel
- ampire,amp19201200b5tzqw-t03
- auo,b101ew05
# AUO G084SN05 V9 8.4" 800x600 LVDS panel
- auo,g084sn05

View File

@@ -12,6 +12,7 @@ maintainers:
properties:
compatible:
enum:
- rockchip,rk3576-mipi-dsi2
- rockchip,rk3588-mipi-dsi2
reg:

View File

@@ -221,6 +221,8 @@ patternProperties:
description: BeagleBoard.org Foundation
"^belling,.*":
description: Shanghai Belling Co., Ltd.
"^bestar,.*":
description: Shenzhen Bestar Electronic Technology Co., Ltd.
"^bhf,.*":
description: Beckhoff Automation GmbH & Co. KG
"^bigtreetech,.*":

View File

@@ -785,8 +785,9 @@ static int aie2_get_clock_metadata(struct amdxdna_client *client,
static int aie2_hwctx_status_cb(struct amdxdna_hwctx *hwctx, void *arg)
{
struct amdxdna_drm_query_hwctx __user *buf, *tmp __free(kfree) = NULL;
struct amdxdna_drm_query_hwctx *tmp __free(kfree) = NULL;
struct amdxdna_drm_get_info *get_info_args = arg;
struct amdxdna_drm_query_hwctx __user *buf;
if (get_info_args->buffer_size < sizeof(*tmp))
return -EINVAL;

View File

@@ -261,6 +261,11 @@ static const struct of_device_id simple_bridge_match[] = {
.timings = &default_bridge_timings,
.connector_type = DRM_MODE_CONNECTOR_VGA,
},
}, {
.compatible = "radxa,ra620",
.data = &(const struct simple_bridge_info) {
.connector_type = DRM_MODE_CONNECTOR_HDMIA,
},
}, {
.compatible = "ti,opa362",
.data = &(const struct simple_bridge_info) {

View File

@@ -3962,6 +3962,7 @@ int drm_edp_backlight_set_level(struct drm_dp_aux *aux, const struct drm_edp_bac
int ret;
unsigned int offset = DP_EDP_BACKLIGHT_BRIGHTNESS_MSB;
u8 buf[3] = { 0 };
size_t len = 2;
/* The panel uses the PWM for controlling brightness levels */
if (!(bl->aux_set || bl->luminance_set))
@@ -3974,6 +3975,7 @@ int drm_edp_backlight_set_level(struct drm_dp_aux *aux, const struct drm_edp_bac
buf[1] = (level & 0x00ff00) >> 8;
buf[2] = (level & 0xff0000) >> 16;
offset = DP_EDP_PANEL_TARGET_LUMINANCE_VALUE;
len = 3;
} else if (bl->lsb_reg_used) {
buf[0] = (level & 0xff00) >> 8;
buf[1] = (level & 0x00ff);
@@ -3981,7 +3983,7 @@ int drm_edp_backlight_set_level(struct drm_dp_aux *aux, const struct drm_edp_bac
buf[0] = level;
}
ret = drm_dp_dpcd_write_data(aux, offset, buf, sizeof(buf));
ret = drm_dp_dpcd_write_data(aux, offset, buf, len);
if (ret < 0) {
drm_err(aux->drm_dev,
"%s: Failed to write aux backlight level: %d\n",

View File

@@ -1078,19 +1078,20 @@ int drm_atomic_set_property(struct drm_atomic_state *state,
}
if (async_flip) {
/* check if the prop does a nop change */
if ((prop != config->prop_fb_id &&
prop != config->prop_in_fence_fd &&
prop != config->prop_fb_damage_clips)) {
ret = drm_atomic_plane_get_property(plane, plane_state,
prop, &old_val);
ret = drm_atomic_check_prop_changes(ret, old_val, prop_value, prop);
/* no-op changes are always allowed */
ret = drm_atomic_plane_get_property(plane, plane_state,
prop, &old_val);
ret = drm_atomic_check_prop_changes(ret, old_val, prop_value, prop);
/* fail everything that isn't no-op or a pure flip */
if (ret && prop != config->prop_fb_id &&
prop != config->prop_in_fence_fd &&
prop != config->prop_fb_damage_clips) {
break;
}
/* ask the driver if this non-primary plane is supported */
if (plane->type != DRM_PLANE_TYPE_PRIMARY) {
ret = -EINVAL;
if (ret && plane->type != DRM_PLANE_TYPE_PRIMARY) {
/* ask the driver if this non-primary plane is supported */
if (plane_funcs && plane_funcs->atomic_async_check)
ret = plane_funcs->atomic_async_check(plane, state, true);

View File

@@ -817,6 +817,40 @@ void drm_crtc_load_palette_8(struct drm_crtc *crtc, const struct drm_color_lut *
}
EXPORT_SYMBOL(drm_crtc_load_palette_8);
static void fill_palette_332(struct drm_crtc *crtc, u16 r, u16 g, u16 b,
drm_crtc_set_lut_func set_palette)
{
unsigned int i = (r << 5) | (g << 2) | b; /* 8-bit palette index */
/* Expand R (3-bit) G (3-bit) and B (2-bit) values to 16-bit values */
r = (r << 13) | (r << 10) | (r << 7) | (r << 4) | (r << 1) | (r >> 2);
g = (g << 13) | (g << 10) | (g << 7) | (g << 4) | (g << 1) | (g >> 2);
b = (b << 14) | (b << 12) | (b << 10) | (b << 8) | (b << 6) | (b << 4) | (b << 2) | b;
set_palette(crtc, i, r, g, b);
}
/**
* drm_crtc_fill_palette_332 - Programs a default palette for R332-like formats
* @crtc: The displaying CRTC
* @set_palette: Callback for programming the hardware gamma LUT
*
* Programs an RGB332 palette to hardware.
*/
void drm_crtc_fill_palette_332(struct drm_crtc *crtc, drm_crtc_set_lut_func set_palette)
{
unsigned int r, g, b;
/* Limits of 8-8-4 are the maximum number of values for each channel. */
for (r = 0; r < 8; ++r) {
for (g = 0; g < 8; ++g) {
for (b = 0; b < 4; ++b)
fill_palette_332(crtc, r, g, b, set_palette);
}
}
}
EXPORT_SYMBOL(drm_crtc_fill_palette_332);
static void fill_palette_8(struct drm_crtc *crtc, unsigned int i,
drm_crtc_set_lut_func set_palette)
{

View File

@@ -1243,6 +1243,9 @@ int drm_fb_blit(struct iosys_map *dst, const unsigned int *dst_pitch, uint32_t d
} else if (dst_format == DRM_FORMAT_BGRX8888) {
drm_fb_swab(dst, dst_pitch, src, fb, clip, false, state);
return 0;
} else if (dst_format == DRM_FORMAT_RGB332) {
drm_fb_xrgb8888_to_rgb332(dst, dst_pitch, src, fb, clip, state);
return 0;
}
}

View File

@@ -55,7 +55,8 @@ EXPORT_SYMBOL(drm_of_crtc_port_mask);
* and generate the DRM mask of CRTCs which may be attached to this
* encoder.
*
* See Documentation/devicetree/bindings/graph.txt for the bindings.
* See https://github.com/devicetree-org/dt-schema/blob/main/dtschema/schemas/graph.yaml
* for the bindings.
*/
uint32_t drm_of_find_possible_crtcs(struct drm_device *dev,
struct device_node *port)
@@ -106,7 +107,9 @@ EXPORT_SYMBOL_GPL(drm_of_component_match_add);
* Parse the platform device OF node and bind all the components associated
* with the master. Interface ports are added before the encoders in order to
* satisfy their .bind requirements
* See Documentation/devicetree/bindings/graph.txt for the bindings.
*
* See https://github.com/devicetree-org/dt-schema/blob/main/dtschema/schemas/graph.yaml
* for the bindings.
*
* Returns zero if successful, or one of the standard error codes if it fails.
*/

View File

@@ -134,6 +134,9 @@ void drm_panel_prepare(struct drm_panel *panel)
panel->prepared = true;
list_for_each_entry(follower, &panel->followers, list) {
if (!follower->funcs->panel_prepared)
continue;
ret = follower->funcs->panel_prepared(follower);
if (ret < 0)
dev_info(panel->dev, "%ps failed: %d\n",
@@ -179,6 +182,9 @@ void drm_panel_unprepare(struct drm_panel *panel)
mutex_lock(&panel->follower_lock);
list_for_each_entry(follower, &panel->followers, list) {
if (!follower->funcs->panel_unpreparing)
continue;
ret = follower->funcs->panel_unpreparing(follower);
if (ret < 0)
dev_info(panel->dev, "%ps failed: %d\n",
@@ -209,6 +215,7 @@ EXPORT_SYMBOL(drm_panel_unprepare);
*/
void drm_panel_enable(struct drm_panel *panel)
{
struct drm_panel_follower *follower;
int ret;
if (!panel)
@@ -219,10 +226,12 @@ void drm_panel_enable(struct drm_panel *panel)
return;
}
mutex_lock(&panel->follower_lock);
if (panel->funcs && panel->funcs->enable) {
ret = panel->funcs->enable(panel);
if (ret < 0)
return;
goto exit;
}
panel->enabled = true;
@@ -230,6 +239,19 @@ void drm_panel_enable(struct drm_panel *panel)
if (ret < 0)
DRM_DEV_INFO(panel->dev, "failed to enable backlight: %d\n",
ret);
list_for_each_entry(follower, &panel->followers, list) {
if (!follower->funcs->panel_enabled)
continue;
ret = follower->funcs->panel_enabled(follower);
if (ret < 0)
dev_info(panel->dev, "%ps failed: %d\n",
follower->funcs->panel_enabled, ret);
}
exit:
mutex_unlock(&panel->follower_lock);
}
EXPORT_SYMBOL(drm_panel_enable);
@@ -243,6 +265,7 @@ EXPORT_SYMBOL(drm_panel_enable);
*/
void drm_panel_disable(struct drm_panel *panel)
{
struct drm_panel_follower *follower;
int ret;
if (!panel)
@@ -262,6 +285,18 @@ void drm_panel_disable(struct drm_panel *panel)
return;
}
mutex_lock(&panel->follower_lock);
list_for_each_entry(follower, &panel->followers, list) {
if (!follower->funcs->panel_disabling)
continue;
ret = follower->funcs->panel_disabling(follower);
if (ret < 0)
dev_info(panel->dev, "%ps failed: %d\n",
follower->funcs->panel_disabling, ret);
}
ret = backlight_disable(panel->backlight);
if (ret < 0)
DRM_DEV_INFO(panel->dev, "failed to disable backlight: %d\n",
@@ -270,9 +305,12 @@ void drm_panel_disable(struct drm_panel *panel)
if (panel->funcs && panel->funcs->disable) {
ret = panel->funcs->disable(panel);
if (ret < 0)
return;
goto exit;
}
panel->enabled = false;
exit:
mutex_unlock(&panel->follower_lock);
}
EXPORT_SYMBOL(drm_panel_disable);
@@ -539,13 +577,13 @@ EXPORT_SYMBOL(drm_is_panel_follower);
* @follower_dev: The 'struct device' for the follower.
* @follower: The panel follower descriptor for the follower.
*
* A panel follower is called right after preparing the panel and right before
* unpreparing the panel. It's primary intention is to power on an associated
* touchscreen, though it could be used for any similar devices. Multiple
* devices are allowed the follow the same panel.
* A panel follower is called right after preparing/enabling the panel and right
* before unpreparing/disabling the panel. It's primary intention is to power on
* an associated touchscreen, though it could be used for any similar devices.
* Multiple devices are allowed the follow the same panel.
*
* If a follower is added to a panel that's already been turned on, the
* follower's prepare callback is called right away.
* If a follower is added to a panel that's already been prepared/enabled, the
* follower's prepared/enabled callback is called right away.
*
* The "panel" property of the follower points to the panel to be followed.
*
@@ -569,12 +607,18 @@ int drm_panel_add_follower(struct device *follower_dev,
mutex_lock(&panel->follower_lock);
list_add_tail(&follower->list, &panel->followers);
if (panel->prepared) {
if (panel->prepared && follower->funcs->panel_prepared) {
ret = follower->funcs->panel_prepared(follower);
if (ret < 0)
dev_info(panel->dev, "%ps failed: %d\n",
follower->funcs->panel_prepared, ret);
}
if (panel->enabled && follower->funcs->panel_enabled) {
ret = follower->funcs->panel_enabled(follower);
if (ret < 0)
dev_info(panel->dev, "%ps failed: %d\n",
follower->funcs->panel_enabled, ret);
}
mutex_unlock(&panel->follower_lock);
@@ -587,7 +631,8 @@ EXPORT_SYMBOL(drm_panel_add_follower);
* @follower: The panel follower descriptor for the follower.
*
* Undo drm_panel_add_follower(). This includes calling the follower's
* unprepare function if we're removed from a panel that's currently prepared.
* unpreparing/disabling function if we're removed from a panel that's currently
* prepared/enabled.
*
* Return: 0 or an error code.
*/
@@ -598,7 +643,13 @@ void drm_panel_remove_follower(struct drm_panel_follower *follower)
mutex_lock(&panel->follower_lock);
if (panel->prepared) {
if (panel->enabled && follower->funcs->panel_disabling) {
ret = follower->funcs->panel_disabling(follower);
if (ret < 0)
dev_info(panel->dev, "%ps failed: %d\n",
follower->funcs->panel_disabling, ret);
}
if (panel->prepared && follower->funcs->panel_unpreparing) {
ret = follower->funcs->panel_unpreparing(follower);
if (ret < 0)
dev_info(panel->dev, "%ps failed: %d\n",

View File

@@ -371,12 +371,6 @@ struct drm_gpuva *
msm_gem_vma_new(struct drm_gpuvm *gpuvm, struct drm_gem_object *obj,
u64 offset, u64 range_start, u64 range_end)
{
struct drm_gpuva_op_map op_map = {
.va.addr = range_start,
.va.range = range_end - range_start,
.gem.obj = obj,
.gem.offset = offset,
};
struct msm_gem_vm *vm = to_msm_vm(gpuvm);
struct drm_gpuvm_bo *vm_bo;
struct msm_gem_vma *vma;
@@ -405,6 +399,13 @@ msm_gem_vma_new(struct drm_gpuvm *gpuvm, struct drm_gem_object *obj,
if (obj)
GEM_WARN_ON((range_end - range_start) > obj->size);
struct drm_gpuva_op_map op_map = {
.va.addr = range_start,
.va.range = range_end - range_start,
.gem.obj = obj,
.gem.offset = offset,
};
drm_gpuva_init_from_op(&vma->base, &op_map);
vma->mapped = false;

View File

@@ -1417,6 +1417,200 @@ static const struct ili9881c_instr rpi_7inch_init[] = {
ILI9881C_COMMAND_INSTR(0xD3, 0x39),
};
static const struct ili9881c_instr bsd1218_a101kl68_init[] = {
ILI9881C_SWITCH_PAGE_INSTR(3),
ILI9881C_COMMAND_INSTR(0x01, 0x00),
ILI9881C_COMMAND_INSTR(0x02, 0x00),
ILI9881C_COMMAND_INSTR(0x03, 0x55),
ILI9881C_COMMAND_INSTR(0x04, 0x55),
ILI9881C_COMMAND_INSTR(0x05, 0x03),
ILI9881C_COMMAND_INSTR(0x06, 0x06),
ILI9881C_COMMAND_INSTR(0x07, 0x00),
ILI9881C_COMMAND_INSTR(0x08, 0x07),
ILI9881C_COMMAND_INSTR(0x09, 0x00),
ILI9881C_COMMAND_INSTR(0x0a, 0x00),
ILI9881C_COMMAND_INSTR(0x0b, 0x00),
ILI9881C_COMMAND_INSTR(0x0c, 0x00),
ILI9881C_COMMAND_INSTR(0x0d, 0x00),
ILI9881C_COMMAND_INSTR(0x0e, 0x00),
ILI9881C_COMMAND_INSTR(0x0f, 0x00),
ILI9881C_COMMAND_INSTR(0x10, 0x00),
ILI9881C_COMMAND_INSTR(0x11, 0x00),
ILI9881C_COMMAND_INSTR(0x12, 0x00),
ILI9881C_COMMAND_INSTR(0x13, 0x00),
ILI9881C_COMMAND_INSTR(0x14, 0x00),
ILI9881C_COMMAND_INSTR(0x15, 0x00),
ILI9881C_COMMAND_INSTR(0x16, 0x00),
ILI9881C_COMMAND_INSTR(0x17, 0x00),
ILI9881C_COMMAND_INSTR(0x18, 0x00),
ILI9881C_COMMAND_INSTR(0x19, 0x00),
ILI9881C_COMMAND_INSTR(0x1a, 0x00),
ILI9881C_COMMAND_INSTR(0x1b, 0x00),
ILI9881C_COMMAND_INSTR(0x1c, 0x00),
ILI9881C_COMMAND_INSTR(0x1d, 0x00),
ILI9881C_COMMAND_INSTR(0x1e, 0xc0),
ILI9881C_COMMAND_INSTR(0x1f, 0x80),
ILI9881C_COMMAND_INSTR(0x20, 0x04),
ILI9881C_COMMAND_INSTR(0x21, 0x03),
ILI9881C_COMMAND_INSTR(0x22, 0x00),
ILI9881C_COMMAND_INSTR(0x23, 0x00),
ILI9881C_COMMAND_INSTR(0x24, 0x00),
ILI9881C_COMMAND_INSTR(0x25, 0x00),
ILI9881C_COMMAND_INSTR(0x26, 0x00),
ILI9881C_COMMAND_INSTR(0x27, 0x00),
ILI9881C_COMMAND_INSTR(0x28, 0x33),
ILI9881C_COMMAND_INSTR(0x29, 0x33),
ILI9881C_COMMAND_INSTR(0x2a, 0x00),
ILI9881C_COMMAND_INSTR(0x2b, 0x00),
ILI9881C_COMMAND_INSTR(0x2c, 0x00),
ILI9881C_COMMAND_INSTR(0x2d, 0x00),
ILI9881C_COMMAND_INSTR(0x2e, 0x00),
ILI9881C_COMMAND_INSTR(0x2f, 0x00),
ILI9881C_COMMAND_INSTR(0x30, 0x00),
ILI9881C_COMMAND_INSTR(0x31, 0x00),
ILI9881C_COMMAND_INSTR(0x32, 0x00),
ILI9881C_COMMAND_INSTR(0x33, 0x00),
ILI9881C_COMMAND_INSTR(0x34, 0x04),
ILI9881C_COMMAND_INSTR(0x35, 0x00),
ILI9881C_COMMAND_INSTR(0x36, 0x00),
ILI9881C_COMMAND_INSTR(0x37, 0x00),
ILI9881C_COMMAND_INSTR(0x38, 0x3c),
ILI9881C_COMMAND_INSTR(0x39, 0x00),
ILI9881C_COMMAND_INSTR(0x3a, 0x00),
ILI9881C_COMMAND_INSTR(0x3b, 0x00),
ILI9881C_COMMAND_INSTR(0x3c, 0x00),
ILI9881C_COMMAND_INSTR(0x3d, 0x00),
ILI9881C_COMMAND_INSTR(0x3e, 0x00),
ILI9881C_COMMAND_INSTR(0x3f, 0x00),
ILI9881C_COMMAND_INSTR(0x40, 0x00),
ILI9881C_COMMAND_INSTR(0x41, 0x00),
ILI9881C_COMMAND_INSTR(0x42, 0x00),
ILI9881C_COMMAND_INSTR(0x43, 0x00),
ILI9881C_COMMAND_INSTR(0x44, 0x00),
ILI9881C_COMMAND_INSTR(0x50, 0x00),
ILI9881C_COMMAND_INSTR(0x51, 0x11),
ILI9881C_COMMAND_INSTR(0x52, 0x44),
ILI9881C_COMMAND_INSTR(0x53, 0x55),
ILI9881C_COMMAND_INSTR(0x54, 0x88),
ILI9881C_COMMAND_INSTR(0x55, 0xab),
ILI9881C_COMMAND_INSTR(0x56, 0x00),
ILI9881C_COMMAND_INSTR(0x57, 0x11),
ILI9881C_COMMAND_INSTR(0x58, 0x22),
ILI9881C_COMMAND_INSTR(0x59, 0x33),
ILI9881C_COMMAND_INSTR(0x5a, 0x44),
ILI9881C_COMMAND_INSTR(0x5b, 0x55),
ILI9881C_COMMAND_INSTR(0x5c, 0x66),
ILI9881C_COMMAND_INSTR(0x5d, 0x77),
ILI9881C_COMMAND_INSTR(0x5e, 0x00),
ILI9881C_COMMAND_INSTR(0x5f, 0x02),
ILI9881C_COMMAND_INSTR(0x60, 0x02),
ILI9881C_COMMAND_INSTR(0x61, 0x0a),
ILI9881C_COMMAND_INSTR(0x62, 0x09),
ILI9881C_COMMAND_INSTR(0x63, 0x08),
ILI9881C_COMMAND_INSTR(0x64, 0x13),
ILI9881C_COMMAND_INSTR(0x65, 0x12),
ILI9881C_COMMAND_INSTR(0x66, 0x11),
ILI9881C_COMMAND_INSTR(0x67, 0x10),
ILI9881C_COMMAND_INSTR(0x68, 0x0f),
ILI9881C_COMMAND_INSTR(0x69, 0x0e),
ILI9881C_COMMAND_INSTR(0x6a, 0x0d),
ILI9881C_COMMAND_INSTR(0x6b, 0x0c),
ILI9881C_COMMAND_INSTR(0x6c, 0x06),
ILI9881C_COMMAND_INSTR(0x6d, 0x07),
ILI9881C_COMMAND_INSTR(0x6e, 0x02),
ILI9881C_COMMAND_INSTR(0x6f, 0x02),
ILI9881C_COMMAND_INSTR(0x70, 0x02),
ILI9881C_COMMAND_INSTR(0x71, 0x02),
ILI9881C_COMMAND_INSTR(0x72, 0x02),
ILI9881C_COMMAND_INSTR(0x73, 0x02),
ILI9881C_COMMAND_INSTR(0x74, 0x02),
ILI9881C_COMMAND_INSTR(0x75, 0x02),
ILI9881C_COMMAND_INSTR(0x76, 0x02),
ILI9881C_COMMAND_INSTR(0x77, 0x0a),
ILI9881C_COMMAND_INSTR(0x78, 0x06),
ILI9881C_COMMAND_INSTR(0x79, 0x07),
ILI9881C_COMMAND_INSTR(0x7a, 0x10),
ILI9881C_COMMAND_INSTR(0x7b, 0x11),
ILI9881C_COMMAND_INSTR(0x7c, 0x12),
ILI9881C_COMMAND_INSTR(0x7d, 0x13),
ILI9881C_COMMAND_INSTR(0x7e, 0x0c),
ILI9881C_COMMAND_INSTR(0x7f, 0x0d),
ILI9881C_COMMAND_INSTR(0x80, 0x0e),
ILI9881C_COMMAND_INSTR(0x81, 0x0f),
ILI9881C_COMMAND_INSTR(0x82, 0x09),
ILI9881C_COMMAND_INSTR(0x83, 0x08),
ILI9881C_COMMAND_INSTR(0x84, 0x02),
ILI9881C_COMMAND_INSTR(0x85, 0x02),
ILI9881C_COMMAND_INSTR(0x86, 0x02),
ILI9881C_COMMAND_INSTR(0x87, 0x02),
ILI9881C_COMMAND_INSTR(0x88, 0x02),
ILI9881C_COMMAND_INSTR(0x89, 0x02),
ILI9881C_COMMAND_INSTR(0x8a, 0x02),
ILI9881C_SWITCH_PAGE_INSTR(4),
ILI9881C_COMMAND_INSTR(0x6e, 0x2a),
ILI9881C_COMMAND_INSTR(0x6f, 0x37),
ILI9881C_COMMAND_INSTR(0x3a, 0x24),
ILI9881C_COMMAND_INSTR(0x8d, 0x19),
ILI9881C_COMMAND_INSTR(0x87, 0xba),
ILI9881C_COMMAND_INSTR(0xb2, 0xd1),
ILI9881C_COMMAND_INSTR(0x88, 0x0b),
ILI9881C_COMMAND_INSTR(0x38, 0x01),
ILI9881C_COMMAND_INSTR(0x39, 0x00),
ILI9881C_COMMAND_INSTR(0xb5, 0x02),
ILI9881C_COMMAND_INSTR(0x31, 0x25),
ILI9881C_COMMAND_INSTR(0x3b, 0x98),
ILI9881C_SWITCH_PAGE_INSTR(1),
ILI9881C_COMMAND_INSTR(0x22, 0x0a),
ILI9881C_COMMAND_INSTR(0x31, 0x0c),
ILI9881C_COMMAND_INSTR(0x53, 0x40),
ILI9881C_COMMAND_INSTR(0x55, 0x45),
ILI9881C_COMMAND_INSTR(0x50, 0xb7),
ILI9881C_COMMAND_INSTR(0x51, 0xb2),
ILI9881C_COMMAND_INSTR(0x60, 0x07),
ILI9881C_COMMAND_INSTR(0xa0, 0x22),
ILI9881C_COMMAND_INSTR(0xa1, 0x3f),
ILI9881C_COMMAND_INSTR(0xa2, 0x4e),
ILI9881C_COMMAND_INSTR(0xa3, 0x17),
ILI9881C_COMMAND_INSTR(0xa4, 0x1a),
ILI9881C_COMMAND_INSTR(0xa5, 0x2d),
ILI9881C_COMMAND_INSTR(0xa6, 0x21),
ILI9881C_COMMAND_INSTR(0xa7, 0x22),
ILI9881C_COMMAND_INSTR(0xa8, 0xc4),
ILI9881C_COMMAND_INSTR(0xa9, 0x1b),
ILI9881C_COMMAND_INSTR(0xaa, 0x25),
ILI9881C_COMMAND_INSTR(0xab, 0xa7),
ILI9881C_COMMAND_INSTR(0xac, 0x1a),
ILI9881C_COMMAND_INSTR(0xad, 0x19),
ILI9881C_COMMAND_INSTR(0xae, 0x4b),
ILI9881C_COMMAND_INSTR(0xaf, 0x1f),
ILI9881C_COMMAND_INSTR(0xb0, 0x2a),
ILI9881C_COMMAND_INSTR(0xb1, 0x59),
ILI9881C_COMMAND_INSTR(0xb2, 0x64),
ILI9881C_COMMAND_INSTR(0xb3, 0x3f),
ILI9881C_COMMAND_INSTR(0xc0, 0x22),
ILI9881C_COMMAND_INSTR(0xc1, 0x48),
ILI9881C_COMMAND_INSTR(0xc2, 0x59),
ILI9881C_COMMAND_INSTR(0xc3, 0x15),
ILI9881C_COMMAND_INSTR(0xc4, 0x15),
ILI9881C_COMMAND_INSTR(0xc5, 0x28),
ILI9881C_COMMAND_INSTR(0xc6, 0x1c),
ILI9881C_COMMAND_INSTR(0xc7, 0x1e),
ILI9881C_COMMAND_INSTR(0xc8, 0xc4),
ILI9881C_COMMAND_INSTR(0xc9, 0x1c),
ILI9881C_COMMAND_INSTR(0xca, 0x2b),
ILI9881C_COMMAND_INSTR(0xcb, 0xa3),
ILI9881C_COMMAND_INSTR(0xcc, 0x1f),
ILI9881C_COMMAND_INSTR(0xcd, 0x1e),
ILI9881C_COMMAND_INSTR(0xce, 0x52),
ILI9881C_COMMAND_INSTR(0xcf, 0x24),
ILI9881C_COMMAND_INSTR(0xd0, 0x2a),
ILI9881C_COMMAND_INSTR(0xd1, 0x58),
ILI9881C_COMMAND_INSTR(0xd2, 0x68),
ILI9881C_COMMAND_INSTR(0xd3, 0x3f),
};
static inline struct ili9881c *panel_to_ili9881c(struct drm_panel *panel)
{
return container_of(panel, struct ili9881c, panel);
@@ -1433,33 +1627,24 @@ static inline struct ili9881c *panel_to_ili9881c(struct drm_panel *panel)
* So before any attempt at sending a command or data, we have to be
* sure if we're in the right page or not.
*/
static int ili9881c_switch_page(struct ili9881c *ctx, u8 page)
static void ili9881c_switch_page(struct mipi_dsi_multi_context *mctx, u8 page)
{
u8 buf[4] = { 0xff, 0x98, 0x81, page };
int ret;
ret = mipi_dsi_dcs_write_buffer(ctx->dsi, buf, sizeof(buf));
if (ret < 0)
return ret;
return 0;
mipi_dsi_dcs_write_buffer_multi(mctx, buf, sizeof(buf));
}
static int ili9881c_send_cmd_data(struct ili9881c *ctx, u8 cmd, u8 data)
static void ili9881c_send_cmd_data(struct mipi_dsi_multi_context *mctx, u8 cmd, u8 data)
{
u8 buf[2] = { cmd, data };
int ret;
ret = mipi_dsi_dcs_write_buffer(ctx->dsi, buf, sizeof(buf));
if (ret < 0)
return ret;
return 0;
mipi_dsi_dcs_write_buffer_multi(mctx, buf, sizeof(buf));
}
static int ili9881c_prepare(struct drm_panel *panel)
{
struct ili9881c *ctx = panel_to_ili9881c(panel);
struct mipi_dsi_multi_context mctx = { .dsi = ctx->dsi };
unsigned int i;
int ret;
@@ -1480,61 +1665,39 @@ static int ili9881c_prepare(struct drm_panel *panel)
const struct ili9881c_instr *instr = &ctx->desc->init[i];
if (instr->op == ILI9881C_SWITCH_PAGE)
ret = ili9881c_switch_page(ctx, instr->arg.page);
ili9881c_switch_page(&mctx, instr->arg.page);
else if (instr->op == ILI9881C_COMMAND)
ret = ili9881c_send_cmd_data(ctx, instr->arg.cmd.cmd,
instr->arg.cmd.data);
if (ret)
return ret;
ili9881c_send_cmd_data(&mctx, instr->arg.cmd.cmd,
instr->arg.cmd.data);
}
ret = ili9881c_switch_page(ctx, 0);
if (ret)
return ret;
ili9881c_switch_page(&mctx, 0);
if (ctx->address_mode) {
ret = mipi_dsi_dcs_write(ctx->dsi, MIPI_DCS_SET_ADDRESS_MODE,
&ctx->address_mode,
sizeof(ctx->address_mode));
if (ret < 0)
return ret;
}
if (ctx->address_mode)
ili9881c_send_cmd_data(&mctx, MIPI_DCS_SET_ADDRESS_MODE,
ctx->address_mode);
ret = mipi_dsi_dcs_set_tear_on(ctx->dsi, MIPI_DSI_DCS_TEAR_MODE_VBLANK);
if (ret)
return ret;
ret = mipi_dsi_dcs_exit_sleep_mode(ctx->dsi);
if (ret)
return ret;
mipi_dsi_dcs_set_tear_on_multi(&mctx, MIPI_DSI_DCS_TEAR_MODE_VBLANK);
mipi_dsi_dcs_exit_sleep_mode_multi(&mctx);
mipi_dsi_msleep(&mctx, 120);
mipi_dsi_dcs_set_display_on_multi(&mctx);
if (mctx.accum_err)
goto disable_power;
return 0;
}
static int ili9881c_enable(struct drm_panel *panel)
{
struct ili9881c *ctx = panel_to_ili9881c(panel);
msleep(120);
mipi_dsi_dcs_set_display_on(ctx->dsi);
return 0;
}
static int ili9881c_disable(struct drm_panel *panel)
{
struct ili9881c *ctx = panel_to_ili9881c(panel);
return mipi_dsi_dcs_set_display_off(ctx->dsi);
disable_power:
regulator_disable(ctx->power);
return mctx.accum_err;
}
static int ili9881c_unprepare(struct drm_panel *panel)
{
struct ili9881c *ctx = panel_to_ili9881c(panel);
struct mipi_dsi_multi_context mctx = { .dsi = ctx->dsi };
mipi_dsi_dcs_enter_sleep_mode(ctx->dsi);
mipi_dsi_dcs_set_display_off_multi(&mctx);
mipi_dsi_dcs_enter_sleep_mode_multi(&mctx);
regulator_disable(ctx->power);
gpiod_set_value_cansleep(ctx->reset, 1);
@@ -1660,6 +1823,23 @@ static const struct drm_display_mode rpi_7inch_default_mode = {
.height_mm = 151,
};
static const struct drm_display_mode bsd1218_a101kl68_default_mode = {
.clock = 70000,
.hdisplay = 800,
.hsync_start = 800 + 40,
.hsync_end = 800 + 40 + 20,
.htotal = 800 + 40 + 20 + 20,
.vdisplay = 1280,
.vsync_start = 1280 + 20,
.vsync_end = 1280 + 20 + 4,
.vtotal = 1280 + 20 + 4 + 20,
.width_mm = 120,
.height_mm = 170,
};
static int ili9881c_get_modes(struct drm_panel *panel,
struct drm_connector *connector)
{
@@ -1706,8 +1886,6 @@ static enum drm_panel_orientation ili9881c_get_orientation(struct drm_panel *pan
static const struct drm_panel_funcs ili9881c_funcs = {
.prepare = ili9881c_prepare,
.unprepare = ili9881c_unprepare,
.enable = ili9881c_enable,
.disable = ili9881c_disable,
.get_modes = ili9881c_get_modes,
.get_orientation = ili9881c_get_orientation,
};
@@ -1830,8 +2008,18 @@ static const struct ili9881c_desc rpi_7inch_desc = {
.lanes = 2,
};
static const struct ili9881c_desc bsd1218_a101kl68_desc = {
.init = bsd1218_a101kl68_init,
.init_length = ARRAY_SIZE(bsd1218_a101kl68_init),
.mode = &bsd1218_a101kl68_default_mode,
.mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_NO_EOT_PACKET,
.lanes = 4,
};
static const struct of_device_id ili9881c_of_match[] = {
{ .compatible = "bananapi,lhr050h41", .data = &lhr050h41_desc },
{ .compatible = "bestar,bsd1218-a101kl68", .data = &bsd1218_a101kl68_desc },
{ .compatible = "feixin,k101-im2byl02", .data = &k101_im2byl02_desc },
{ .compatible = "startek,kd050hdfia020", .data = &kd050hdfia020_desc },
{ .compatible = "tdo,tl050hdv35", .data = &tl050hdv35_desc },

View File

@@ -233,8 +233,10 @@ static int jdi_panel_prepare(struct drm_panel *panel)
mipi_dsi_dual(mipi_dsi_dcs_set_display_on_multi,
&dsi_ctx, jdi->link1, jdi->link2);
if (dsi_ctx.accum_err < 0)
if (dsi_ctx.accum_err < 0) {
err = dsi_ctx.accum_err;
goto poweroff;
}
jdi->link1->mode_flags &= ~MIPI_DSI_MODE_LPM;
jdi->link2->mode_flags &= ~MIPI_DSI_MODE_LPM;

View File

@@ -437,6 +437,15 @@ static void dw_mipi_dsi2_rockchip_remove(struct platform_device *pdev)
dw_mipi_dsi2_remove(dsi2->dmd);
}
static const struct dsigrf_reg rk3576_dsi_grf_reg_fields[MAX_FIELDS] = {
[TXREQCLKHS_EN] = { 0x0028, 1, 1 },
[GATING_EN] = { 0x0028, 0, 0 },
[IPI_SHUTDN] = { 0x0028, 3, 3 },
[IPI_COLORM] = { 0x0028, 2, 2 },
[IPI_COLOR_DEPTH] = { 0x0028, 8, 11 },
[IPI_FORMAT] = { 0x0028, 4, 7 },
};
static const struct dsigrf_reg rk3588_dsi0_grf_reg_fields[MAX_FIELDS] = {
[TXREQCLKHS_EN] = { 0x0000, 11, 11 },
[GATING_EN] = { 0x0000, 10, 10 },
@@ -455,6 +464,15 @@ static const struct dsigrf_reg rk3588_dsi1_grf_reg_fields[MAX_FIELDS] = {
[IPI_FORMAT] = { 0x0004, 0, 3 },
};
static const struct rockchip_dw_dsi2_chip_data rk3576_chip_data[] = {
{
.reg = 0x27d80000,
.grf_regs = rk3576_dsi_grf_reg_fields,
.max_bit_rate_per_lane = 2500000ULL,
},
{ /* sentinel */ }
};
static const struct rockchip_dw_dsi2_chip_data rk3588_chip_data[] = {
{
.reg = 0xfde20000,
@@ -470,6 +488,9 @@ static const struct rockchip_dw_dsi2_chip_data rk3588_chip_data[] = {
static const struct of_device_id dw_mipi_dsi2_rockchip_dt_ids[] = {
{
.compatible = "rockchip,rk3576-mipi-dsi2",
.data = &rk3576_chip_data,
}, {
.compatible = "rockchip,rk3588-mipi-dsi2",
.data = &rk3588_chip_data,
},

View File

@@ -641,7 +641,7 @@ static inline void ltdc_set_ycbcr_config(struct drm_plane *plane, u32 drm_pix_fm
break;
default:
/* RGB or not a YCbCr supported format */
DRM_ERROR("Unsupported pixel format: %u\n", drm_pix_fmt);
drm_err(plane->dev, "Unsupported pixel format: %u\n", drm_pix_fmt);
return;
}
@@ -664,18 +664,19 @@ static inline void ltdc_set_ycbcr_coeffs(struct drm_plane *plane)
u32 lofs = plane->index * LAY_OFS;
if (enc != DRM_COLOR_YCBCR_BT601 && enc != DRM_COLOR_YCBCR_BT709) {
DRM_ERROR("color encoding %d not supported, use bt601 by default\n", enc);
drm_err(plane->dev, "color encoding %d not supported, use bt601 by default\n", enc);
/* set by default color encoding to DRM_COLOR_YCBCR_BT601 */
enc = DRM_COLOR_YCBCR_BT601;
}
if (ran != DRM_COLOR_YCBCR_LIMITED_RANGE && ran != DRM_COLOR_YCBCR_FULL_RANGE) {
DRM_ERROR("color range %d not supported, use limited range by default\n", ran);
drm_err(plane->dev,
"color range %d not supported, use limited range by default\n", ran);
/* set by default color range to DRM_COLOR_YCBCR_LIMITED_RANGE */
ran = DRM_COLOR_YCBCR_LIMITED_RANGE;
}
DRM_DEBUG_DRIVER("Color encoding=%d, range=%d\n", enc, ran);
drm_err(plane->dev, "Color encoding=%d, range=%d\n", enc, ran);
regmap_write(ldev->regmap, LTDC_L1CYR0R + lofs,
ltdc_ycbcr2rgb_coeffs[enc][ran][0]);
regmap_write(ldev->regmap, LTDC_L1CYR1R + lofs,
@@ -774,7 +775,7 @@ static void ltdc_crtc_atomic_enable(struct drm_crtc *crtc,
struct ltdc_device *ldev = crtc_to_ltdc(crtc);
struct drm_device *ddev = crtc->dev;
DRM_DEBUG_DRIVER("\n");
drm_dbg_driver(crtc->dev, "\n");
pm_runtime_get_sync(ddev->dev);
@@ -798,7 +799,7 @@ static void ltdc_crtc_atomic_disable(struct drm_crtc *crtc,
struct drm_device *ddev = crtc->dev;
int layer_index = 0;
DRM_DEBUG_DRIVER("\n");
drm_dbg_driver(crtc->dev, "\n");
drm_crtc_vblank_off(crtc);
@@ -837,7 +838,7 @@ ltdc_crtc_mode_valid(struct drm_crtc *crtc,
result = clk_round_rate(ldev->pixel_clk, target);
DRM_DEBUG_DRIVER("clk rate target %d, available %d\n", target, result);
drm_dbg_driver(crtc->dev, "clk rate target %d, available %d\n", target, result);
/* Filter modes according to the max frequency supported by the pads */
if (result > ldev->caps.pad_max_freq_hz)
@@ -872,14 +873,14 @@ static bool ltdc_crtc_mode_fixup(struct drm_crtc *crtc,
int rate = mode->clock * 1000;
if (clk_set_rate(ldev->pixel_clk, rate) < 0) {
DRM_ERROR("Cannot set rate (%dHz) for pixel clk\n", rate);
drm_err(crtc->dev, "Cannot set rate (%dHz) for pixel clk\n", rate);
return false;
}
adjusted_mode->clock = clk_get_rate(ldev->pixel_clk) / 1000;
DRM_DEBUG_DRIVER("requested clock %dkHz, adjusted clock %dkHz\n",
mode->clock, adjusted_mode->clock);
drm_dbg_driver(crtc->dev, "requested clock %dkHz, adjusted clock %dkHz\n",
mode->clock, adjusted_mode->clock);
return true;
}
@@ -934,20 +935,20 @@ static void ltdc_crtc_mode_set_nofb(struct drm_crtc *crtc)
if (!pm_runtime_active(ddev->dev)) {
ret = pm_runtime_get_sync(ddev->dev);
if (ret) {
DRM_ERROR("Failed to set mode, cannot get sync\n");
drm_err(crtc->dev, "Failed to set mode, cannot get sync\n");
return;
}
}
DRM_DEBUG_DRIVER("CRTC:%d mode:%s\n", crtc->base.id, mode->name);
DRM_DEBUG_DRIVER("Video mode: %dx%d", mode->hdisplay, mode->vdisplay);
DRM_DEBUG_DRIVER(" hfp %d hbp %d hsl %d vfp %d vbp %d vsl %d\n",
mode->hsync_start - mode->hdisplay,
mode->htotal - mode->hsync_end,
mode->hsync_end - mode->hsync_start,
mode->vsync_start - mode->vdisplay,
mode->vtotal - mode->vsync_end,
mode->vsync_end - mode->vsync_start);
drm_dbg_driver(crtc->dev, "CRTC:%d mode:%s\n", crtc->base.id, mode->name);
drm_dbg_driver(crtc->dev, "Video mode: %dx%d", mode->hdisplay, mode->vdisplay);
drm_dbg_driver(crtc->dev, " hfp %d hbp %d hsl %d vfp %d vbp %d vsl %d\n",
mode->hsync_start - mode->hdisplay,
mode->htotal - mode->hsync_end,
mode->hsync_end - mode->hsync_start,
mode->vsync_start - mode->vdisplay,
mode->vtotal - mode->vsync_end,
mode->vsync_end - mode->vsync_start);
/* Convert video timings to ltdc timings */
hsync = mode->hsync_end - mode->hsync_start - 1;
@@ -1033,7 +1034,7 @@ static void ltdc_crtc_atomic_flush(struct drm_crtc *crtc,
struct drm_device *ddev = crtc->dev;
struct drm_pending_vblank_event *event = crtc->state->event;
DRM_DEBUG_ATOMIC("\n");
drm_dbg_atomic(crtc->dev, "\n");
ltdc_crtc_update_clut(crtc);
@@ -1121,7 +1122,7 @@ static int ltdc_crtc_enable_vblank(struct drm_crtc *crtc)
struct ltdc_device *ldev = crtc_to_ltdc(crtc);
struct drm_crtc_state *state = crtc->state;
DRM_DEBUG_DRIVER("\n");
drm_dbg_driver(crtc->dev, "\n");
if (state->enable)
regmap_set_bits(ldev->regmap, LTDC_IER, IER_LIE);
@@ -1135,7 +1136,7 @@ static void ltdc_crtc_disable_vblank(struct drm_crtc *crtc)
{
struct ltdc_device *ldev = crtc_to_ltdc(crtc);
DRM_DEBUG_DRIVER("\n");
drm_dbg_driver(crtc->dev, "\n");
regmap_clear_bits(ldev->regmap, LTDC_IER, IER_LIE);
}
@@ -1144,11 +1145,11 @@ static int ltdc_crtc_set_crc_source(struct drm_crtc *crtc, const char *source)
struct ltdc_device *ldev;
int ret;
DRM_DEBUG_DRIVER("\n");
if (!crtc)
return -ENODEV;
drm_dbg_driver(crtc->dev, "\n");
ldev = crtc_to_ltdc(crtc);
if (source && strcmp(source, "auto") == 0) {
@@ -1168,14 +1169,14 @@ static int ltdc_crtc_set_crc_source(struct drm_crtc *crtc, const char *source)
static int ltdc_crtc_verify_crc_source(struct drm_crtc *crtc,
const char *source, size_t *values_cnt)
{
DRM_DEBUG_DRIVER("\n");
if (!crtc)
return -ENODEV;
drm_dbg_driver(crtc->dev, "\n");
if (source && strcmp(source, "auto") != 0) {
DRM_DEBUG_DRIVER("Unknown CRC source %s for %s\n",
source, crtc->name);
drm_dbg_driver(crtc->dev, "Unknown CRC source %s for %s\n",
source, crtc->name);
return -EINVAL;
}
@@ -1233,7 +1234,7 @@ static int ltdc_plane_atomic_check(struct drm_plane *plane,
struct drm_framebuffer *fb = new_plane_state->fb;
u32 src_w, src_h;
DRM_DEBUG_DRIVER("\n");
drm_dbg_driver(plane->dev, "\n");
if (!fb)
return 0;
@@ -1244,7 +1245,7 @@ static int ltdc_plane_atomic_check(struct drm_plane *plane,
/* Reject scaling */
if (src_w != new_plane_state->crtc_w || src_h != new_plane_state->crtc_h) {
DRM_DEBUG_DRIVER("Scaling is not supported");
drm_dbg_driver(plane->dev, "Scaling is not supported");
return -EINVAL;
}
@@ -1270,7 +1271,7 @@ static void ltdc_plane_atomic_update(struct drm_plane *plane,
enum ltdc_pix_fmt pf;
if (!newstate->crtc || !fb) {
DRM_DEBUG_DRIVER("fb or crtc NULL");
drm_dbg_driver(plane->dev, "fb or crtc NULL");
return;
}
@@ -1280,11 +1281,11 @@ static void ltdc_plane_atomic_update(struct drm_plane *plane,
src_w = newstate->src_w >> 16;
src_h = newstate->src_h >> 16;
DRM_DEBUG_DRIVER("plane:%d fb:%d (%dx%d)@(%d,%d) -> (%dx%d)@(%d,%d)\n",
plane->base.id, fb->base.id,
src_w, src_h, src_x, src_y,
newstate->crtc_w, newstate->crtc_h,
newstate->crtc_x, newstate->crtc_y);
drm_dbg_driver(plane->dev, "plane:%d fb:%d (%dx%d)@(%d,%d) -> (%dx%d)@(%d,%d)\n",
plane->base.id, fb->base.id,
src_w, src_h, src_x, src_y,
newstate->crtc_w, newstate->crtc_h,
newstate->crtc_x, newstate->crtc_y);
regmap_read(ldev->regmap, LTDC_BPCR, &bpcr);
@@ -1312,8 +1313,8 @@ static void ltdc_plane_atomic_update(struct drm_plane *plane,
val = ltdc_set_flexible_pixel_format(plane, pf);
if (val == NB_PF) {
DRM_ERROR("Pixel format %.4s not supported\n",
(char *)&fb->format->format);
drm_err(fb->dev, "Pixel format %.4s not supported\n",
(char *)&fb->format->format);
val = 0; /* set by default ARGB 32 bits */
}
regmap_write_bits(ldev->regmap, LTDC_L1PFCR + lofs, LXPFCR_PF, val);
@@ -1350,7 +1351,7 @@ static void ltdc_plane_atomic_update(struct drm_plane *plane,
if (newstate->rotation & DRM_MODE_REFLECT_Y)
paddr += (fb->pitches[0] * (y1 - y0));
DRM_DEBUG_DRIVER("fb: phys 0x%08x", paddr);
drm_dbg_driver(fb->dev, "fb: phys 0x%08x", paddr);
regmap_write(ldev->regmap, LTDC_L1CFBAR + lofs, paddr);
/* Configures the color frame buffer pitch in bytes & line length */
@@ -1517,8 +1518,8 @@ static void ltdc_plane_atomic_disable(struct drm_plane *plane,
regmap_write_bits(ldev->regmap, LTDC_L1RCR + lofs,
LXRCR_IMR | LXRCR_VBR | LXRCR_GRMSK, LXRCR_VBR);
DRM_DEBUG_DRIVER("CRTC:%d plane:%d\n",
oldstate->crtc->base.id, plane->base.id);
drm_dbg_driver(plane->dev, "CRTC:%d plane:%d\n",
oldstate->crtc->base.id, plane->base.id);
}
static void ltdc_plane_atomic_print_state(struct drm_printer *p,
@@ -1632,7 +1633,7 @@ static struct drm_plane *ltdc_plane_create(struct drm_device *ddev,
drm_plane_create_alpha_property(plane);
DRM_DEBUG_DRIVER("plane:%d created\n", plane->base.id);
drm_dbg_driver(plane->dev, "plane:%d created\n", plane->base.id);
return plane;
}
@@ -1647,7 +1648,7 @@ static int ltdc_crtc_init(struct drm_device *ddev, struct drm_crtc *crtc)
primary = ltdc_plane_create(ddev, DRM_PLANE_TYPE_PRIMARY, 0);
if (!primary) {
DRM_ERROR("Can not create primary plane\n");
drm_err(ddev, "Can not create primary plane\n");
return -EINVAL;
}
@@ -1668,7 +1669,7 @@ static int ltdc_crtc_init(struct drm_device *ddev, struct drm_crtc *crtc)
ret = drmm_crtc_init_with_planes(ddev, crtc, primary, NULL,
&ltdc_crtc_funcs, NULL);
if (ret) {
DRM_ERROR("Can not initialize CRTC\n");
drm_err(ddev, "Can not initialize CRTC\n");
return ret;
}
@@ -1677,13 +1678,13 @@ static int ltdc_crtc_init(struct drm_device *ddev, struct drm_crtc *crtc)
drm_mode_crtc_set_gamma_size(crtc, CLUT_SIZE);
drm_crtc_enable_color_mgmt(crtc, 0, false, CLUT_SIZE);
DRM_DEBUG_DRIVER("CRTC:%d created\n", crtc->base.id);
drm_dbg_driver(ddev, "CRTC:%d created\n", crtc->base.id);
/* Add planes. Note : the first layer is used by primary plane */
for (i = 1; i < ldev->caps.nb_layers; i++) {
overlay = ltdc_plane_create(ddev, DRM_PLANE_TYPE_OVERLAY, i);
if (!overlay) {
DRM_ERROR("Can not create overlay plane %d\n", i);
drm_err(ddev, "Can not create overlay plane %d\n", i);
return -ENOMEM;
}
if (ldev->caps.dynamic_zorder)
@@ -1704,7 +1705,7 @@ static void ltdc_encoder_disable(struct drm_encoder *encoder)
struct drm_device *ddev = encoder->dev;
struct ltdc_device *ldev = ddev->dev_private;
DRM_DEBUG_DRIVER("\n");
drm_dbg_driver(encoder->dev, "\n");
/* Disable LTDC */
regmap_clear_bits(ldev->regmap, LTDC_GCR, GCR_LTDCEN);
@@ -1718,7 +1719,7 @@ static void ltdc_encoder_enable(struct drm_encoder *encoder)
struct drm_device *ddev = encoder->dev;
struct ltdc_device *ldev = ddev->dev_private;
DRM_DEBUG_DRIVER("\n");
drm_dbg_driver(encoder->dev, "\n");
/* set fifo underrun threshold register */
if (ldev->caps.fifo_threshold)
@@ -1734,7 +1735,7 @@ static void ltdc_encoder_mode_set(struct drm_encoder *encoder,
{
struct drm_device *ddev = encoder->dev;
DRM_DEBUG_DRIVER("\n");
drm_dbg_driver(encoder->dev, "\n");
/*
* Set to default state the pinctrl only with DPI type.
@@ -1770,7 +1771,7 @@ static int ltdc_encoder_init(struct drm_device *ddev, struct drm_bridge *bridge)
if (ret)
return ret;
DRM_DEBUG_DRIVER("Bridge encoder:%d created\n", encoder->base.id);
drm_dbg_driver(encoder->dev, "Bridge encoder:%d created\n", encoder->base.id);
return 0;
}
@@ -1870,7 +1871,7 @@ void ltdc_suspend(struct drm_device *ddev)
{
struct ltdc_device *ldev = ddev->dev_private;
DRM_DEBUG_DRIVER("\n");
drm_dbg_driver(ddev, "\n");
clk_disable_unprepare(ldev->pixel_clk);
}
@@ -1879,11 +1880,11 @@ int ltdc_resume(struct drm_device *ddev)
struct ltdc_device *ldev = ddev->dev_private;
int ret;
DRM_DEBUG_DRIVER("\n");
drm_dbg_driver(ddev, "\n");
ret = clk_prepare_enable(ldev->pixel_clk);
if (ret) {
DRM_ERROR("failed to enable pixel clock (%d)\n", ret);
drm_err(ddev, "failed to enable pixel clock (%d)\n", ret);
return ret;
}
@@ -1903,7 +1904,7 @@ int ltdc_load(struct drm_device *ddev)
int irq, i, nb_endpoints;
int ret = -ENODEV;
DRM_DEBUG_DRIVER("\n");
drm_dbg_driver(ddev, "\n");
/* Get number of endpoints */
nb_endpoints = of_graph_get_endpoint_count(np);
@@ -1913,12 +1914,12 @@ int ltdc_load(struct drm_device *ddev)
ldev->pixel_clk = devm_clk_get(dev, "lcd");
if (IS_ERR(ldev->pixel_clk)) {
if (PTR_ERR(ldev->pixel_clk) != -EPROBE_DEFER)
DRM_ERROR("Unable to get lcd clock\n");
drm_err(ddev, "Unable to get lcd clock\n");
return PTR_ERR(ldev->pixel_clk);
}
if (clk_prepare_enable(ldev->pixel_clk)) {
DRM_ERROR("Unable to prepare pixel clock\n");
drm_err(ddev, "Unable to prepare pixel clock\n");
return -ENODEV;
}
@@ -1939,7 +1940,7 @@ int ltdc_load(struct drm_device *ddev)
if (panel) {
bridge = drmm_panel_bridge_add(ddev, panel);
if (IS_ERR(bridge)) {
DRM_ERROR("panel-bridge endpoint %d\n", i);
drm_err(ddev, "panel-bridge endpoint %d\n", i);
ret = PTR_ERR(bridge);
goto err;
}
@@ -1949,7 +1950,7 @@ int ltdc_load(struct drm_device *ddev)
ret = ltdc_encoder_init(ddev, bridge);
if (ret) {
if (ret != -EPROBE_DEFER)
DRM_ERROR("init encoder endpoint %d\n", i);
drm_err(ddev, "init encoder endpoint %d\n", i);
goto err;
}
}
@@ -1967,29 +1968,29 @@ int ltdc_load(struct drm_device *ddev)
ldev->regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(ldev->regs)) {
DRM_ERROR("Unable to get ltdc registers\n");
drm_err(ddev, "Unable to get ltdc registers\n");
ret = PTR_ERR(ldev->regs);
goto err;
}
ldev->regmap = devm_regmap_init_mmio(&pdev->dev, ldev->regs, &stm32_ltdc_regmap_cfg);
if (IS_ERR(ldev->regmap)) {
DRM_ERROR("Unable to regmap ltdc registers\n");
drm_err(ddev, "Unable to regmap ltdc registers\n");
ret = PTR_ERR(ldev->regmap);
goto err;
}
ret = ltdc_get_caps(ddev);
if (ret) {
DRM_ERROR("hardware identifier (0x%08x) not supported!\n",
ldev->caps.hw_version);
drm_err(ddev, "hardware identifier (0x%08x) not supported!\n",
ldev->caps.hw_version);
goto err;
}
/* Disable all interrupts */
regmap_clear_bits(ldev->regmap, LTDC_IER, IER_MASK);
DRM_DEBUG_DRIVER("ltdc hw version 0x%08x\n", ldev->caps.hw_version);
drm_dbg_driver(ddev, "ltdc hw version 0x%08x\n", ldev->caps.hw_version);
/* initialize default value for fifo underrun threshold & clear interrupt error counters */
ldev->transfer_err = 0;
@@ -2008,27 +2009,27 @@ int ltdc_load(struct drm_device *ddev)
ltdc_irq_thread, IRQF_ONESHOT,
dev_name(dev), ddev);
if (ret) {
DRM_ERROR("Failed to register LTDC interrupt\n");
drm_err(ddev, "Failed to register LTDC interrupt\n");
goto err;
}
}
crtc = drmm_kzalloc(ddev, sizeof(*crtc), GFP_KERNEL);
if (!crtc) {
DRM_ERROR("Failed to allocate crtc\n");
drm_err(ddev, "Failed to allocate crtc\n");
ret = -ENOMEM;
goto err;
}
ret = ltdc_crtc_init(ddev, crtc);
if (ret) {
DRM_ERROR("Failed to init crtc\n");
drm_err(ddev, "Failed to init crtc\n");
goto err;
}
ret = drm_vblank_init(ddev, NB_CRTC);
if (ret) {
DRM_ERROR("Failed calling drm_vblank_init()\n");
drm_err(ddev, "Failed calling drm_vblank_init()\n");
goto err;
}
@@ -2047,7 +2048,7 @@ int ltdc_load(struct drm_device *ddev)
void ltdc_unload(struct drm_device *ddev)
{
DRM_DEBUG_DRIVER("\n");
drm_dbg_driver(ddev, "\n");
pm_runtime_disable(ddev->dev);
}

View File

@@ -132,7 +132,7 @@ int drm_sysfb_plane_helper_get_scanout_buffer(struct drm_plane *plane,
struct drm_sysfb_crtc_state {
struct drm_crtc_state base;
/* Primary-plane format; required for color mgmt. */
/* CRTC input color format; required for color mgmt. */
const struct drm_format_info *format;
};

View File

@@ -210,7 +210,12 @@ int drm_sysfb_plane_helper_atomic_check(struct drm_plane *plane,
else if (!new_plane_state->visible)
return 0;
if (new_fb->format != sysfb->fb_format) {
new_crtc_state = drm_atomic_get_new_crtc_state(new_state, new_plane_state->crtc);
new_sysfb_crtc_state = to_drm_sysfb_crtc_state(new_crtc_state);
new_sysfb_crtc_state->format = sysfb->fb_format;
if (new_fb->format != new_sysfb_crtc_state->format) {
void *buf;
/* format conversion necessary; reserve buffer */
@@ -220,11 +225,6 @@ int drm_sysfb_plane_helper_atomic_check(struct drm_plane *plane,
return -ENOMEM;
}
new_crtc_state = drm_atomic_get_new_crtc_state(new_state, new_plane_state->crtc);
new_sysfb_crtc_state = to_drm_sysfb_crtc_state(new_crtc_state);
new_sysfb_crtc_state->format = new_fb->format;
return 0;
}
EXPORT_SYMBOL(drm_sysfb_plane_helper_atomic_check);
@@ -238,7 +238,10 @@ void drm_sysfb_plane_helper_atomic_update(struct drm_plane *plane, struct drm_at
struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state);
struct drm_framebuffer *fb = plane_state->fb;
unsigned int dst_pitch = sysfb->fb_pitch;
const struct drm_format_info *dst_format = sysfb->fb_format;
struct drm_crtc_state *crtc_state = crtc_state =
drm_atomic_get_new_crtc_state(state, plane_state->crtc);
struct drm_sysfb_crtc_state *sysfb_crtc_state = to_drm_sysfb_crtc_state(crtc_state);
const struct drm_format_info *dst_format = sysfb_crtc_state->format;
struct drm_atomic_helper_damage_iter iter;
struct drm_rect damage;
int ret, idx;
@@ -370,16 +373,19 @@ EXPORT_SYMBOL(drm_sysfb_crtc_helper_atomic_check);
void drm_sysfb_crtc_reset(struct drm_crtc *crtc)
{
struct drm_sysfb_device *sysfb = to_drm_sysfb_device(crtc->dev);
struct drm_sysfb_crtc_state *sysfb_crtc_state;
if (crtc->state)
drm_sysfb_crtc_state_destroy(to_drm_sysfb_crtc_state(crtc->state));
sysfb_crtc_state = kzalloc(sizeof(*sysfb_crtc_state), GFP_KERNEL);
if (sysfb_crtc_state)
if (sysfb_crtc_state) {
sysfb_crtc_state->format = sysfb->fb_format;
__drm_atomic_helper_crtc_reset(crtc, &sysfb_crtc_state->base);
else
} else {
__drm_atomic_helper_crtc_reset(crtc, NULL);
}
}
EXPORT_SYMBOL(drm_sysfb_crtc_reset);

View File

@@ -79,22 +79,19 @@ const struct drm_format_info *drm_sysfb_get_format_si(struct drm_device *dev,
const struct screen_info *si)
{
const struct drm_format_info *format = NULL;
u32 bits_per_pixel;
struct pixel_format pixel;
size_t i;
int ret;
bits_per_pixel = __screen_info_lfb_bits_per_pixel(si);
ret = screen_info_pixel_format(si, &pixel);
if (ret)
return NULL;
for (i = 0; i < nformats; ++i) {
const struct pixel_format *f = &formats[i].pixel;
const struct drm_sysfb_format *f = &formats[i];
if (bits_per_pixel == f->bits_per_pixel &&
si->red_size == f->red.length &&
si->red_pos == f->red.offset &&
si->green_size == f->green.length &&
si->green_pos == f->green.offset &&
si->blue_size == f->blue.length &&
si->blue_pos == f->blue.offset) {
format = drm_format_info(formats[i].fourcc);
if (pixel_format_equal(&pixel, &f->pixel)) {
format = drm_format_info(f->fourcc);
break;
}
}

View File

@@ -46,6 +46,7 @@ static const struct drm_format_info *vesadrm_get_format_si(struct drm_device *de
{ PIXEL_FORMAT_RGB888, DRM_FORMAT_RGB888, },
{ PIXEL_FORMAT_XRGB8888, DRM_FORMAT_XRGB8888, },
{ PIXEL_FORMAT_XBGR8888, DRM_FORMAT_XBGR8888, },
{ PIXEL_FORMAT_C8, DRM_FORMAT_C8, },
};
return drm_sysfb_get_format_si(dev, formats, ARRAY_SIZE(formats), si);
@@ -82,7 +83,7 @@ static struct vesadrm_device *to_vesadrm_device(struct drm_device *dev)
}
/*
* Palette
* Color LUT
*/
static void vesadrm_vga_cmap_write(struct vesadrm_device *vesa, unsigned int index,
@@ -128,7 +129,7 @@ static void vesadrm_pmi_cmap_write(struct vesadrm_device *vesa, unsigned int ind
}
#endif
static void vesadrm_set_gamma_lut(struct drm_crtc *crtc, unsigned int index,
static void vesadrm_set_color_lut(struct drm_crtc *crtc, unsigned int index,
u16 red, u16 green, u16 blue)
{
struct drm_device *dev = crtc->dev;
@@ -149,15 +150,15 @@ static void vesadrm_fill_gamma_lut(struct vesadrm_device *vesa,
switch (format->format) {
case DRM_FORMAT_XRGB1555:
drm_crtc_fill_gamma_555(crtc, vesadrm_set_gamma_lut);
drm_crtc_fill_gamma_555(crtc, vesadrm_set_color_lut);
break;
case DRM_FORMAT_RGB565:
drm_crtc_fill_gamma_565(crtc, vesadrm_set_gamma_lut);
drm_crtc_fill_gamma_565(crtc, vesadrm_set_color_lut);
break;
case DRM_FORMAT_RGB888:
case DRM_FORMAT_XRGB8888:
case DRM_FORMAT_BGRX8888:
drm_crtc_fill_gamma_888(crtc, vesadrm_set_gamma_lut);
drm_crtc_fill_gamma_888(crtc, vesadrm_set_color_lut);
break;
default:
drm_warn_once(dev, "Unsupported format %p4cc for gamma correction\n",
@@ -175,15 +176,53 @@ static void vesadrm_load_gamma_lut(struct vesadrm_device *vesa,
switch (format->format) {
case DRM_FORMAT_XRGB1555:
drm_crtc_load_gamma_555_from_888(crtc, lut, vesadrm_set_gamma_lut);
drm_crtc_load_gamma_555_from_888(crtc, lut, vesadrm_set_color_lut);
break;
case DRM_FORMAT_RGB565:
drm_crtc_load_gamma_565_from_888(crtc, lut, vesadrm_set_gamma_lut);
drm_crtc_load_gamma_565_from_888(crtc, lut, vesadrm_set_color_lut);
break;
case DRM_FORMAT_RGB888:
case DRM_FORMAT_XRGB8888:
case DRM_FORMAT_BGRX8888:
drm_crtc_load_gamma_888(crtc, lut, vesadrm_set_gamma_lut);
drm_crtc_load_gamma_888(crtc, lut, vesadrm_set_color_lut);
break;
default:
drm_warn_once(dev, "Unsupported format %p4cc for gamma correction\n",
&format->format);
break;
}
}
static void vesadrm_fill_palette_lut(struct vesadrm_device *vesa,
const struct drm_format_info *format)
{
struct drm_device *dev = &vesa->sysfb.dev;
struct drm_crtc *crtc = &vesa->crtc;
switch (format->format) {
case DRM_FORMAT_C8:
drm_crtc_fill_palette_8(crtc, vesadrm_set_color_lut);
break;
case DRM_FORMAT_RGB332:
drm_crtc_fill_palette_332(crtc, vesadrm_set_color_lut);
break;
default:
drm_warn_once(dev, "Unsupported format %p4cc for palette\n",
&format->format);
break;
}
}
static void vesadrm_load_palette_lut(struct vesadrm_device *vesa,
const struct drm_format_info *format,
struct drm_color_lut *lut)
{
struct drm_device *dev = &vesa->sysfb.dev;
struct drm_crtc *crtc = &vesa->crtc;
switch (format->format) {
case DRM_FORMAT_C8:
drm_crtc_load_palette_8(crtc, lut, vesadrm_set_color_lut);
break;
default:
drm_warn_once(dev, "Unsupported format %p4cc for gamma correction\n",
@@ -200,8 +239,67 @@ static const u64 vesadrm_primary_plane_format_modifiers[] = {
DRM_SYSFB_PLANE_FORMAT_MODIFIERS,
};
static int vesadrm_primary_plane_helper_atomic_check(struct drm_plane *plane,
struct drm_atomic_state *new_state)
{
struct drm_sysfb_device *sysfb = to_drm_sysfb_device(plane->dev);
struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(new_state, plane);
struct drm_framebuffer *new_fb = new_plane_state->fb;
struct drm_crtc_state *new_crtc_state;
struct drm_sysfb_crtc_state *new_sysfb_crtc_state;
int ret;
ret = drm_sysfb_plane_helper_atomic_check(plane, new_state);
if (ret)
return ret;
else if (!new_plane_state->visible)
return 0;
/*
* Fix up format conversion for specific cases
*/
switch (sysfb->fb_format->format) {
case DRM_FORMAT_C8:
new_crtc_state = drm_atomic_get_new_crtc_state(new_state, new_plane_state->crtc);
new_sysfb_crtc_state = to_drm_sysfb_crtc_state(new_crtc_state);
switch (new_fb->format->format) {
case DRM_FORMAT_XRGB8888:
/*
* Reduce XRGB8888 to RGB332. Each resulting pixel is an index
* into the C8 hardware palette, which stores RGB332 colors.
*/
if (new_sysfb_crtc_state->format->format != DRM_FORMAT_RGB332) {
new_sysfb_crtc_state->format =
drm_format_info(DRM_FORMAT_RGB332);
new_crtc_state->color_mgmt_changed = true;
}
break;
case DRM_FORMAT_C8:
/*
* Restore original output. Emulation of XRGB8888 set RBG332
* output format and hardware palette. This needs to be undone
* when we switch back to DRM_FORMAT_C8.
*/
if (new_sysfb_crtc_state->format->format == DRM_FORMAT_RGB332) {
new_sysfb_crtc_state->format = sysfb->fb_format;
new_crtc_state->color_mgmt_changed = true;
}
break;
}
break;
};
return 0;
}
static const struct drm_plane_helper_funcs vesadrm_primary_plane_helper_funcs = {
DRM_SYSFB_PLANE_HELPER_FUNCS,
DRM_GEM_SHADOW_PLANE_HELPER_FUNCS,
.atomic_check = vesadrm_primary_plane_helper_atomic_check,
.atomic_update = drm_sysfb_plane_helper_atomic_update,
.atomic_disable = drm_sysfb_plane_helper_atomic_disable,
.get_scanout_buffer = drm_sysfb_plane_helper_get_scanout_buffer,
};
static const struct drm_plane_funcs vesadrm_primary_plane_funcs = {
@@ -223,15 +321,36 @@ static void vesadrm_crtc_helper_atomic_flush(struct drm_crtc *crtc,
* plane's color format.
*/
if (crtc_state->enable && crtc_state->color_mgmt_changed) {
if (sysfb_crtc_state->format == sysfb->fb_format) {
if (crtc_state->gamma_lut)
vesadrm_load_gamma_lut(vesa,
sysfb_crtc_state->format,
crtc_state->gamma_lut->data);
else
switch (sysfb->fb_format->format) {
/*
* Index formats
*/
case DRM_FORMAT_C8:
if (sysfb_crtc_state->format->format == DRM_FORMAT_RGB332) {
vesadrm_fill_palette_lut(vesa, sysfb_crtc_state->format);
} else if (crtc->state->gamma_lut) {
vesadrm_load_palette_lut(vesa,
sysfb_crtc_state->format,
crtc_state->gamma_lut->data);
} else {
vesadrm_fill_palette_lut(vesa, sysfb_crtc_state->format);
}
break;
/*
* Component formats
*/
default:
if (sysfb_crtc_state->format == sysfb->fb_format) {
if (crtc_state->gamma_lut)
vesadrm_load_gamma_lut(vesa,
sysfb_crtc_state->format,
crtc_state->gamma_lut->data);
else
vesadrm_fill_gamma_lut(vesa, sysfb_crtc_state->format);
} else {
vesadrm_fill_gamma_lut(vesa, sysfb_crtc_state->format);
} else {
vesadrm_fill_gamma_lut(vesa, sysfb_crtc_state->format);
}
break;
}
}
}

View File

@@ -112,9 +112,9 @@ struct i2c_hid {
struct i2chid_ops *ops;
struct drm_panel_follower panel_follower;
struct work_struct panel_follower_prepare_work;
struct work_struct panel_follower_work;
bool is_panel_follower;
bool prepare_work_finished;
bool panel_follower_work_finished;
};
static const struct i2c_hid_quirks {
@@ -1110,10 +1110,10 @@ static int i2c_hid_core_probe_panel_follower(struct i2c_hid *ihid)
return ret;
}
static void ihid_core_panel_prepare_work(struct work_struct *work)
static void ihid_core_panel_follower_work(struct work_struct *work)
{
struct i2c_hid *ihid = container_of(work, struct i2c_hid,
panel_follower_prepare_work);
panel_follower_work);
struct hid_device *hid = ihid->hid;
int ret;
@@ -1130,7 +1130,7 @@ static void ihid_core_panel_prepare_work(struct work_struct *work)
if (ret)
dev_warn(&ihid->client->dev, "Power on failed: %d\n", ret);
else
WRITE_ONCE(ihid->prepare_work_finished, true);
WRITE_ONCE(ihid->panel_follower_work_finished, true);
/*
* The work APIs provide a number of memory ordering guarantees
@@ -1139,12 +1139,12 @@ static void ihid_core_panel_prepare_work(struct work_struct *work)
* guarantee that a write that happened in the work is visible after
* cancel_work_sync(). We'll add a write memory barrier here to match
* with i2c_hid_core_panel_unpreparing() to ensure that our write to
* prepare_work_finished is visible there.
* panel_follower_work_finished is visible there.
*/
smp_wmb();
}
static int i2c_hid_core_panel_prepared(struct drm_panel_follower *follower)
static int i2c_hid_core_panel_follower_resume(struct drm_panel_follower *follower)
{
struct i2c_hid *ihid = container_of(follower, struct i2c_hid, panel_follower);
@@ -1152,29 +1152,36 @@ static int i2c_hid_core_panel_prepared(struct drm_panel_follower *follower)
* Powering on a touchscreen can be a slow process. Queue the work to
* the system workqueue so we don't block the panel's power up.
*/
WRITE_ONCE(ihid->prepare_work_finished, false);
schedule_work(&ihid->panel_follower_prepare_work);
WRITE_ONCE(ihid->panel_follower_work_finished, false);
schedule_work(&ihid->panel_follower_work);
return 0;
}
static int i2c_hid_core_panel_unpreparing(struct drm_panel_follower *follower)
static int i2c_hid_core_panel_follower_suspend(struct drm_panel_follower *follower)
{
struct i2c_hid *ihid = container_of(follower, struct i2c_hid, panel_follower);
cancel_work_sync(&ihid->panel_follower_prepare_work);
cancel_work_sync(&ihid->panel_follower_work);
/* Match with ihid_core_panel_prepare_work() */
/* Match with ihid_core_panel_follower_work() */
smp_rmb();
if (!READ_ONCE(ihid->prepare_work_finished))
if (!READ_ONCE(ihid->panel_follower_work_finished))
return 0;
return i2c_hid_core_suspend(ihid, true);
}
static const struct drm_panel_follower_funcs i2c_hid_core_panel_follower_funcs = {
.panel_prepared = i2c_hid_core_panel_prepared,
.panel_unpreparing = i2c_hid_core_panel_unpreparing,
static const struct drm_panel_follower_funcs
i2c_hid_core_panel_follower_prepare_funcs = {
.panel_prepared = i2c_hid_core_panel_follower_resume,
.panel_unpreparing = i2c_hid_core_panel_follower_suspend,
};
static const struct drm_panel_follower_funcs
i2c_hid_core_panel_follower_enable_funcs = {
.panel_enabled = i2c_hid_core_panel_follower_resume,
.panel_disabling = i2c_hid_core_panel_follower_suspend,
};
static int i2c_hid_core_register_panel_follower(struct i2c_hid *ihid)
@@ -1182,7 +1189,10 @@ static int i2c_hid_core_register_panel_follower(struct i2c_hid *ihid)
struct device *dev = &ihid->client->dev;
int ret;
ihid->panel_follower.funcs = &i2c_hid_core_panel_follower_funcs;
if (ihid->hid->initial_quirks & HID_QUIRK_POWER_ON_AFTER_BACKLIGHT)
ihid->panel_follower.funcs = &i2c_hid_core_panel_follower_enable_funcs;
else
ihid->panel_follower.funcs = &i2c_hid_core_panel_follower_prepare_funcs;
/*
* If we're not in control of our own power up/power down then we can't
@@ -1237,7 +1247,7 @@ int i2c_hid_core_probe(struct i2c_client *client, struct i2chid_ops *ops,
init_waitqueue_head(&ihid->wait);
mutex_init(&ihid->cmd_lock);
mutex_init(&ihid->reset_lock);
INIT_WORK(&ihid->panel_follower_prepare_work, ihid_core_panel_prepare_work);
INIT_WORK(&ihid->panel_follower_work, ihid_core_panel_follower_work);
/* we need to allocate the command buffer without knowing the maximum
* size of the reports. Let's use HID_MIN_BUFFER_SIZE, then we do the

View File

@@ -8,6 +8,7 @@
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/gpio/consumer.h>
#include <linux/hid.h>
#include <linux/i2c.h>
#include <linux/kernel.h>
#include <linux/module.h>
@@ -23,6 +24,7 @@ struct elan_i2c_hid_chip_data {
unsigned int post_power_delay_ms;
u16 hid_descriptor_address;
const char *main_supply_name;
bool power_after_backlight;
};
struct i2c_hid_of_elan {
@@ -97,6 +99,7 @@ static int i2c_hid_of_elan_probe(struct i2c_client *client)
{
struct i2c_hid_of_elan *ihid_elan;
int ret;
u32 quirks = 0;
ihid_elan = devm_kzalloc(&client->dev, sizeof(*ihid_elan), GFP_KERNEL);
if (!ihid_elan)
@@ -131,8 +134,12 @@ static int i2c_hid_of_elan_probe(struct i2c_client *client)
}
}
if (ihid_elan->chip_data->power_after_backlight)
quirks = HID_QUIRK_POWER_ON_AFTER_BACKLIGHT;
ret = i2c_hid_core_probe(client, &ihid_elan->ops,
ihid_elan->chip_data->hid_descriptor_address, 0);
ihid_elan->chip_data->hid_descriptor_address,
quirks);
if (ret)
goto err_deassert_reset;
@@ -150,6 +157,7 @@ static const struct elan_i2c_hid_chip_data elan_ekth6915_chip_data = {
.post_gpio_reset_on_delay_ms = 300,
.hid_descriptor_address = 0x0001,
.main_supply_name = "vcc33",
.power_after_backlight = true,
};
static const struct elan_i2c_hid_chip_data elan_ekth6a12nay_chip_data = {
@@ -157,6 +165,7 @@ static const struct elan_i2c_hid_chip_data elan_ekth6a12nay_chip_data = {
.post_gpio_reset_on_delay_ms = 300,
.hid_descriptor_address = 0x0001,
.main_supply_name = "vcc33",
.power_after_backlight = true,
};
static const struct elan_i2c_hid_chip_data ilitek_ili9882t_chip_data = {

View File

@@ -5,6 +5,8 @@
#include <linux/screen_info.h>
#include <linux/string.h>
#include <video/pixel_format.h>
static void resource_init_named(struct resource *r,
resource_size_t start, resource_size_t size,
const char *name, unsigned int flags)
@@ -180,3 +182,56 @@ u32 __screen_info_lfb_bits_per_pixel(const struct screen_info *si)
return bits_per_pixel;
}
EXPORT_SYMBOL(__screen_info_lfb_bits_per_pixel);
static int __screen_info_lfb_pixel_format(const struct screen_info *si, struct pixel_format *f)
{
u32 bits_per_pixel = __screen_info_lfb_bits_per_pixel(si);
if (bits_per_pixel > U8_MAX)
return -EINVAL;
f->bits_per_pixel = bits_per_pixel;
if (si->lfb_depth > 8) {
f->indexed = false;
f->alpha.offset = 0;
f->alpha.length = 0;
f->red.offset = si->red_pos;
f->red.length = si->red_size;
f->green.offset = si->green_pos;
f->green.length = si->green_size;
f->blue.offset = si->blue_pos;
f->blue.length = si->blue_size;
} else {
f->indexed = true;
f->index.offset = 0;
f->index.length = si->lfb_depth;
}
return 0;
}
/**
* screen_info_pixel_format - Returns the screen-info format as pixel-format description
*
* @si: the screen_info
* @f: pointer to return pixel-format description
*
* Returns:
* 0 on success, or a negative errno code otherwise.
*/
int screen_info_pixel_format(const struct screen_info *si, struct pixel_format *f)
{
unsigned int type = screen_info_video_type(si);
/* TODO: Add support for additional types as needed. */
switch (type) {
case VIDEO_TYPE_VLFB:
case VIDEO_TYPE_EFI:
return __screen_info_lfb_pixel_format(si, f);
}
/* not supported */
return -EINVAL;
}
EXPORT_SYMBOL(screen_info_pixel_format);

View File

@@ -143,6 +143,7 @@ void drm_crtc_fill_gamma_555(struct drm_crtc *crtc, drm_crtc_set_lut_func set_ga
void drm_crtc_load_palette_8(struct drm_crtc *crtc, const struct drm_color_lut *lut,
drm_crtc_set_lut_func set_palette);
void drm_crtc_fill_palette_332(struct drm_crtc *crtc, drm_crtc_set_lut_func set_palette);
void drm_crtc_fill_palette_8(struct drm_crtc *crtc, drm_crtc_set_lut_func set_palette);
#endif

View File

@@ -160,6 +160,20 @@ struct drm_panel_follower_funcs {
* Called before the panel is powered off.
*/
int (*panel_unpreparing)(struct drm_panel_follower *follower);
/**
* @panel_enabled:
*
* Called after the panel and the backlight have been enabled.
*/
int (*panel_enabled)(struct drm_panel_follower *follower);
/**
* @panel_disabling:
*
* Called before the panel and the backlight are disabled.
*/
int (*panel_disabling)(struct drm_panel_follower *follower);
};
struct drm_panel_follower {

View File

@@ -364,6 +364,7 @@ struct hid_item {
* | @HID_QUIRK_HAVE_SPECIAL_DRIVER:
* | @HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE:
* | @HID_QUIRK_IGNORE_SPECIAL_DRIVER
* | @HID_QUIRK_POWER_ON_AFTER_BACKLIGHT
* | @HID_QUIRK_FULLSPEED_INTERVAL:
* | @HID_QUIRK_NO_INIT_REPORTS:
* | @HID_QUIRK_NO_IGNORE:
@@ -391,6 +392,7 @@ struct hid_item {
#define HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE BIT(20)
#define HID_QUIRK_NOINVERT BIT(21)
#define HID_QUIRK_IGNORE_SPECIAL_DRIVER BIT(22)
#define HID_QUIRK_POWER_ON_AFTER_BACKLIGHT BIT(23)
#define HID_QUIRK_FULLSPEED_INTERVAL BIT(28)
#define HID_QUIRK_NO_INIT_REPORTS BIT(29)
#define HID_QUIRK_NO_IGNORE BIT(30)

View File

@@ -12,6 +12,7 @@
#define SCREEN_INFO_MAX_RESOURCES 3
struct pci_dev;
struct pixel_format;
struct resource;
static inline bool __screen_info_has_lfb(unsigned int type)
@@ -136,6 +137,7 @@ static inline u32 __screen_info_vesapm_info_base(const struct screen_info *si)
ssize_t screen_info_resources(const struct screen_info *si, struct resource *r, size_t num);
u32 __screen_info_lfb_bits_per_pixel(const struct screen_info *si);
int screen_info_pixel_format(const struct screen_info *si, struct pixel_format *f);
#if defined(CONFIG_PCI)
void screen_info_apply_fixups(void);

View File

@@ -20,6 +20,9 @@ struct pixel_format {
};
};
#define PIXEL_FORMAT_C8 \
{ 8, true, { .index = {0, 8}, } }
#define PIXEL_FORMAT_XRGB1555 \
{ 16, false, { .alpha = {0, 0}, .red = {10, 5}, .green = {5, 5}, .blue = {0, 5} } }
@@ -38,4 +41,62 @@ struct pixel_format {
#define PIXEL_FORMAT_XRGB2101010 \
{ 32, false, { .alpha = {0, 0}, .red = {20, 10}, .green = {10, 10}, .blue = {0, 10} } }
#define __pixel_format_cmp_field(lhs, rhs, name) \
{ \
int ret = ((lhs)->name) - ((rhs)->name); \
if (ret) \
return ret; \
}
#define __pixel_format_cmp_bitfield(lhs, rhs, name) \
{ \
__pixel_format_cmp_field(lhs, rhs, name.offset); \
__pixel_format_cmp_field(lhs, rhs, name.length); \
}
/**
* pixel_format_cmp - Compares two pixel-format descriptions
*
* @lhs: a pixel-format description
* @rhs: a pixel-format description
*
* Compares two pixel-format descriptions for their order. The semantics
* are equivalent to memcmp().
*
* Returns:
* 0 if both arguments describe the same pixel format, less-than-zero if lhs < rhs,
* or greater-than-zero if lhs > rhs.
*/
static inline int pixel_format_cmp(const struct pixel_format *lhs, const struct pixel_format *rhs)
{
__pixel_format_cmp_field(lhs, rhs, bits_per_pixel);
__pixel_format_cmp_field(lhs, rhs, indexed);
if (lhs->indexed) {
__pixel_format_cmp_bitfield(lhs, rhs, index);
} else {
__pixel_format_cmp_bitfield(lhs, rhs, alpha);
__pixel_format_cmp_bitfield(lhs, rhs, red);
__pixel_format_cmp_bitfield(lhs, rhs, green);
__pixel_format_cmp_bitfield(lhs, rhs, blue);
}
return 0;
}
/**
* pixel_format_equal - Compares two pixel-format descriptions for equality
*
* @lhs: a pixel-format description
* @rhs: a pixel-format description
*
* Returns:
* True if both arguments describe the same pixel format, or false otherwise.
*/
static inline bool pixel_format_equal(const struct pixel_format *lhs,
const struct pixel_format *rhs)
{
return !pixel_format_cmp(lhs, rhs);
}
#endif