drm-misc-next for v6.1:

Core Changes:
 - Add dma_resv_assert_held to vmap/vunmap calls.
 - Add kunit tests for some format conversion calls.
 - Don't rewrite link config when setting phy test pattern in
   DP link training.
 
 Driver Changes:
 - Assorted small fixes in bridge/lt8192b, qxl, virtio-gpu, ast.
 - Fix corrupted image output in lt8912b.
 - Fix driver unbind in meson.
 - Add INX, BOE, AUO, Multi-Inno Technology panels to panel-edp.
 - Synchronize access to GEM bo's in simpledrm, ssd130x.
 - Use dev_err_probe in panel-edp and panel-simple.
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEuXvWqAysSYEJGuVH/lWMcqZwE8MFAmM2rpoACgkQ/lWMcqZw
 E8OyTA/+PTxuSG8ueMO7BoTNn1o1t7KDDC4GoIyQPrwTXGa+dZwi2xnPLH3qVdjZ
 TlaxOZmP9mvX9AkZTn+El47eP19t5U6FUa+U9aJFLdi2vgrxMqaR3jwGRo2X4G5q
 dzmglC6f3dMbRsW9a7O3HTpvP5dFUIE/9e507hrMqMB6XHEJ6vh2ZJdr6qzXyQwB
 nY0neSwNwn1wVpjVa0F3t2XEmnbpESzzpEsDFmJNaLzrW44XemEL14iePPYFCo9T
 /IxiDOOnEYgWMqWi1pRxzc/u9Syojnn4mWCDpZBQ3ovx+ObK1XHXNYXrJcyWgNq1
 K133P85cUnlstq7wJjBWtdh03LFw4vXHpxpeyd21BU/PMtnVq9eZQRJtJowHCAu8
 KuYpDWF4UYx+MTo7wFuZ9y1uKkTPMHlNJYt+6i54KOFh6yfqPNAH1/LrK7YXtlGG
 EboPpDZTubueLxo6FwG76xireGSDKcgTiqN68vud5A0LJ10+ztunCUnxDdRn3g4m
 2cAqj3VjSgn0vgQPn7B3WwllyX4GsWPdc0Js0uGvqK6WvgpHBYBZK8NXTURBGL2K
 vQdrbz9nKY/wS5SzYDwlspGpts/I7kEVdwkzb/bk+BBxLXST+bFRFfRzztsQJK8e
 rRG3bCGU2XDRGLIcf2nxwehzrm7bwEX8w8y1LW2xZFeE5xRsAV0=
 =o69X
 -----END PGP SIGNATURE-----

Merge tag 'drm-misc-next-2022-09-30' of git://anongit.freedesktop.org/drm/drm-misc into drm-next

drm-misc-next for v6.1:

Core Changes:
- Add dma_resv_assert_held to vmap/vunmap calls.
- Add kunit tests for some format conversion calls.
- Don't rewrite link config when setting phy test pattern in
  DP link training.

Driver Changes:
- Assorted small fixes in bridge/lt8192b, qxl, virtio-gpu, ast.
- Fix corrupted image output in lt8912b.
- Fix driver unbind in meson.
- Add INX, BOE, AUO, Multi-Inno Technology panels to panel-edp.
- Synchronize access to GEM bo's in simpledrm, ssd130x.
- Use dev_err_probe in panel-edp and panel-simple.

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

From: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/afbd505a-3799-c73b-8008-ef6e156ad7e1@linux.intel.com
This commit is contained in:
Dave Airlie 2022-10-04 09:29:15 +10:00
commit 4ae9f874dc
22 changed files with 397 additions and 116 deletions

View File

@ -234,6 +234,8 @@ properties:
- mitsubishi,aa070mc01-ca1
# Multi-Inno Technology Co.,Ltd MI0700S4T-6 7" 800x480 TFT Resistive Touch Module
- multi-inno,mi0700s4t-6
# Multi-Inno Technology Co.,Ltd MI0800FT-9 8" 800x600 TFT Resistive Touch Module
- multi-inno,mi0800ft-9
# Multi-Inno Technology Co.,Ltd MI1010AIT-1CP 10.1" 1280x800 LVDS IPS Cap Touch Mod.
- multi-inno,mi1010ait-1cp
# NEC LCD Technologies, Ltd. 12.1" WXGA (1280x800) LVDS TFT LCD panel

View File

@ -39,7 +39,7 @@
#include "ast_drv.h"
int ast_modeset = -1;
static int ast_modeset = -1;
MODULE_PARM_DESC(modeset, "Disable/Enable modesetting");
module_param_named(modeset, ast_modeset, int, 0400);

View File

@ -165,30 +165,38 @@ static int lt8912_write_rxlogicres_config(struct lt8912 *lt)
return ret;
};
/* enable LVDS output with some hardcoded configuration, not required for the HDMI output */
static int lt8912_write_lvds_config(struct lt8912 *lt)
{
const struct reg_sequence seq[] = {
// lvds power up
{0x44, 0x30},
{0x51, 0x05},
{0x50, 0x24},
{0x51, 0x2d},
{0x52, 0x04},
{0x69, 0x0e},
// core pll bypass
{0x50, 0x24}, // cp=50uA
{0x51, 0x2d}, // Pix_clk as reference, second order passive LPF PLL
{0x52, 0x04}, // loopdiv=0, use second-order PLL
{0x69, 0x0e}, // CP_PRESET_DIV_RATIO
{0x69, 0x8e},
{0x6a, 0x00},
{0x6c, 0xb8},
{0x6c, 0xb8}, // RGD_CP_SOFT_K_EN,RGD_CP_SOFT_K[13:8]
{0x6b, 0x51},
{0x04, 0xfb},
{0x04, 0xfb}, // core pll reset
{0x04, 0xff},
{0x7f, 0x00},
{0xa8, 0x13},
{0x02, 0xf7},
// scaler bypass
{0x7f, 0x00}, // disable scaler
{0xa8, 0x13}, // 0x13: JEIDA, 0x33: VESA
{0x02, 0xf7}, // lvds pll reset
{0x02, 0xff},
{0x03, 0xcf},
{0x03, 0xff},
};
return regmap_multi_reg_write(lt->regmap[I2C_CEC_DSI], seq, ARRAY_SIZE(seq));
return regmap_multi_reg_write(lt->regmap[I2C_MAIN], seq, ARRAY_SIZE(seq));
};
static inline struct lt8912 *bridge_to_lt8912(struct drm_bridge *b)
@ -268,7 +276,7 @@ static int lt8912_video_setup(struct lt8912 *lt)
u32 hactive, h_total, hpw, hfp, hbp;
u32 vactive, v_total, vpw, vfp, vbp;
u8 settle = 0x08;
int ret;
int ret, hsync_activehigh, vsync_activehigh;
if (!lt)
return -EINVAL;
@ -278,12 +286,14 @@ static int lt8912_video_setup(struct lt8912 *lt)
hpw = lt->mode.hsync_len;
hbp = lt->mode.hback_porch;
h_total = hactive + hfp + hpw + hbp;
hsync_activehigh = lt->mode.flags & DISPLAY_FLAGS_HSYNC_HIGH;
vactive = lt->mode.vactive;
vfp = lt->mode.vfront_porch;
vpw = lt->mode.vsync_len;
vbp = lt->mode.vback_porch;
v_total = vactive + vfp + vpw + vbp;
vsync_activehigh = lt->mode.flags & DISPLAY_FLAGS_VSYNC_HIGH;
if (vactive <= 600)
settle = 0x04;
@ -317,6 +327,13 @@ static int lt8912_video_setup(struct lt8912 *lt)
ret |= regmap_write(lt->regmap[I2C_CEC_DSI], 0x3e, hfp & 0xff);
ret |= regmap_write(lt->regmap[I2C_CEC_DSI], 0x3f, hfp >> 8);
ret |= regmap_update_bits(lt->regmap[I2C_MAIN], 0xab, BIT(0),
vsync_activehigh ? BIT(0) : 0);
ret |= regmap_update_bits(lt->regmap[I2C_MAIN], 0xab, BIT(1),
hsync_activehigh ? BIT(1) : 0);
ret |= regmap_update_bits(lt->regmap[I2C_MAIN], 0xb2, BIT(0),
lt->connector.display_info.is_hdmi ? BIT(0) : 0);
return ret;
}

View File

@ -2670,17 +2670,8 @@ int drm_dp_set_phy_test_pattern(struct drm_dp_aux *aux,
struct drm_dp_phy_test_params *data, u8 dp_rev)
{
int err, i;
u8 link_config[2];
u8 test_pattern;
link_config[0] = drm_dp_link_rate_to_bw_code(data->link_rate);
link_config[1] = data->num_lanes;
if (data->enhanced_frame_cap)
link_config[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
err = drm_dp_dpcd_write(aux, DP_LINK_BW_SET, link_config, 2);
if (err < 0)
return err;
test_pattern = data->phy_pattern;
if (dp_rev < 0x12) {
test_pattern = (test_pattern << 2) &

View File

@ -553,6 +553,7 @@ void drm_fb_xrgb8888_to_xrgb2101010(struct iosys_map *dst, const unsigned int *d
drm_fb_xfrm(dst, dst_pitch, dst_pixsize, src, fb, clip, false,
drm_fb_xrgb8888_to_xrgb2101010_line);
}
EXPORT_SYMBOL(drm_fb_xrgb8888_to_xrgb2101010);
static void drm_fb_xrgb8888_to_gray8_line(void *dbuf, const void *sbuf, unsigned int pixels)
{

View File

@ -87,13 +87,13 @@ int drm_framebuffer_check_src_coords(uint32_t src_x, uint32_t src_y,
src_x > fb_width - src_w ||
src_h > fb_height ||
src_y > fb_height - src_h) {
DRM_DEBUG_KMS("Invalid source coordinates "
"%u.%06ux%u.%06u+%u.%06u+%u.%06u (fb %ux%u)\n",
src_w >> 16, ((src_w & 0xffff) * 15625) >> 10,
src_h >> 16, ((src_h & 0xffff) * 15625) >> 10,
src_x >> 16, ((src_x & 0xffff) * 15625) >> 10,
src_y >> 16, ((src_y & 0xffff) * 15625) >> 10,
fb->width, fb->height);
drm_dbg_kms(fb->dev, "Invalid source coordinates "
"%u.%06ux%u.%06u+%u.%06u+%u.%06u (fb %ux%u)\n",
src_w >> 16, ((src_w & 0xffff) * 15625) >> 10,
src_h >> 16, ((src_h & 0xffff) * 15625) >> 10,
src_x >> 16, ((src_x & 0xffff) * 15625) >> 10,
src_y >> 16, ((src_y & 0xffff) * 15625) >> 10,
fb->width, fb->height);
return -ENOSPC;
}
@ -125,7 +125,7 @@ int drm_mode_addfb(struct drm_device *dev, struct drm_mode_fb_cmd *or,
r.pixel_format = drm_driver_legacy_fb_format(dev, or->bpp, or->depth);
if (r.pixel_format == DRM_FORMAT_INVALID) {
DRM_DEBUG("bad {bpp:%d, depth:%d}\n", or->bpp, or->depth);
drm_dbg_kms(dev, "bad {bpp:%d, depth:%d}\n", or->bpp, or->depth);
return -EINVAL;
}
@ -177,18 +177,18 @@ static int framebuffer_check(struct drm_device *dev,
/* check if the format is supported at all */
if (!__drm_format_info(r->pixel_format)) {
DRM_DEBUG_KMS("bad framebuffer format %p4cc\n",
&r->pixel_format);
drm_dbg_kms(dev, "bad framebuffer format %p4cc\n",
&r->pixel_format);
return -EINVAL;
}
if (r->width == 0) {
DRM_DEBUG_KMS("bad framebuffer width %u\n", r->width);
drm_dbg_kms(dev, "bad framebuffer width %u\n", r->width);
return -EINVAL;
}
if (r->height == 0) {
DRM_DEBUG_KMS("bad framebuffer height %u\n", r->height);
drm_dbg_kms(dev, "bad framebuffer height %u\n", r->height);
return -EINVAL;
}
@ -202,12 +202,12 @@ static int framebuffer_check(struct drm_device *dev,
u64 min_pitch = drm_format_info_min_pitch(info, i, width);
if (!block_size && (r->modifier[i] == DRM_FORMAT_MOD_LINEAR)) {
DRM_DEBUG_KMS("Format requires non-linear modifier for plane %d\n", i);
drm_dbg_kms(dev, "Format requires non-linear modifier for plane %d\n", i);
return -EINVAL;
}
if (!r->handles[i]) {
DRM_DEBUG_KMS("no buffer object handle for plane %d\n", i);
drm_dbg_kms(dev, "no buffer object handle for plane %d\n", i);
return -EINVAL;
}
@ -218,20 +218,20 @@ static int framebuffer_check(struct drm_device *dev,
return -ERANGE;
if (block_size && r->pitches[i] < min_pitch) {
DRM_DEBUG_KMS("bad pitch %u for plane %d\n", r->pitches[i], i);
drm_dbg_kms(dev, "bad pitch %u for plane %d\n", r->pitches[i], i);
return -EINVAL;
}
if (r->modifier[i] && !(r->flags & DRM_MODE_FB_MODIFIERS)) {
DRM_DEBUG_KMS("bad fb modifier %llu for plane %d\n",
r->modifier[i], i);
drm_dbg_kms(dev, "bad fb modifier %llu for plane %d\n",
r->modifier[i], i);
return -EINVAL;
}
if (r->flags & DRM_MODE_FB_MODIFIERS &&
r->modifier[i] != r->modifier[0]) {
DRM_DEBUG_KMS("bad fb modifier %llu for plane %d\n",
r->modifier[i], i);
drm_dbg_kms(dev, "bad fb modifier %llu for plane %d\n",
r->modifier[i], i);
return -EINVAL;
}
@ -244,7 +244,7 @@ static int framebuffer_check(struct drm_device *dev,
if (r->pixel_format != DRM_FORMAT_NV12 ||
width % 128 || height % 32 ||
r->pitches[i] % 128) {
DRM_DEBUG_KMS("bad modifier data for plane %d\n", i);
drm_dbg_kms(dev, "bad modifier data for plane %d\n", i);
return -EINVAL;
}
break;
@ -256,7 +256,7 @@ static int framebuffer_check(struct drm_device *dev,
for (i = info->num_planes; i < 4; i++) {
if (r->modifier[i]) {
DRM_DEBUG_KMS("non-zero modifier for unused plane %d\n", i);
drm_dbg_kms(dev, "non-zero modifier for unused plane %d\n", i);
return -EINVAL;
}
@ -265,17 +265,17 @@ static int framebuffer_check(struct drm_device *dev,
continue;
if (r->handles[i]) {
DRM_DEBUG_KMS("buffer object handle for unused plane %d\n", i);
drm_dbg_kms(dev, "buffer object handle for unused plane %d\n", i);
return -EINVAL;
}
if (r->pitches[i]) {
DRM_DEBUG_KMS("non-zero pitch for unused plane %d\n", i);
drm_dbg_kms(dev, "non-zero pitch for unused plane %d\n", i);
return -EINVAL;
}
if (r->offsets[i]) {
DRM_DEBUG_KMS("non-zero offset for unused plane %d\n", i);
drm_dbg_kms(dev, "non-zero offset for unused plane %d\n", i);
return -EINVAL;
}
}
@ -293,24 +293,24 @@ drm_internal_framebuffer_create(struct drm_device *dev,
int ret;
if (r->flags & ~(DRM_MODE_FB_INTERLACED | DRM_MODE_FB_MODIFIERS)) {
DRM_DEBUG_KMS("bad framebuffer flags 0x%08x\n", r->flags);
drm_dbg_kms(dev, "bad framebuffer flags 0x%08x\n", r->flags);
return ERR_PTR(-EINVAL);
}
if ((config->min_width > r->width) || (r->width > config->max_width)) {
DRM_DEBUG_KMS("bad framebuffer width %d, should be >= %d && <= %d\n",
r->width, config->min_width, config->max_width);
drm_dbg_kms(dev, "bad framebuffer width %d, should be >= %d && <= %d\n",
r->width, config->min_width, config->max_width);
return ERR_PTR(-EINVAL);
}
if ((config->min_height > r->height) || (r->height > config->max_height)) {
DRM_DEBUG_KMS("bad framebuffer height %d, should be >= %d && <= %d\n",
r->height, config->min_height, config->max_height);
drm_dbg_kms(dev, "bad framebuffer height %d, should be >= %d && <= %d\n",
r->height, config->min_height, config->max_height);
return ERR_PTR(-EINVAL);
}
if (r->flags & DRM_MODE_FB_MODIFIERS &&
dev->mode_config.fb_modifiers_not_supported) {
DRM_DEBUG_KMS("driver does not support fb modifiers\n");
drm_dbg_kms(dev, "driver does not support fb modifiers\n");
return ERR_PTR(-EINVAL);
}
@ -320,7 +320,7 @@ drm_internal_framebuffer_create(struct drm_device *dev,
fb = dev->mode_config.funcs->fb_create(dev, file_priv, r);
if (IS_ERR(fb)) {
DRM_DEBUG_KMS("could not create framebuffer\n");
drm_dbg_kms(dev, "could not create framebuffer\n");
return fb;
}
@ -356,7 +356,7 @@ int drm_mode_addfb2(struct drm_device *dev,
if (IS_ERR(fb))
return PTR_ERR(fb);
DRM_DEBUG_KMS("[FB:%d]\n", fb->base.id);
drm_dbg_kms(dev, "[FB:%d]\n", fb->base.id);
r->fb_id = fb->base.id;
/* Transfer ownership to the filp for reaping on close */
@ -384,7 +384,7 @@ int drm_mode_addfb2_ioctl(struct drm_device *dev,
* then. So block it to make userspace fallback to
* ADDFB.
*/
DRM_DEBUG_KMS("addfb2 broken on bigendian");
drm_dbg_kms(dev, "addfb2 broken on bigendian");
return -EOPNOTSUPP;
}
#endif

View File

@ -388,10 +388,14 @@ static void meson_drv_unbind(struct device *dev)
drm_dev_unregister(drm);
drm_kms_helper_poll_fini(drm);
drm_atomic_helper_shutdown(drm);
component_unbind_all(dev, drm);
free_irq(priv->vsync_irq, drm);
drm_dev_put(drm);
meson_encoder_hdmi_remove(priv);
meson_encoder_cvbs_remove(priv);
component_unbind_all(dev, drm);
if (priv->afbcd.ops)
priv->afbcd.ops->exit(priv);
}
@ -493,6 +497,13 @@ static int meson_drv_probe(struct platform_device *pdev)
return 0;
};
static int meson_drv_remove(struct platform_device *pdev)
{
component_master_del(&pdev->dev, &meson_drv_master_ops);
return 0;
}
static struct meson_drm_match_data meson_drm_gxbb_data = {
.compat = VPU_COMPATIBLE_GXBB,
};
@ -530,6 +541,7 @@ static const struct dev_pm_ops meson_drv_pm_ops = {
static struct platform_driver meson_drm_platform_driver = {
.probe = meson_drv_probe,
.remove = meson_drv_remove,
.shutdown = meson_drv_shutdown,
.driver = {
.name = "meson-drm",

View File

@ -25,6 +25,12 @@ enum vpu_compatible {
VPU_COMPATIBLE_G12A = 3,
};
enum {
MESON_ENC_CVBS = 0,
MESON_ENC_HDMI,
MESON_ENC_LAST,
};
struct meson_drm_match_data {
enum vpu_compatible compat;
struct meson_afbcd_ops *afbcd_ops;
@ -51,6 +57,7 @@ struct meson_drm {
struct drm_crtc *crtc;
struct drm_plane *primary_plane;
struct drm_plane *overlay_plane;
void *encoders[MESON_ENC_LAST];
const struct meson_drm_soc_limits *limits;

View File

@ -281,5 +281,18 @@ int meson_encoder_cvbs_init(struct meson_drm *priv)
}
drm_connector_attach_encoder(connector, &meson_encoder_cvbs->encoder);
priv->encoders[MESON_ENC_CVBS] = meson_encoder_cvbs;
return 0;
}
void meson_encoder_cvbs_remove(struct meson_drm *priv)
{
struct meson_encoder_cvbs *meson_encoder_cvbs;
if (priv->encoders[MESON_ENC_CVBS]) {
meson_encoder_cvbs = priv->encoders[MESON_ENC_CVBS];
drm_bridge_remove(&meson_encoder_cvbs->bridge);
drm_bridge_remove(meson_encoder_cvbs->next_bridge);
}
}

View File

@ -25,5 +25,6 @@ struct meson_cvbs_mode {
extern struct meson_cvbs_mode meson_cvbs_modes[MESON_CVBS_MODES_COUNT];
int meson_encoder_cvbs_init(struct meson_drm *priv);
void meson_encoder_cvbs_remove(struct meson_drm *priv);
#endif /* __MESON_VENC_CVBS_H */

View File

@ -452,6 +452,8 @@ int meson_encoder_hdmi_init(struct meson_drm *priv)
meson_encoder_hdmi->cec_notifier = notifier;
}
priv->encoders[MESON_ENC_HDMI] = meson_encoder_hdmi;
dev_dbg(priv->dev, "HDMI encoder initialized\n");
return 0;
@ -460,3 +462,14 @@ err_put_node:
of_node_put(remote);
return ret;
}
void meson_encoder_hdmi_remove(struct meson_drm *priv)
{
struct meson_encoder_hdmi *meson_encoder_hdmi;
if (priv->encoders[MESON_ENC_HDMI]) {
meson_encoder_hdmi = priv->encoders[MESON_ENC_HDMI];
drm_bridge_remove(&meson_encoder_hdmi->bridge);
drm_bridge_remove(meson_encoder_hdmi->next_bridge);
}
}

View File

@ -8,5 +8,6 @@
#define __MESON_ENCODER_HDMI_H
int meson_encoder_hdmi_init(struct meson_drm *priv);
void meson_encoder_hdmi_remove(struct meson_drm *priv);
#endif /* __MESON_ENCODER_HDMI_H */

View File

@ -403,17 +403,10 @@ static int panel_edp_unprepare(struct drm_panel *panel)
static int panel_edp_get_hpd_gpio(struct device *dev, struct panel_edp *p)
{
int err;
p->hpd_gpio = devm_gpiod_get_optional(dev, "hpd", GPIOD_IN);
if (IS_ERR(p->hpd_gpio)) {
err = PTR_ERR(p->hpd_gpio);
if (err != -EPROBE_DEFER)
dev_err(dev, "failed to get 'hpd' GPIO: %d\n", err);
return err;
}
if (IS_ERR(p->hpd_gpio))
return dev_err_probe(dev, PTR_ERR(p->hpd_gpio),
"failed to get 'hpd' GPIO\n");
return 0;
}
@ -832,12 +825,9 @@ static int panel_edp_probe(struct device *dev, const struct panel_desc *desc,
panel->enable_gpio = devm_gpiod_get_optional(dev, "enable",
GPIOD_OUT_LOW);
if (IS_ERR(panel->enable_gpio)) {
err = PTR_ERR(panel->enable_gpio);
if (err != -EPROBE_DEFER)
dev_err(dev, "failed to request GPIO: %d\n", err);
return err;
}
if (IS_ERR(panel->enable_gpio))
return dev_err_probe(dev, PTR_ERR(panel->enable_gpio),
"failed to request GPIO\n");
err = of_drm_get_panel_orientation(dev->of_node, &panel->orientation);
if (err) {
@ -1878,6 +1868,7 @@ static const struct panel_delay delay_200_500_e200 = {
static const struct edp_panel_entry edp_panels[] = {
EDP_PANEL_ENTRY('A', 'U', 'O', 0x1062, &delay_200_500_e50, "B120XAN01.0"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x1e9b, &delay_200_500_e50, "B133UAN02.1"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x1ea5, &delay_200_500_e50, "B116XAK01.6"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x405c, &auo_b116xak01.delay, "B116XAK01"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x615c, &delay_200_500_e50, "B116XAN06.1"),
EDP_PANEL_ENTRY('A', 'U', 'O', 0x8594, &delay_200_500_e50, "B133UAN01.0"),
@ -1885,10 +1876,15 @@ static const struct edp_panel_entry edp_panels[] = {
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0786, &delay_200_500_p2e80, "NV116WHM-T01"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x07d1, &boe_nv133fhm_n61.delay, "NV133FHM-N61"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x082d, &boe_nv133fhm_n61.delay, "NV133FHM-N62"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x094b, &delay_200_500_e50, "NT116WHM-N21"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x098d, &boe_nv110wtm_n61.delay, "NV110WTM-N61"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x09dd, &delay_200_500_e50, "NT116WHM-N21"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0a5d, &delay_200_500_e50, "NV116WHM-N45"),
EDP_PANEL_ENTRY('B', 'O', 'E', 0x0ac5, &delay_200_500_e50, "NV116WHM-N4C"),
EDP_PANEL_ENTRY('C', 'M', 'N', 0x114c, &innolux_n116bca_ea1.delay, "N116BCA-EA1"),
EDP_PANEL_ENTRY('C', 'M', 'N', 0x1152, &delay_200_500_e80_d50, "N116BCN-EA1"),
EDP_PANEL_ENTRY('C', 'M', 'N', 0x1154, &delay_200_500_e80_d50, "N116BCA-EA2"),
EDP_PANEL_ENTRY('C', 'M', 'N', 0x1247, &delay_200_500_e80_d50, "N120ACA-EA1"),
EDP_PANEL_ENTRY('I', 'V', 'O', 0x057d, &delay_200_500_e200, "R140NWF5 RH"),

View File

@ -575,12 +575,9 @@ static int panel_simple_probe(struct device *dev, const struct panel_desc *desc)
panel->enable_gpio = devm_gpiod_get_optional(dev, "enable",
GPIOD_OUT_LOW);
if (IS_ERR(panel->enable_gpio)) {
err = PTR_ERR(panel->enable_gpio);
if (err != -EPROBE_DEFER)
dev_err(dev, "failed to request GPIO: %d\n", err);
return err;
}
if (IS_ERR(panel->enable_gpio))
return dev_err_probe(dev, PTR_ERR(panel->enable_gpio),
"failed to request GPIO\n");
err = of_drm_get_panel_orientation(dev->of_node, &panel->orientation);
if (err) {
@ -2701,6 +2698,36 @@ static const struct panel_desc multi_inno_mi0700s4t_6 = {
.connector_type = DRM_MODE_CONNECTOR_DPI,
};
static const struct display_timing multi_inno_mi0800ft_9_timing = {
.pixelclock = { 32000000, 40000000, 50000000 },
.hactive = { 800, 800, 800 },
.hfront_porch = { 16, 210, 354 },
.hback_porch = { 6, 26, 45 },
.hsync_len = { 1, 20, 40 },
.vactive = { 600, 600, 600 },
.vfront_porch = { 1, 12, 77 },
.vback_porch = { 3, 13, 22 },
.vsync_len = { 1, 10, 20 },
.flags = DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_LOW |
DISPLAY_FLAGS_DE_HIGH | DISPLAY_FLAGS_PIXDATA_POSEDGE |
DISPLAY_FLAGS_SYNC_POSEDGE,
};
static const struct panel_desc multi_inno_mi0800ft_9 = {
.timings = &multi_inno_mi0800ft_9_timing,
.num_timings = 1,
.bpc = 8,
.size = {
.width = 162,
.height = 122,
},
.bus_format = MEDIA_BUS_FMT_RGB888_1X24,
.bus_flags = DRM_BUS_FLAG_DE_HIGH |
DRM_BUS_FLAG_PIXDATA_SAMPLE_NEGEDGE |
DRM_BUS_FLAG_SYNC_SAMPLE_NEGEDGE,
.connector_type = DRM_MODE_CONNECTOR_DPI,
};
static const struct display_timing multi_inno_mi1010ait_1cp_timing = {
.pixelclock = { 68900000, 70000000, 73400000 },
.hactive = { 1280, 1280, 1280 },
@ -4132,6 +4159,9 @@ static const struct of_device_id platform_of_match[] = {
}, {
.compatible = "multi-inno,mi0700s4t-6",
.data = &multi_inno_mi0700s4t_6,
}, {
.compatible = "multi-inno,mi0800ft-9",
.data = &multi_inno_mi0800ft_9,
}, {
.compatible = "multi-inno,mi1010ait-1cp",
.data = &multi_inno_mi1010ait_1cp,

View File

@ -53,17 +53,11 @@ void qxl_ring_free(struct qxl_ring *ring)
kfree(ring);
}
void qxl_ring_init_hdr(struct qxl_ring *ring)
{
ring->ring->header.notify_on_prod = ring->n_elements;
}
struct qxl_ring *
qxl_ring_create(struct qxl_ring_header *header,
int element_size,
int n_elements,
int prod_notify,
bool set_prod_notify,
wait_queue_head_t *push_event)
{
struct qxl_ring *ring;
@ -77,8 +71,6 @@ qxl_ring_create(struct qxl_ring_header *header,
ring->n_elements = n_elements;
ring->prod_notify = prod_notify;
ring->push_event = push_event;
if (set_prod_notify)
qxl_ring_init_hdr(ring);
spin_lock_init(&ring->lock);
return ring;
}

View File

@ -277,10 +277,8 @@ struct qxl_ring *qxl_ring_create(struct qxl_ring_header *header,
int element_size,
int n_elements,
int prod_notify,
bool set_prod_notify,
wait_queue_head_t *push_event);
void qxl_ring_free(struct qxl_ring *ring);
void qxl_ring_init_hdr(struct qxl_ring *ring);
int qxl_check_idle(struct qxl_ring *ring);
static inline uint64_t

View File

@ -194,7 +194,6 @@ int qxl_device_init(struct qxl_device *qdev,
sizeof(struct qxl_command),
QXL_COMMAND_RING_SIZE,
qdev->io_base + QXL_IO_NOTIFY_CMD,
false,
&qdev->display_event);
if (!qdev->command_ring) {
DRM_ERROR("Unable to create command ring\n");
@ -207,7 +206,6 @@ int qxl_device_init(struct qxl_device *qdev,
sizeof(struct qxl_command),
QXL_CURSOR_RING_SIZE,
qdev->io_base + QXL_IO_NOTIFY_CURSOR,
false,
&qdev->cursor_event);
if (!qdev->cursor_ring) {
@ -219,7 +217,7 @@ int qxl_device_init(struct qxl_device *qdev,
qdev->release_ring = qxl_ring_create(
&(qdev->ram_header->release_ring_hdr),
sizeof(uint64_t),
QXL_RELEASE_RING_SIZE, 0, true,
QXL_RELEASE_RING_SIZE, 0,
NULL);
if (!qdev->release_ring) {

View File

@ -555,21 +555,28 @@ static int ssd130x_fb_blit_rect(struct drm_framebuffer *fb, const struct iosys_m
if (!buf)
return -ENOMEM;
ret = drm_gem_fb_begin_cpu_access(fb, DMA_FROM_DEVICE);
if (ret)
goto out_free;
iosys_map_set_vaddr(&dst, buf);
drm_fb_xrgb8888_to_mono(&dst, &dst_pitch, vmap, fb, rect);
drm_gem_fb_end_cpu_access(fb, DMA_FROM_DEVICE);
ssd130x_update_rect(ssd130x, buf, rect);
out_free:
kfree(buf);
return ret;
}
static void ssd130x_primary_plane_helper_atomic_update(struct drm_plane *plane,
struct drm_atomic_state *old_state)
struct drm_atomic_state *state)
{
struct drm_plane_state *plane_state = plane->state;
struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(old_state, plane);
struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane);
struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane);
struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state);
struct drm_device *drm = plane->dev;
struct drm_rect src_clip, dst_clip;
@ -591,7 +598,7 @@ static void ssd130x_primary_plane_helper_atomic_update(struct drm_plane *plane,
}
static void ssd130x_primary_plane_helper_atomic_disable(struct drm_plane *plane,
struct drm_atomic_state *old_state)
struct drm_atomic_state *state)
{
struct drm_device *drm = plane->dev;
struct ssd130x_device *ssd130x = drm_to_ssd130x(drm);

View File

@ -16,6 +16,11 @@
#define TEST_BUF_SIZE 50
struct convert_to_gray8_result {
unsigned int dst_pitch;
const u8 expected[TEST_BUF_SIZE];
};
struct convert_to_rgb332_result {
unsigned int dst_pitch;
const u8 expected[TEST_BUF_SIZE];
@ -27,13 +32,26 @@ struct convert_to_rgb565_result {
const u16 expected_swab[TEST_BUF_SIZE];
};
struct convert_to_rgb888_result {
unsigned int dst_pitch;
const u8 expected[TEST_BUF_SIZE];
};
struct convert_to_xrgb2101010_result {
unsigned int dst_pitch;
const u32 expected[TEST_BUF_SIZE];
};
struct convert_xrgb8888_case {
const char *name;
unsigned int pitch;
struct drm_rect clip;
const u32 xrgb8888[TEST_BUF_SIZE];
struct convert_to_gray8_result gray8_result;
struct convert_to_rgb332_result rgb332_result;
struct convert_to_rgb565_result rgb565_result;
struct convert_to_rgb888_result rgb888_result;
struct convert_to_xrgb2101010_result xrgb2101010_result;
};
static struct convert_xrgb8888_case convert_xrgb8888_cases[] = {
@ -42,6 +60,10 @@ static struct convert_xrgb8888_case convert_xrgb8888_cases[] = {
.pitch = 1 * 4,
.clip = DRM_RECT_INIT(0, 0, 1, 1),
.xrgb8888 = { 0x01FF0000 },
.gray8_result = {
.dst_pitch = 0,
.expected = { 0x4C },
},
.rgb332_result = {
.dst_pitch = 0,
.expected = { 0xE0 },
@ -51,6 +73,14 @@ static struct convert_xrgb8888_case convert_xrgb8888_cases[] = {
.expected = { 0xF800 },
.expected_swab = { 0x00F8 },
},
.rgb888_result = {
.dst_pitch = 0,
.expected = { 0x00, 0x00, 0xFF },
},
.xrgb2101010_result = {
.dst_pitch = 0,
.expected = { 0x3FF00000 },
},
},
{
.name = "single_pixel_clip_rectangle",
@ -60,6 +90,10 @@ static struct convert_xrgb8888_case convert_xrgb8888_cases[] = {
0x00000000, 0x00000000,
0x00000000, 0x10FF0000,
},
.gray8_result = {
.dst_pitch = 0,
.expected = { 0x4C },
},
.rgb332_result = {
.dst_pitch = 0,
.expected = { 0xE0 },
@ -69,6 +103,14 @@ static struct convert_xrgb8888_case convert_xrgb8888_cases[] = {
.expected = { 0xF800 },
.expected_swab = { 0x00F8 },
},
.rgb888_result = {
.dst_pitch = 0,
.expected = { 0x00, 0x00, 0xFF },
},
.xrgb2101010_result = {
.dst_pitch = 0,
.expected = { 0x3FF00000 },
},
},
{
/* Well known colors: White, black, red, green, blue, magenta,
@ -85,6 +127,15 @@ static struct convert_xrgb8888_case convert_xrgb8888_cases[] = {
0x00000000, 0x550000FF, 0x66FF00FF, 0x00000000,
0x00000000, 0x77FFFF00, 0x8800FFFF, 0x00000000,
},
.gray8_result = {
.dst_pitch = 0,
.expected = {
0xFF, 0x00,
0x4C, 0x99,
0x19, 0x66,
0xE5, 0xB2,
},
},
.rgb332_result = {
.dst_pitch = 0,
.expected = {
@ -109,6 +160,24 @@ static struct convert_xrgb8888_case convert_xrgb8888_cases[] = {
0xE0FF, 0xFF07,
},
},
.rgb888_result = {
.dst_pitch = 0,
.expected = {
0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00,
0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00,
0xFF, 0x00, 0x00, 0xFF, 0x00, 0xFF,
0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
},
},
.xrgb2101010_result = {
.dst_pitch = 0,
.expected = {
0x3FFFFFFF, 0x00000000,
0x3FF00000, 0x000FFC00,
0x000003FF, 0x3FF003FF,
0x3FFFFC00, 0x000FFFFF,
},
},
},
{
/* Randomly picked colors. Full buffer within the clip area. */
@ -120,6 +189,14 @@ static struct convert_xrgb8888_case convert_xrgb8888_cases[] = {
0xD16C7073, 0xA20E449C, 0xB2114D05,
0xC2A80303, 0xD26C7073, 0xA30E449C,
},
.gray8_result = {
.dst_pitch = 5,
.expected = {
0x3C, 0x33, 0x34, 0x00, 0x00,
0x6F, 0x3C, 0x33, 0x00, 0x00,
0x34, 0x6F, 0x3C, 0x00, 0x00,
},
},
.rgb332_result = {
.dst_pitch = 5,
.expected = {
@ -141,6 +218,25 @@ static struct convert_xrgb8888_case convert_xrgb8888_cases[] = {
0x00A8, 0x8E6B, 0x330A, 0x0000, 0x0000,
},
},
.rgb888_result = {
.dst_pitch = 15,
.expected = {
0x9C, 0x44, 0x0E, 0x05, 0x4D, 0x11, 0x03, 0x03, 0xA8,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x73, 0x70, 0x6C, 0x9C, 0x44, 0x0E, 0x05, 0x4D, 0x11,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x03, 0x03, 0xA8, 0x73, 0x70, 0x6C, 0x9C, 0x44, 0x0E,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
},
},
.xrgb2101010_result = {
.dst_pitch = 20,
.expected = {
0x03844672, 0x0444D414, 0x2A20300C, 0x00000000, 0x00000000,
0x1B1705CD, 0x03844672, 0x0444D414, 0x00000000, 0x00000000,
0x2A20300C, 0x1B1705CD, 0x03844672, 0x00000000, 0x00000000,
},
},
},
};
@ -192,6 +288,36 @@ static void convert_xrgb8888_case_desc(struct convert_xrgb8888_case *t,
KUNIT_ARRAY_PARAM(convert_xrgb8888, convert_xrgb8888_cases,
convert_xrgb8888_case_desc);
static void drm_test_fb_xrgb8888_to_gray8(struct kunit *test)
{
const struct convert_xrgb8888_case *params = test->param_value;
const struct convert_to_gray8_result *result = &params->gray8_result;
size_t dst_size;
__u8 *buf = NULL;
__u32 *xrgb8888 = NULL;
struct iosys_map dst, src;
struct drm_framebuffer fb = {
.format = drm_format_info(DRM_FORMAT_XRGB8888),
.pitches = { params->pitch, 0, 0 },
};
dst_size = conversion_buf_size(DRM_FORMAT_R8, result->dst_pitch,
&params->clip);
KUNIT_ASSERT_GT(test, dst_size, 0);
buf = kunit_kzalloc(test, dst_size, GFP_KERNEL);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, buf);
iosys_map_set_vaddr(&dst, buf);
xrgb8888 = le32buf_to_cpu(test, params->xrgb8888, TEST_BUF_SIZE);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xrgb8888);
iosys_map_set_vaddr(&src, xrgb8888);
drm_fb_xrgb8888_to_gray8(&dst, &result->dst_pitch, &src, &fb, &params->clip);
KUNIT_EXPECT_EQ(test, memcmp(buf, result->expected, dst_size), 0);
}
static void drm_test_fb_xrgb8888_to_rgb332(struct kunit *test)
{
const struct convert_xrgb8888_case *params = test->param_value;
@ -255,9 +381,73 @@ static void drm_test_fb_xrgb8888_to_rgb565(struct kunit *test)
KUNIT_EXPECT_EQ(test, memcmp(buf, result->expected_swab, dst_size), 0);
}
static void drm_test_fb_xrgb8888_to_rgb888(struct kunit *test)
{
const struct convert_xrgb8888_case *params = test->param_value;
const struct convert_to_rgb888_result *result = &params->rgb888_result;
size_t dst_size;
__u8 *buf = NULL;
__u32 *xrgb8888 = NULL;
struct iosys_map dst, src;
struct drm_framebuffer fb = {
.format = drm_format_info(DRM_FORMAT_XRGB8888),
.pitches = { params->pitch, 0, 0 },
};
dst_size = conversion_buf_size(DRM_FORMAT_RGB888, result->dst_pitch,
&params->clip);
KUNIT_ASSERT_GT(test, dst_size, 0);
buf = kunit_kzalloc(test, dst_size, GFP_KERNEL);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, buf);
iosys_map_set_vaddr(&dst, buf);
xrgb8888 = le32buf_to_cpu(test, params->xrgb8888, TEST_BUF_SIZE);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xrgb8888);
iosys_map_set_vaddr(&src, xrgb8888);
drm_fb_xrgb8888_to_rgb888(&dst, &result->dst_pitch, &src, &fb, &params->clip);
KUNIT_EXPECT_EQ(test, memcmp(buf, result->expected, dst_size), 0);
}
static void drm_test_fb_xrgb8888_to_xrgb2101010(struct kunit *test)
{
const struct convert_xrgb8888_case *params = test->param_value;
const struct convert_to_xrgb2101010_result *result = &params->xrgb2101010_result;
size_t dst_size;
__u32 *buf = NULL;
__u32 *xrgb8888 = NULL;
struct iosys_map dst, src;
struct drm_framebuffer fb = {
.format = drm_format_info(DRM_FORMAT_XRGB8888),
.pitches = { params->pitch, 0, 0 },
};
dst_size = conversion_buf_size(DRM_FORMAT_XRGB2101010,
result->dst_pitch, &params->clip);
KUNIT_ASSERT_GT(test, dst_size, 0);
buf = kunit_kzalloc(test, dst_size, GFP_KERNEL);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, buf);
iosys_map_set_vaddr(&dst, buf);
xrgb8888 = le32buf_to_cpu(test, params->xrgb8888, TEST_BUF_SIZE);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xrgb8888);
iosys_map_set_vaddr(&src, xrgb8888);
drm_fb_xrgb8888_to_xrgb2101010(&dst, &result->dst_pitch, &src, &fb, &params->clip);
buf = le32buf_to_cpu(test, buf, TEST_BUF_SIZE);
KUNIT_EXPECT_EQ(test, memcmp(buf, result->expected, dst_size), 0);
}
static struct kunit_case drm_format_helper_test_cases[] = {
KUNIT_CASE_PARAM(drm_test_fb_xrgb8888_to_gray8, convert_xrgb8888_gen_params),
KUNIT_CASE_PARAM(drm_test_fb_xrgb8888_to_rgb332, convert_xrgb8888_gen_params),
KUNIT_CASE_PARAM(drm_test_fb_xrgb8888_to_rgb565, convert_xrgb8888_gen_params),
KUNIT_CASE_PARAM(drm_test_fb_xrgb8888_to_rgb888, convert_xrgb8888_gen_params),
KUNIT_CASE_PARAM(drm_test_fb_xrgb8888_to_xrgb2101010, convert_xrgb8888_gen_params),
{}
};

View File

@ -470,40 +470,45 @@ static const uint64_t simpledrm_primary_plane_format_modifiers[] = {
};
static void simpledrm_primary_plane_helper_atomic_update(struct drm_plane *plane,
struct drm_atomic_state *old_state)
struct drm_atomic_state *state)
{
struct drm_plane_state *plane_state = plane->state;
struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(old_state, plane);
struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane);
struct drm_plane_state *old_plane_state = drm_atomic_get_old_plane_state(state, plane);
struct drm_shadow_plane_state *shadow_plane_state = to_drm_shadow_plane_state(plane_state);
struct drm_framebuffer *fb = plane_state->fb;
struct drm_device *dev = plane->dev;
struct simpledrm_device *sdev = simpledrm_device_of_dev(dev);
struct iosys_map dst = IOSYS_MAP_INIT_VADDR(sdev->screen_base);
struct drm_rect src_clip, dst_clip;
int idx;
struct drm_atomic_helper_damage_iter iter;
struct drm_rect damage;
int ret, idx;
if (!fb)
return;
if (!drm_atomic_helper_damage_merged(old_plane_state, plane_state, &src_clip))
return;
dst_clip = plane_state->dst;
if (!drm_rect_intersect(&dst_clip, &src_clip))
ret = drm_gem_fb_begin_cpu_access(fb, DMA_FROM_DEVICE);
if (ret)
return;
if (!drm_dev_enter(dev, &idx))
return;
goto out_drm_gem_fb_end_cpu_access;
iosys_map_incr(&dst, drm_fb_clip_offset(sdev->pitch, sdev->format, &dst_clip));
drm_fb_blit(&dst, &sdev->pitch, sdev->format->format, shadow_plane_state->data, fb,
&src_clip);
drm_atomic_helper_damage_iter_init(&iter, old_plane_state, plane_state);
drm_atomic_for_each_plane_damage(&iter, &damage) {
struct iosys_map dst = IOSYS_MAP_INIT_VADDR(sdev->screen_base);
struct drm_rect dst_clip = plane_state->dst;
if (!drm_rect_intersect(&dst_clip, &damage))
continue;
iosys_map_incr(&dst, drm_fb_clip_offset(sdev->pitch, sdev->format, &dst_clip));
drm_fb_blit(&dst, &sdev->pitch, sdev->format->format, shadow_plane_state->data, fb,
&damage);
}
drm_dev_exit(idx);
out_drm_gem_fb_end_cpu_access:
drm_gem_fb_end_cpu_access(fb, DMA_FROM_DEVICE);
}
static void simpledrm_primary_plane_helper_atomic_disable(struct drm_plane *plane,
struct drm_atomic_state *old_state)
struct drm_atomic_state *state)
{
struct drm_device *dev = plane->dev;
struct simpledrm_device *sdev = simpledrm_device_of_dev(dev);
@ -687,8 +692,11 @@ static struct simpledrm_device *simpledrm_device_create(struct drm_driver *drv,
drm_err(dev, "no simplefb configuration found\n");
return ERR_PTR(-ENODEV);
}
if (!stride)
stride = DIV_ROUND_UP(drm_format_info_bpp(format, 0) * width, 8);
if (!stride) {
stride = drm_format_info_min_pitch(format, 0, width);
if (drm_WARN_ON(dev, !stride))
return ERR_PTR(-EINVAL);
}
sdev->mode = simpledrm_mode(width, height);
sdev->format = format;

View File

@ -402,6 +402,8 @@ int ttm_bo_vmap(struct ttm_buffer_object *bo, struct iosys_map *map)
struct ttm_resource *mem = bo->resource;
int ret;
dma_resv_assert_held(bo->base.resv);
ret = ttm_mem_io_reserve(bo->bdev, mem);
if (ret)
return ret;
@ -460,6 +462,8 @@ void ttm_bo_vunmap(struct ttm_buffer_object *bo, struct iosys_map *map)
{
struct ttm_resource *mem = bo->resource;
dma_resv_assert_held(bo->base.resv);
if (iosys_map_is_null(map))
return;

View File

@ -47,7 +47,7 @@ static int virtio_gpu_fence_event_create(struct drm_device *dev,
struct virtio_gpu_fence_event *e = NULL;
int ret;
if (!(vfpriv->ring_idx_mask & (1 << ring_idx)))
if (!(vfpriv->ring_idx_mask & BIT_ULL(ring_idx)))
return 0;
e = kzalloc(sizeof(*e), GFP_KERNEL);