Commit 91fdc5e7 authored by Dave Airlie's avatar Dave Airlie

Merge tag 'drm-misc-next-2024-06-27' of...

Merge tag 'drm-misc-next-2024-06-27' of https://gitlab.freedesktop.org/drm/misc/kernel into drm-next

drm-misc-next for 6.11:

UAPI Changes:

Cross-subsystem Changes:

Core Changes:
  - panic: Monochrome logo support, Various fixes
  - ttm: Improve the number of page faults on some platforms, Fix test
    build breakage with PREEMPT_RT, more test coverage and various test
    improvements

Driver Changes:
  - Add missing MODULE_DESCRIPTION where needed
  - ipu-v3: Various fixes
  - vc4: Monochrome TV support
  - bridge:
    - analogix_dp: Various improvements and reworks, handle AUX
      transfers timeout
    - tc358767: Fix DRM_BRIDGE_ATTACH_NO_CONNECTOR, Fix clock
      calculations
  - panels:
    - More transitions to mipi_dsi wrapped functions
    - New panels: Lincoln Technologies LCD197, Ortustech COM35H3P70ULC,
Signed-off-by: default avatarDave Airlie <airlied@redhat.com>

From: Maxime Ripard <mripard@redhat.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20240627-congenial-pistachio-nyala-848cf4@houat
parents 275fee9d 61bfcd19
......@@ -71,6 +71,10 @@ properties:
- const: iahb
- const: venci
power-domains:
maxItems: 1
description: phandle to the associated power domain
resets:
minItems: 3
......@@ -129,6 +133,7 @@ examples:
reset-names = "hdmitx_apb", "hdmitx", "hdmitx_phy";
clocks = <&clk_isfr>, <&clk_iahb>, <&clk_venci>;
clock-names = "isfr", "iahb", "venci";
power-domains = <&pd_vpu>;
#address-cells = <1>;
#size-cells = <0>;
......
......@@ -45,6 +45,19 @@ properties:
- const: isfr
additionalItems: true
ddc-i2c-bus:
$ref: /schemas/types.yaml#/definitions/phandle
deprecated: true
description:
The HDMI DDC bus can be connected to either a system I2C master or the
functionally-reduced I2C master contained in the DWC HDMI. When connected
to a system I2C master this property contains a phandle to that I2C
master controller.
This property is deprecated, the system I2C master controller should
be referenced through the ddc-i2c-bus property of the HDMI connector
node.
interrupts:
maxItems: 1
......
......@@ -25,8 +25,8 @@ properties:
reg:
enum:
- 0x68
- 0x0f
- 0x68
description: |
i2c address of the bridge, 0x68 or 0x0f, depending on bootstrap pins
......
......@@ -31,14 +31,6 @@ properties:
clock-names:
maxItems: 2
ddc-i2c-bus:
$ref: /schemas/types.yaml#/definitions/phandle
description:
The HDMI DDC bus can be connected to either a system I2C master or the
functionally-reduced I2C master contained in the DWC HDMI. When connected
to a system I2C master this property contains a phandle to that I2C
master controller.
gpr:
$ref: /schemas/types.yaml#/definitions/phandle
description:
......
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/display/panel/ilitek,ili9806e.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Ilitek ILI9806E based MIPI-DSI panels
maintainers:
- Michael Walle <mwalle@kernel.org>
allOf:
- $ref: panel-common.yaml#
properties:
compatible:
items:
- enum:
- ortustech,com35h3p70ulc
- const: ilitek,ili9806e
reg:
maxItems: 1
vdd-supply: true
vccio-supply: true
required:
- compatible
- reg
- vdd-supply
- vccio-supply
- reset-gpios
- backlight
- port
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/gpio/gpio.h>
dsi {
#address-cells = <1>;
#size-cells = <0>;
panel@0 {
compatible = "ortustech,com35h3p70ulc", "ilitek,ili9806e";
reg = <0>;
vdd-supply = <&reg_vdd_panel>;
vccio-supply = <&reg_vccio_panel>;
reset-gpios = <&gpio3 6 GPIO_ACTIVE_LOW>;
backlight = <&backlight>;
port {
panel_in: endpoint {
remote-endpoint = <&dsi_out>;
};
};
};
};
...
......@@ -46,6 +46,8 @@ properties:
- lg,ld070wx3-sl01
# LG Corporation 5" HD TFT LCD panel
- lg,lh500wx1-sd03
# Lincoln LCD197 5" 1080x1920 LCD panel
- lincolntech,lcd197
# One Stop Displays OSD101T2587-53TS 10.1" 1920x1200 panel
- osddisplays,osd101t2587-53ts
# Panasonic 10" WUXGA TFT LCD panel
......
......@@ -70,14 +70,6 @@ properties:
- vpll
- ref
ddc-i2c-bus:
$ref: /schemas/types.yaml#/definitions/phandle
description:
The HDMI DDC bus can be connected to either a system I2C master or the
functionally-reduced I2C master contained in the DWC HDMI. When connected
to a system I2C master this property contains a phandle to that I2C
master controller.
phys:
maxItems: 1
description: The HDMI PHY
......
......@@ -6899,6 +6899,11 @@ S: Maintained
F: Documentation/devicetree/bindings/display/panel/ilitek,ili9805.yaml
F: drivers/gpu/drm/panel/panel-ilitek-ili9805.c
DRM DRIVER FOR ILITEK ILI9806E PANELS
M: Michael Walle <mwalle@kernel.org>
S: Maintained
F: drivers/gpu/drm/panel/panel-ilitek-ili9806e.c
DRM DRIVER FOR JADARD JD9365DA-H3 MIPI-DSI LCD PANELS
M: Jagan Teki <jagan@edgeble.ai>
S: Maintained
......@@ -7519,8 +7524,9 @@ F: include/uapi/drm/v3d_drm.h
DRM DRIVERS FOR VC4
M: Maxime Ripard <mripard@kernel.org>
M: Dave Stevenson <dave.stevenson@raspberrypi.com>
R: Raspberry Pi Kernel Maintenance <kernel-list@raspberrypi.com>
S: Supported
T: git git://github.com/anholt/linux
T: git https://gitlab.freedesktop.org/drm/misc/kernel.git
F: Documentation/devicetree/bindings/display/brcm,bcm2835-*.yaml
F: drivers/gpu/drm/vc4/
......
......@@ -108,7 +108,6 @@ config DRM_KMS_HELPER
config DRM_PANIC
bool "Display a user-friendly message when a kernel panic occurs"
depends on DRM && !(FRAMEBUFFER_CONSOLE && VT_CONSOLE)
select DRM_KMS_HELPER
select FONT_SUPPORT
help
Enable a drm panic handler, which will display a user-friendly message
......@@ -138,7 +137,7 @@ config DRM_PANIC_DEBUG
If in doubt, say "N".
config DRM_PANIC_SCREEN
string "Panic screen formater"
string "Panic screen formatter"
default "user"
depends on DRM_PANIC
help
......@@ -248,6 +247,7 @@ config DRM_TTM_KUNIT_TEST
default n
depends on DRM && KUNIT && MMU && (UML || COMPILE_TEST)
select DRM_TTM
select DRM_BUDDY
select DRM_EXPORT_FOR_TESTS if m
select DRM_KUNIT_TEST_HELPERS
default KUNIT_ALL_TESTS
......
......@@ -45,7 +45,6 @@
#include <drm/drm_managed.h>
#include <drm/drm_panic.h>
#include <drm/drm_probe_helper.h>
#include <drm/drm_simple_kms_helper.h>
#include "ast_ddc.h"
#include "ast_drv.h"
......@@ -1358,6 +1357,14 @@ static int ast_crtc_init(struct drm_device *dev)
return 0;
}
/*
* VGA Encoder
*/
static const struct drm_encoder_funcs ast_vga_encoder_funcs = {
.destroy = drm_encoder_cleanup,
};
/*
* VGA Connector
*/
......@@ -1411,7 +1418,8 @@ static int ast_vga_output_init(struct ast_device *ast)
struct drm_connector *connector = &ast->output.vga.connector;
int ret;
ret = drm_simple_encoder_init(dev, encoder, DRM_MODE_ENCODER_DAC);
ret = drm_encoder_init(dev, encoder, &ast_vga_encoder_funcs,
DRM_MODE_ENCODER_DAC, NULL);
if (ret)
return ret;
encoder->possible_crtcs = drm_crtc_mask(crtc);
......@@ -1427,6 +1435,14 @@ static int ast_vga_output_init(struct ast_device *ast)
return 0;
}
/*
* SIL164 Encoder
*/
static const struct drm_encoder_funcs ast_sil164_encoder_funcs = {
.destroy = drm_encoder_cleanup,
};
/*
* SIL164 Connector
*/
......@@ -1480,7 +1496,8 @@ static int ast_sil164_output_init(struct ast_device *ast)
struct drm_connector *connector = &ast->output.sil164.connector;
int ret;
ret = drm_simple_encoder_init(dev, encoder, DRM_MODE_ENCODER_TMDS);
ret = drm_encoder_init(dev, encoder, &ast_sil164_encoder_funcs,
DRM_MODE_ENCODER_TMDS, NULL);
if (ret)
return ret;
encoder->possible_crtcs = drm_crtc_mask(crtc);
......@@ -1496,6 +1513,14 @@ static int ast_sil164_output_init(struct ast_device *ast)
return 0;
}
/*
* DP501 Encoder
*/
static const struct drm_encoder_funcs ast_dp501_encoder_funcs = {
.destroy = drm_encoder_cleanup,
};
/*
* DP501 Connector
*/
......@@ -1578,7 +1603,8 @@ static int ast_dp501_output_init(struct ast_device *ast)
struct drm_connector *connector = &ast->output.dp501.connector;
int ret;
ret = drm_simple_encoder_init(dev, encoder, DRM_MODE_ENCODER_TMDS);
ret = drm_encoder_init(dev, encoder, &ast_dp501_encoder_funcs,
DRM_MODE_ENCODER_TMDS, NULL);
if (ret)
return ret;
encoder->possible_crtcs = drm_crtc_mask(crtc);
......@@ -1594,6 +1620,14 @@ static int ast_dp501_output_init(struct ast_device *ast)
return 0;
}
/*
* ASPEED Display-Port Encoder
*/
static const struct drm_encoder_funcs ast_astdp_encoder_funcs = {
.destroy = drm_encoder_cleanup,
};
/*
* ASPEED Display-Port Connector
*/
......@@ -1688,7 +1722,8 @@ static int ast_astdp_output_init(struct ast_device *ast)
struct drm_connector *connector = &ast->output.astdp.connector;
int ret;
ret = drm_simple_encoder_init(dev, encoder, DRM_MODE_ENCODER_TMDS);
ret = drm_encoder_init(dev, encoder, &ast_astdp_encoder_funcs,
DRM_MODE_ENCODER_TMDS, NULL);
if (ret)
return ret;
encoder->possible_crtcs = drm_crtc_mask(crtc);
......
......@@ -41,10 +41,8 @@ struct bridge_init {
struct device_node *node;
};
static int analogix_dp_init_dp(struct analogix_dp_device *dp)
static void analogix_dp_init_dp(struct analogix_dp_device *dp)
{
int ret;
analogix_dp_reset(dp);
analogix_dp_swreset(dp);
......@@ -56,13 +54,9 @@ static int analogix_dp_init_dp(struct analogix_dp_device *dp)
analogix_dp_enable_sw_function(dp);
analogix_dp_config_interrupt(dp);
ret = analogix_dp_init_analog_func(dp);
if (ret)
return ret;
analogix_dp_init_hpd(dp);
analogix_dp_init_aux(dp);
return 0;
}
static int analogix_dp_detect_hpd(struct analogix_dp_device *dp)
......@@ -237,7 +231,7 @@ static int analogix_dp_training_pattern_dis(struct analogix_dp_device *dp)
static int analogix_dp_link_start(struct analogix_dp_device *dp)
{
u8 buf[4];
int lane, lane_count, pll_tries, retval;
int lane, lane_count, retval;
lane_count = dp->link_train.lane_count;
......@@ -249,6 +243,16 @@ static int analogix_dp_link_start(struct analogix_dp_device *dp)
/* Set link rate and count as you want to establish*/
analogix_dp_set_link_bandwidth(dp, dp->link_train.link_rate);
retval = analogix_dp_wait_pll_locked(dp);
if (retval) {
DRM_DEV_ERROR(dp->dev, "Wait for pll lock failed %d\n", retval);
return retval;
}
/*
* MACRO_RST must be applied after the PLL_LOCK to avoid
* the DP inter pair skew issue for at least 10 us
*/
analogix_dp_reset_macro(dp);
analogix_dp_set_lane_count(dp, dp->link_train.lane_count);
/* Setup RX configuration */
......@@ -271,18 +275,6 @@ static int analogix_dp_link_start(struct analogix_dp_device *dp)
DP_TRAIN_PRE_EMPH_LEVEL_0;
analogix_dp_set_lane_link_training(dp);
/* Wait for PLL lock */
pll_tries = 0;
while (analogix_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) {
if (pll_tries == DP_TIMEOUT_LOOP_COUNT) {
dev_err(dp->dev, "Wait for PLL lock timed out\n");
return -ETIMEDOUT;
}
pll_tries++;
usleep_range(90, 120);
}
/* Set training pattern 1 */
analogix_dp_set_training_pattern(dp, TRAINING_PTN1);
......@@ -568,12 +560,6 @@ static int analogix_dp_full_link_train(struct analogix_dp_device *dp,
int retval = 0;
bool training_finished = false;
/*
* MACRO_RST must be applied after the PLL_LOCK to avoid
* the DP inter pair skew issue for at least 10 us
*/
analogix_dp_reset_macro(dp);
/* Initialize by reading RX's DPCD */
analogix_dp_get_max_rx_bandwidth(dp, &dp->link_train.link_rate);
analogix_dp_get_max_rx_lane_count(dp, &dp->link_train.lane_count);
......@@ -638,22 +624,22 @@ static int analogix_dp_fast_link_train(struct analogix_dp_device *dp)
{
int ret;
u8 link_align, link_status[2];
enum pll_status status;
analogix_dp_reset_macro(dp);
analogix_dp_set_link_bandwidth(dp, dp->link_train.link_rate);
analogix_dp_set_lane_count(dp, dp->link_train.lane_count);
analogix_dp_set_lane_link_training(dp);
ret = readx_poll_timeout(analogix_dp_get_pll_lock_status, dp, status,
status != PLL_UNLOCKED, 120,
120 * DP_TIMEOUT_LOOP_COUNT);
ret = analogix_dp_wait_pll_locked(dp);
if (ret) {
DRM_DEV_ERROR(dp->dev, "Wait for pll lock failed %d\n", ret);
return ret;
}
/*
* MACRO_RST must be applied after the PLL_LOCK to avoid
* the DP inter pair skew issue for at least 10 us
*/
analogix_dp_reset_macro(dp);
analogix_dp_set_lane_count(dp, dp->link_train.lane_count);
analogix_dp_set_lane_link_training(dp);
/* source Set training pattern 1 */
analogix_dp_set_training_pattern(dp, TRAINING_PTN1);
/* From DP spec, pattern must be on-screen for a minimum 500us */
......@@ -723,11 +709,6 @@ static int analogix_dp_config_video(struct analogix_dp_device *dp)
analogix_dp_set_video_color_format(dp);
if (analogix_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) {
dev_err(dp->dev, "PLL is not locked yet.\n");
return -EINVAL;
}
for (;;) {
timeout_loop++;
if (analogix_dp_is_slave_video_stream_clock_on(dp) == 0)
......@@ -1251,20 +1232,9 @@ static int analogix_dp_set_bridge(struct analogix_dp_device *dp)
pm_runtime_get_sync(dp->dev);
ret = clk_prepare_enable(dp->clock);
if (ret < 0) {
DRM_ERROR("Failed to prepare_enable the clock clk [%d]\n", ret);
goto out_dp_clk_pre;
}
if (dp->plat_data->power_on_start)
dp->plat_data->power_on_start(dp->plat_data);
phy_power_on(dp->phy);
ret = analogix_dp_init_dp(dp);
ret = analogix_dp_init_analog_func(dp);
if (ret)
goto out_dp_init;
return ret;
/*
* According to DP spec v1.3 chap 3.5.1.2 Link Training,
......@@ -1283,18 +1253,10 @@ static int analogix_dp_set_bridge(struct analogix_dp_device *dp)
goto out_dp_init;
}
if (dp->plat_data->power_on_end)
dp->plat_data->power_on_end(dp->plat_data);
enable_irq(dp->irq);
return 0;
out_dp_init:
phy_power_off(dp->phy);
if (dp->plat_data->power_off)
dp->plat_data->power_off(dp->plat_data);
clk_disable_unprepare(dp->clock);
out_dp_clk_pre:
pm_runtime_put_sync(dp->dev);
return ret;
......@@ -1357,13 +1319,7 @@ static void analogix_dp_bridge_disable(struct drm_bridge *bridge)
disable_irq(dp->irq);
if (dp->plat_data->power_off)
dp->plat_data->power_off(dp->plat_data);
analogix_dp_set_analog_power_down(dp, POWER_ALL, 1);
phy_power_off(dp->phy);
clk_disable_unprepare(dp->clock);
pm_runtime_put_sync(dp->dev);
......@@ -1654,8 +1610,6 @@ analogix_dp_probe(struct device *dev, struct analogix_dp_plat_data *plat_data)
return ERR_CAST(dp->clock);
}
clk_prepare_enable(dp->clock);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
dp->reg_base = devm_ioremap_resource(&pdev->dev, res);
......@@ -1717,6 +1671,40 @@ analogix_dp_probe(struct device *dev, struct analogix_dp_plat_data *plat_data)
}
EXPORT_SYMBOL_GPL(analogix_dp_probe);
int analogix_dp_suspend(struct analogix_dp_device *dp)
{
phy_power_off(dp->phy);
if (dp->plat_data->power_off)
dp->plat_data->power_off(dp->plat_data);
clk_disable_unprepare(dp->clock);
return 0;
}
EXPORT_SYMBOL_GPL(analogix_dp_suspend);
int analogix_dp_resume(struct analogix_dp_device *dp)
{
int ret;
ret = clk_prepare_enable(dp->clock);
if (ret < 0) {
DRM_ERROR("Failed to prepare_enable the clock clk [%d]\n", ret);
return ret;
}
if (dp->plat_data->power_on)
dp->plat_data->power_on(dp->plat_data);
phy_power_on(dp->phy);
analogix_dp_init_dp(dp);
return 0;
}
EXPORT_SYMBOL_GPL(analogix_dp_resume);
int analogix_dp_bind(struct analogix_dp_device *dp, struct drm_device *drm_dev)
{
int ret;
......@@ -1724,31 +1712,44 @@ int analogix_dp_bind(struct analogix_dp_device *dp, struct drm_device *drm_dev)
dp->drm_dev = drm_dev;
dp->encoder = dp->plat_data->encoder;
if (IS_ENABLED(CONFIG_PM)) {
pm_runtime_use_autosuspend(dp->dev);
pm_runtime_set_autosuspend_delay(dp->dev, 100);
pm_runtime_enable(dp->dev);
} else {
ret = analogix_dp_resume(dp);
if (ret)
return ret;
}
dp->aux.name = "DP-AUX";
dp->aux.transfer = analogix_dpaux_transfer;
dp->aux.dev = dp->dev;
dp->aux.drm_dev = drm_dev;
ret = drm_dp_aux_register(&dp->aux);
if (ret)
return ret;
pm_runtime_use_autosuspend(dp->dev);
pm_runtime_set_autosuspend_delay(dp->dev, 100);
pm_runtime_enable(dp->dev);
if (ret) {
DRM_ERROR("failed to register AUX (%d)\n", ret);
goto err_disable_pm_runtime;
}
ret = analogix_dp_create_bridge(drm_dev, dp);
if (ret) {
DRM_ERROR("failed to create bridge (%d)\n", ret);
goto err_disable_pm_runtime;
goto err_unregister_aux;
}
return 0;
err_disable_pm_runtime:
pm_runtime_dont_use_autosuspend(dp->dev);
pm_runtime_disable(dp->dev);
err_unregister_aux:
drm_dp_aux_unregister(&dp->aux);
err_disable_pm_runtime:
if (IS_ENABLED(CONFIG_PM)) {
pm_runtime_dont_use_autosuspend(dp->dev);
pm_runtime_disable(dp->dev);
} else {
analogix_dp_suspend(dp);
}
return ret;
}
......@@ -1765,39 +1766,15 @@ void analogix_dp_unbind(struct analogix_dp_device *dp)
}
drm_dp_aux_unregister(&dp->aux);
pm_runtime_dont_use_autosuspend(dp->dev);
pm_runtime_disable(dp->dev);
}
EXPORT_SYMBOL_GPL(analogix_dp_unbind);
void analogix_dp_remove(struct analogix_dp_device *dp)
{
clk_disable_unprepare(dp->clock);
}
EXPORT_SYMBOL_GPL(analogix_dp_remove);
#ifdef CONFIG_PM
int analogix_dp_suspend(struct analogix_dp_device *dp)
{
clk_disable_unprepare(dp->clock);
return 0;
}
EXPORT_SYMBOL_GPL(analogix_dp_suspend);
int analogix_dp_resume(struct analogix_dp_device *dp)
{
int ret;
ret = clk_prepare_enable(dp->clock);
if (ret < 0) {
DRM_ERROR("Failed to prepare_enable the clock clk [%d]\n", ret);
return ret;
if (IS_ENABLED(CONFIG_PM)) {
pm_runtime_dont_use_autosuspend(dp->dev);
pm_runtime_disable(dp->dev);
} else {
analogix_dp_suspend(dp);
}
return 0;
}
EXPORT_SYMBOL_GPL(analogix_dp_resume);
#endif
EXPORT_SYMBOL_GPL(analogix_dp_unbind);
int analogix_dp_start_crc(struct drm_connector *connector)
{
......
......@@ -95,11 +95,6 @@ enum dynamic_range {
CEA
};
enum pll_status {
PLL_UNLOCKED,
PLL_LOCKED
};
enum clock_recovery_m_value_type {
CALCULATED_M,
REGISTER_M
......@@ -191,7 +186,7 @@ void analogix_dp_swreset(struct analogix_dp_device *dp);
void analogix_dp_config_interrupt(struct analogix_dp_device *dp);
void analogix_dp_mute_hpd_interrupt(struct analogix_dp_device *dp);
void analogix_dp_unmute_hpd_interrupt(struct analogix_dp_device *dp);
enum pll_status analogix_dp_get_pll_lock_status(struct analogix_dp_device *dp);
int analogix_dp_wait_pll_locked(struct analogix_dp_device *dp);
void analogix_dp_set_pll_power_down(struct analogix_dp_device *dp, bool enable);
void analogix_dp_set_analog_power_down(struct analogix_dp_device *dp,
enum analog_power_block block,
......
......@@ -217,15 +217,13 @@ void analogix_dp_unmute_hpd_interrupt(struct analogix_dp_device *dp)
writel(reg, dp->reg_base + ANALOGIX_DP_INT_STA_MASK);
}
enum pll_status analogix_dp_get_pll_lock_status(struct analogix_dp_device *dp)
int analogix_dp_wait_pll_locked(struct analogix_dp_device *dp)
{
u32 reg;
u32 val;
reg = readl(dp->reg_base + ANALOGIX_DP_DEBUG_CTL);
if (reg & PLL_LOCK)
return PLL_LOCKED;
else
return PLL_UNLOCKED;
return readl_poll_timeout(dp->reg_base + ANALOGIX_DP_DEBUG_CTL, val,
val & PLL_LOCK, 120,
120 * DP_TIMEOUT_LOOP_COUNT);
}
void analogix_dp_set_pll_power_down(struct analogix_dp_device *dp, bool enable)
......@@ -356,7 +354,6 @@ void analogix_dp_set_analog_power_down(struct analogix_dp_device *dp,
int analogix_dp_init_analog_func(struct analogix_dp_device *dp)
{
u32 reg;
int timeout_loop = 0;
analogix_dp_set_analog_power_down(dp, POWER_ALL, 0);
......@@ -368,18 +365,7 @@ int analogix_dp_init_analog_func(struct analogix_dp_device *dp)
writel(reg, dp->reg_base + ANALOGIX_DP_DEBUG_CTL);
/* Power up PLL */
if (analogix_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) {
analogix_dp_set_pll_power_down(dp, 0);
while (analogix_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) {
timeout_loop++;
if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) {
dev_err(dp->dev, "failed to get pll lock status\n");
return -ETIMEDOUT;
}
usleep_range(10, 20);
}
}
analogix_dp_set_pll_power_down(dp, 0);
/* Enable Serdes FIFO function and Link symbol clock domain module */
reg = readl(dp->reg_base + ANALOGIX_DP_FUNC_EN_2);
......@@ -938,7 +924,6 @@ ssize_t analogix_dp_transfer(struct analogix_dp_device *dp,
struct drm_dp_aux_msg *msg)
{
u32 reg;
u32 status_reg;
u8 *buffer = msg->buffer;
unsigned int i;
int ret;
......@@ -1025,12 +1010,17 @@ ssize_t analogix_dp_transfer(struct analogix_dp_device *dp,
/* Clear interrupt source for AUX CH access error */
reg = readl(dp->reg_base + ANALOGIX_DP_INT_STA);
status_reg = readl(dp->reg_base + ANALOGIX_DP_AUX_CH_STA);
if ((reg & AUX_ERR) || (status_reg & AUX_STATUS_MASK)) {
if ((reg & AUX_ERR)) {
u32 aux_status = readl(dp->reg_base + ANALOGIX_DP_AUX_CH_STA) &
AUX_STATUS_MASK;
writel(AUX_ERR, dp->reg_base + ANALOGIX_DP_INT_STA);
if (aux_status == AUX_STATUS_TIMEOUT_ERROR)
return -ETIMEDOUT;
dev_warn(dp->dev, "AUX CH error happened: %#x (%d)\n",
status_reg & AUX_STATUS_MASK, !!(reg & AUX_ERR));
aux_status, !!(reg & AUX_ERR));
goto aux_error;
}
......
......@@ -361,6 +361,15 @@
/* ANALOGIX_DP_AUX_CH_STA */
#define AUX_BUSY (0x1 << 4)
#define AUX_STATUS_MASK (0xf << 0)
#define AUX_STATUS_OK (0x0 << 0)
#define AUX_STATUS_NACK_ERROR (0x1 << 0)
#define AUX_STATUS_TIMEOUT_ERROR (0x2 << 0)
#define AUX_STATUS_UNKNOWN_ERROR (0x3 << 0)
#define AUX_STATUS_MUCH_DEFER_ERROR (0x4 << 0)
#define AUX_STATUS_TX_SHORT_ERROR (0x5 << 0)
#define AUX_STATUS_RX_SHORT_ERROR (0x6 << 0)
#define AUX_STATUS_NACK_WITHOUT_M_ERROR (0x7 << 0)
#define AUX_STATUS_I2C_NACK_ERROR (0x8 << 0)
/* ANALOGIX_DP_AUX_CH_DEFER_CTL */
#define DEFER_CTRL_EN (0x1 << 7)
......
......@@ -382,9 +382,6 @@ struct tc_data {
/* HPD pin number (0 or 1) or -ENODEV */
int hpd_pin;
/* Number of pixels to subtract from a line due to pixel clock delta */
u32 line_pixel_subtract;
};
static inline struct tc_data *aux_to_tc(struct drm_dp_aux *a)
......@@ -580,14 +577,9 @@ static int tc_pllupdate(struct tc_data *tc, unsigned int pllctrl)
return 0;
}
static u32 div64_round_up(u64 v, u32 d)
static int tc_pxl_pll_calc(struct tc_data *tc, u32 refclk, u32 pixelclock,
int *out_best_pixelclock, u32 *out_pxl_pllparam)
{
return div_u64(v + d - 1, d);
}
static int tc_pxl_pll_en(struct tc_data *tc, u32 refclk, u32 pixelclock)
{
int ret;
int i_pre, best_pre = 1;
int i_post, best_post = 1;
int div, best_div = 1;
......@@ -666,11 +658,7 @@ static int tc_pxl_pll_en(struct tc_data *tc, u32 refclk, u32 pixelclock)
return -EINVAL;
}
tc->line_pixel_subtract = tc->mode.htotal -
div64_round_up(tc->mode.htotal * (u64)best_pixelclock, pixelclock);
dev_dbg(tc->dev, "PLL: got %d, delta %d (subtract %d px)\n", best_pixelclock,
best_delta, tc->line_pixel_subtract);
dev_dbg(tc->dev, "PLL: got %d, delta %d\n", best_pixelclock, best_delta);
dev_dbg(tc->dev, "PLL: %d / %d / %d * %d / %d\n", refclk,
ext_div[best_pre], best_div, best_mul, ext_div[best_post]);
......@@ -683,11 +671,6 @@ static int tc_pxl_pll_en(struct tc_data *tc, u32 refclk, u32 pixelclock)
if (best_mul == 128)
best_mul = 0;
/* Power up PLL and switch to bypass */
ret = regmap_write(tc->regmap, PXL_PLLCTRL, PLLBYP | PLLEN);
if (ret)
return ret;
pxl_pllparam = vco_hi << 24; /* For PLL VCO >= 300 MHz = 1 */
pxl_pllparam |= ext_div[best_pre] << 20; /* External Pre-divider */
pxl_pllparam |= ext_div[best_post] << 16; /* External Post-divider */
......@@ -695,6 +678,29 @@ static int tc_pxl_pll_en(struct tc_data *tc, u32 refclk, u32 pixelclock)
pxl_pllparam |= best_div << 8; /* Divider for PLL RefClk */
pxl_pllparam |= best_mul; /* Multiplier for PLL */
if (out_best_pixelclock)
*out_best_pixelclock = best_pixelclock;
if (out_pxl_pllparam)
*out_pxl_pllparam = pxl_pllparam;
return 0;
}
static int tc_pxl_pll_en(struct tc_data *tc, u32 refclk, u32 pixelclock)
{
u32 pxl_pllparam = 0;
int ret;
ret = tc_pxl_pll_calc(tc, refclk, pixelclock, NULL, &pxl_pllparam);
if (ret)
return ret;
/* Power up PLL and switch to bypass */
ret = regmap_write(tc->regmap, PXL_PLLCTRL, PLLBYP | PLLEN);
if (ret)
return ret;
ret = regmap_write(tc->regmap, PXL_PLLPARAM, pxl_pllparam);
if (ret)
return ret;
......@@ -732,7 +738,7 @@ static int tc_stream_clock_calc(struct tc_data *tc)
static int tc_set_syspllparam(struct tc_data *tc)
{
unsigned long rate;
u32 pllparam = SYSCLK_SEL_LSCLK | LSCLK_DIV_2;
u32 pllparam = SYSCLK_SEL_LSCLK | LSCLK_DIV_1;
rate = clk_get_rate(tc->refclk);
switch (rate) {
......@@ -896,13 +902,6 @@ static int tc_set_common_video_mode(struct tc_data *tc,
upper_margin, lower_margin, vsync_len);
dev_dbg(tc->dev, "total: %dx%d\n", mode->htotal, mode->vtotal);
if (right_margin > tc->line_pixel_subtract) {
right_margin -= tc->line_pixel_subtract;
} else {
dev_err(tc->dev, "Bridge pixel clock too slow for mode\n");
right_margin = 0;
}
/*
* LCD Ctl Frame Size
* datasheet is not clear of vsdelay in case of DPI
......@@ -1357,10 +1356,10 @@ static int tc_dsi_rx_enable(struct tc_data *tc)
u32 value;
int ret;
regmap_write(tc->regmap, PPI_D0S_CLRSIPOCOUNT, 25);
regmap_write(tc->regmap, PPI_D1S_CLRSIPOCOUNT, 25);
regmap_write(tc->regmap, PPI_D2S_CLRSIPOCOUNT, 25);
regmap_write(tc->regmap, PPI_D3S_CLRSIPOCOUNT, 25);
regmap_write(tc->regmap, PPI_D0S_CLRSIPOCOUNT, 5);
regmap_write(tc->regmap, PPI_D1S_CLRSIPOCOUNT, 5);
regmap_write(tc->regmap, PPI_D2S_CLRSIPOCOUNT, 5);
regmap_write(tc->regmap, PPI_D3S_CLRSIPOCOUNT, 5);
regmap_write(tc->regmap, PPI_D0S_ATMR, 0);
regmap_write(tc->regmap, PPI_D1S_ATMR, 0);
regmap_write(tc->regmap, PPI_TX_RX_TA, TTA_GET | TTA_SURE);
......@@ -1606,6 +1605,18 @@ static int tc_dpi_atomic_check(struct drm_bridge *bridge,
struct drm_crtc_state *crtc_state,
struct drm_connector_state *conn_state)
{
struct tc_data *tc = bridge_to_tc(bridge);
int adjusted_clock = 0;
int ret;
ret = tc_pxl_pll_calc(tc, clk_get_rate(tc->refclk),
crtc_state->mode.clock * 1000,
&adjusted_clock, NULL);
if (ret)
return ret;
crtc_state->adjusted_mode.clock = adjusted_clock / 1000;
/* DSI->DPI interface clock limitation: upto 100 MHz */
if (crtc_state->adjusted_mode.clock > 100000)
return -EINVAL;
......@@ -1618,6 +1629,18 @@ static int tc_edp_atomic_check(struct drm_bridge *bridge,
struct drm_crtc_state *crtc_state,
struct drm_connector_state *conn_state)
{
struct tc_data *tc = bridge_to_tc(bridge);
int adjusted_clock = 0;
int ret;
ret = tc_pxl_pll_calc(tc, clk_get_rate(tc->refclk),
crtc_state->mode.clock * 1000,
&adjusted_clock, NULL);
if (ret)
return ret;
crtc_state->adjusted_mode.clock = adjusted_clock / 1000;
/* DPI->(e)DP interface clock limitation: upto 154 MHz */
if (crtc_state->adjusted_mode.clock > 154000)
return -EINVAL;
......@@ -1820,6 +1843,7 @@ static void tc_edp_bridge_detach(struct drm_bridge *bridge)
}
#define MAX_INPUT_SEL_FORMATS 1
#define MAX_OUTPUT_SEL_FORMATS 1
static u32 *
tc_dpi_atomic_get_input_bus_fmts(struct drm_bridge *bridge,
......@@ -1845,6 +1869,28 @@ tc_dpi_atomic_get_input_bus_fmts(struct drm_bridge *bridge,
return input_fmts;
}
static u32 *
tc_edp_atomic_get_output_bus_fmts(struct drm_bridge *bridge,
struct drm_bridge_state *bridge_state,
struct drm_crtc_state *crtc_state,
struct drm_connector_state *conn_state,
unsigned int *num_output_fmts)
{
u32 *output_fmts;
*num_output_fmts = 0;
output_fmts = kcalloc(MAX_OUTPUT_SEL_FORMATS, sizeof(*output_fmts),
GFP_KERNEL);
if (!output_fmts)
return NULL;
output_fmts[0] = MEDIA_BUS_FMT_RGB888_1X24;
*num_output_fmts = 1;
return output_fmts;
}
static const struct drm_bridge_funcs tc_dpi_bridge_funcs = {
.attach = tc_dpi_bridge_attach,
.mode_valid = tc_dpi_mode_valid,
......@@ -1871,6 +1917,8 @@ static const struct drm_bridge_funcs tc_edp_bridge_funcs = {
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
.atomic_reset = drm_atomic_helper_bridge_reset,
.atomic_get_input_bus_fmts = drm_atomic_helper_bridge_propagate_bus_fmt,
.atomic_get_output_bus_fmts = tc_edp_atomic_get_output_bus_fmts,
};
static bool tc_readable_reg(struct device *dev, unsigned int reg)
......
......@@ -716,7 +716,7 @@ drm_atomic_helper_connector_hdmi_update_audio_infoframe(struct drm_connector *co
EXPORT_SYMBOL(drm_atomic_helper_connector_hdmi_update_audio_infoframe);
/**
* drm_atomic_helper_connector_hdmi_disable_audio_infoframe - Stop sending the Audio Infoframe
* drm_atomic_helper_connector_hdmi_clear_audio_infoframe - Stop sending the Audio Infoframe
* @connector: A pointer to the HDMI connector
*
* This function is meant for HDMI connector drivers to stop sending their
......@@ -727,7 +727,7 @@ EXPORT_SYMBOL(drm_atomic_helper_connector_hdmi_update_audio_infoframe);
* Zero on success, error code on failure.
*/
int
drm_atomic_helper_connector_hdmi_disable_audio_infoframe(struct drm_connector *connector)
drm_atomic_helper_connector_hdmi_clear_audio_infoframe(struct drm_connector *connector)
{
struct drm_connector_hdmi_infoframe *infoframe =
&connector->hdmi.infoframes.audio;
......@@ -749,4 +749,4 @@ drm_atomic_helper_connector_hdmi_disable_audio_infoframe(struct drm_connector *c
return ret;
}
EXPORT_SYMBOL(drm_atomic_helper_connector_hdmi_disable_audio_infoframe);
EXPORT_SYMBOL(drm_atomic_helper_connector_hdmi_clear_audio_infoframe);
......@@ -7,16 +7,19 @@
*/
#include <linux/font.h>
#include <linux/init.h>
#include <linux/iosys-map.h>
#include <linux/kdebug.h>
#include <linux/kmsg_dump.h>
#include <linux/linux_logo.h>
#include <linux/list.h>
#include <linux/math.h>
#include <linux/module.h>
#include <linux/overflow.h>
#include <linux/printk.h>
#include <linux/types.h>
#include <drm/drm_drv.h>
#include <drm/drm_format_helper.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_framebuffer.h>
#include <drm/drm_modeset_helper_vtables.h>
......@@ -78,7 +81,7 @@ static struct drm_panic_line panic_msg[] = {
PANIC_LINE("Please reboot your computer."),
};
static const struct drm_panic_line logo[] = {
static const struct drm_panic_line logo_ascii[] = {
PANIC_LINE(" .--. _"),
PANIC_LINE(" |o_o | | |"),
PANIC_LINE(" |:_/ | | |"),
......@@ -88,6 +91,42 @@ static const struct drm_panic_line logo[] = {
PANIC_LINE(" \\___)=(___/"),
};
#if defined(CONFIG_LOGO) && !defined(MODULE)
static const struct linux_logo *logo_mono;
static int drm_panic_setup_logo(void)
{
const struct linux_logo *logo = fb_find_logo(1);
const unsigned char *logo_data;
struct linux_logo *logo_dup;
if (!logo || logo->type != LINUX_LOGO_MONO)
return 0;
/* The logo is __init, so we must make a copy for later use */
logo_data = kmemdup(logo->data,
size_mul(DIV_ROUND_UP(logo->width, BITS_PER_BYTE), logo->height),
GFP_KERNEL);
if (!logo_data)
return -ENOMEM;
logo_dup = kmemdup(logo, sizeof(*logo), GFP_KERNEL);
if (!logo_dup) {
kfree(logo_data);
return -ENOMEM;
}
logo_dup->data = logo_data;
logo_mono = logo_dup;
return 0;
}
device_initcall(drm_panic_setup_logo);
#else
#define logo_mono ((const struct linux_logo *)NULL)
#endif
/*
* Color conversion
*/
......@@ -447,20 +486,27 @@ static void draw_txt_rectangle(struct drm_scanout_buffer *sb,
static void draw_panic_static_user(struct drm_scanout_buffer *sb)
{
size_t msg_lines = ARRAY_SIZE(panic_msg);
size_t logo_lines = ARRAY_SIZE(logo);
size_t logo_ascii_lines = ARRAY_SIZE(logo_ascii);
u32 fg_color = convert_from_xrgb8888(CONFIG_DRM_PANIC_FOREGROUND_COLOR, sb->format->format);
u32 bg_color = convert_from_xrgb8888(CONFIG_DRM_PANIC_BACKGROUND_COLOR, sb->format->format);
const struct font_desc *font = get_default_font(sb->width, sb->height, NULL, NULL);
struct drm_rect r_screen, r_logo, r_msg;
unsigned int logo_width, logo_height;
if (!font)
return;
r_screen = DRM_RECT_INIT(0, 0, sb->width, sb->height);
r_logo = DRM_RECT_INIT(0, 0,
get_max_line_len(logo, logo_lines) * font->width,
logo_lines * font->height);
if (logo_mono) {
logo_width = logo_mono->width;
logo_height = logo_mono->height;
} else {
logo_width = get_max_line_len(logo_ascii, logo_ascii_lines) * font->width;
logo_height = logo_ascii_lines * font->height;
}
r_logo = DRM_RECT_INIT(0, 0, logo_width, logo_height);
r_msg = DRM_RECT_INIT(0, 0,
min(get_max_line_len(panic_msg, msg_lines) * font->width, sb->width),
min(msg_lines * font->height, sb->height));
......@@ -471,9 +517,14 @@ static void draw_panic_static_user(struct drm_scanout_buffer *sb)
/* Fill with the background color, and draw text on top */
drm_panic_fill(sb, &r_screen, bg_color);
if ((r_msg.x1 >= drm_rect_width(&r_logo) || r_msg.y1 >= drm_rect_height(&r_logo)) &&
drm_rect_width(&r_logo) < sb->width && drm_rect_height(&r_logo) < sb->height) {
draw_txt_rectangle(sb, font, logo, logo_lines, false, &r_logo, fg_color);
if ((r_msg.x1 >= logo_width || r_msg.y1 >= logo_height) &&
logo_width <= sb->width && logo_height <= sb->height) {
if (logo_mono)
drm_panic_blit(sb, &r_logo, logo_mono->data, DIV_ROUND_UP(logo_width, 8),
fg_color);
else
draw_txt_rectangle(sb, font, logo_ascii, logo_ascii_lines, false, &r_logo,
fg_color);
}
draw_txt_rectangle(sb, font, panic_msg, msg_lines, true, &r_msg, fg_color);
}
......@@ -582,7 +633,7 @@ static void draw_panic_dispatch(struct drm_scanout_buffer *sb)
static void draw_panic_plane(struct drm_plane *plane)
{
struct drm_scanout_buffer sb;
struct drm_scanout_buffer sb = { };
int ret;
unsigned long flags;
......
......@@ -233,7 +233,7 @@ static int exynos_dp_probe(struct platform_device *pdev)
/* The remote port can be either a panel or a bridge */
dp->plat_data.panel = panel;
dp->plat_data.dev_type = EXYNOS_DP;
dp->plat_data.power_on_start = exynos_dp_poweron;
dp->plat_data.power_on = exynos_dp_poweron;
dp->plat_data.power_off = exynos_dp_poweroff;
dp->plat_data.attach = exynos_dp_bridge_attach;
dp->plat_data.get_modes = exynos_dp_get_modes;
......@@ -251,10 +251,7 @@ static int exynos_dp_probe(struct platform_device *pdev)
static void exynos_dp_remove(struct platform_device *pdev)
{
struct exynos_dp_device *dp = platform_get_drvdata(pdev);
component_del(&pdev->dev, &exynos_dp_ops);
analogix_dp_remove(dp->adp);
}
static int exynos_dp_suspend(struct device *dev)
......
......@@ -7,6 +7,7 @@ config DRM_MEDIATEK
depends on HAVE_ARM_SMCCC
depends on OF
depends on MTK_MMSYS
select DRM_GEM_DMA_HELPER if DRM_FBDEV_EMULATION
select DRM_KMS_HELPER
select DRM_MIPI_DSI
select DRM_PANEL
......
......@@ -205,6 +205,15 @@ config DRM_PANEL_ILITEK_ILI9805
Say Y if you want to enable support for panels based on the
Ilitek ILI9805 controller.
config DRM_PANEL_ILITEK_ILI9806E
tristate "Ilitek ILI9806E-based panels"
depends on OF
depends on DRM_MIPI_DSI
depends on BACKLIGHT_CLASS_DEVICE
help
Say Y if you want to enable support for panels based on the
Ilitek ILI9806E controller.
config DRM_PANEL_ILITEK_ILI9881C
tristate "Ilitek ILI9881C-based panels"
depends on OF
......@@ -328,6 +337,17 @@ config DRM_PANEL_LEADTEK_LTK500HD1829
24 bit RGB per pixel. It provides a MIPI DSI interface to
the host and has a built-in LED backlight.
config DRM_PANEL_LINCOLNTECH_LCD197
tristate "Lincoln Technologies lcd197 panel"
depends on OF
depends on DRM_MIPI_DSI
depends on BACKLIGHT_CLASS_DEVICE
help
Say Y here if you want to enable support for lincolntech lcd197
TFT-LCD modules. The panel has a 1080x1920 resolution and uses
24 bit RGB per pixel. It provides a MIPI DSI interface to
the host.
config DRM_PANEL_LG_LB035Q02
tristate "LG LB035Q024573 RGB panel"
depends on GPIOLIB && OF && SPI
......
......@@ -21,6 +21,7 @@ obj-$(CONFIG_DRM_PANEL_HIMAX_HX8394) += panel-himax-hx8394.o
obj-$(CONFIG_DRM_PANEL_ILITEK_IL9322) += panel-ilitek-ili9322.o
obj-$(CONFIG_DRM_PANEL_ILITEK_ILI9341) += panel-ilitek-ili9341.o
obj-$(CONFIG_DRM_PANEL_ILITEK_ILI9805) += panel-ilitek-ili9805.o
obj-$(CONFIG_DRM_PANEL_ILITEK_ILI9806E) += panel-ilitek-ili9806e.o
obj-$(CONFIG_DRM_PANEL_ILITEK_ILI9881C) += panel-ilitek-ili9881c.o
obj-$(CONFIG_DRM_PANEL_ILITEK_ILI9882T) += panel-ilitek-ili9882t.o
obj-$(CONFIG_DRM_PANEL_INNOLUX_EJ030NA) += panel-innolux-ej030na.o
......@@ -33,6 +34,7 @@ obj-$(CONFIG_DRM_PANEL_KHADAS_TS050) += panel-khadas-ts050.o
obj-$(CONFIG_DRM_PANEL_KINGDISPLAY_KD097D04) += panel-kingdisplay-kd097d04.o
obj-$(CONFIG_DRM_PANEL_LEADTEK_LTK050H3146W) += panel-leadtek-ltk050h3146w.o
obj-$(CONFIG_DRM_PANEL_LEADTEK_LTK500HD1829) += panel-leadtek-ltk500hd1829.o
obj-$(CONFIG_DRM_PANEL_LINCOLNTECH_LCD197) += panel-lincolntech-lcd197.o
obj-$(CONFIG_DRM_PANEL_LG_LB035Q02) += panel-lg-lb035q02.o
obj-$(CONFIG_DRM_PANEL_LG_LG4573) += panel-lg-lg4573.o
obj-$(CONFIG_DRM_PANEL_LG_SW43408) += panel-lg-sw43408.o
......
......@@ -33,119 +33,97 @@ static void tm5p5_nt35596_reset(struct tm5p5_nt35596 *ctx)
usleep_range(15000, 16000);
}
static int tm5p5_nt35596_on(struct tm5p5_nt35596 *ctx)
static void tm5p5_nt35596_on(struct mipi_dsi_multi_context *dsi_ctx)
{
struct mipi_dsi_device *dsi = ctx->dsi;
mipi_dsi_generic_write_seq(dsi, 0xff, 0x05);
mipi_dsi_generic_write_seq(dsi, 0xfb, 0x01);
mipi_dsi_generic_write_seq(dsi, 0xc5, 0x31);
mipi_dsi_generic_write_seq(dsi, 0xff, 0x04);
mipi_dsi_generic_write_seq(dsi, 0x01, 0x84);
mipi_dsi_generic_write_seq(dsi, 0x05, 0x25);
mipi_dsi_generic_write_seq(dsi, 0x06, 0x01);
mipi_dsi_generic_write_seq(dsi, 0x07, 0x20);
mipi_dsi_generic_write_seq(dsi, 0x08, 0x06);
mipi_dsi_generic_write_seq(dsi, 0x09, 0x08);
mipi_dsi_generic_write_seq(dsi, 0x0a, 0x10);
mipi_dsi_generic_write_seq(dsi, 0x0b, 0x10);
mipi_dsi_generic_write_seq(dsi, 0x0c, 0x10);
mipi_dsi_generic_write_seq(dsi, 0x0d, 0x14);
mipi_dsi_generic_write_seq(dsi, 0x0e, 0x14);
mipi_dsi_generic_write_seq(dsi, 0x0f, 0x14);
mipi_dsi_generic_write_seq(dsi, 0x10, 0x14);
mipi_dsi_generic_write_seq(dsi, 0x11, 0x14);
mipi_dsi_generic_write_seq(dsi, 0x12, 0x14);
mipi_dsi_generic_write_seq(dsi, 0x17, 0xf3);
mipi_dsi_generic_write_seq(dsi, 0x18, 0xc0);
mipi_dsi_generic_write_seq(dsi, 0x19, 0xc0);
mipi_dsi_generic_write_seq(dsi, 0x1a, 0xc0);
mipi_dsi_generic_write_seq(dsi, 0x1b, 0xb3);
mipi_dsi_generic_write_seq(dsi, 0x1c, 0xb3);
mipi_dsi_generic_write_seq(dsi, 0x1d, 0xb3);
mipi_dsi_generic_write_seq(dsi, 0x1e, 0xb3);
mipi_dsi_generic_write_seq(dsi, 0x1f, 0xb3);
mipi_dsi_generic_write_seq(dsi, 0x20, 0xb3);
mipi_dsi_generic_write_seq(dsi, 0xfb, 0x01);
mipi_dsi_generic_write_seq(dsi, 0xff, 0x00);
mipi_dsi_generic_write_seq(dsi, 0xfb, 0x01);
mipi_dsi_generic_write_seq(dsi, 0x35, 0x01);
mipi_dsi_generic_write_seq(dsi, 0xd3, 0x06);
mipi_dsi_generic_write_seq(dsi, 0xd4, 0x04);
mipi_dsi_generic_write_seq(dsi, 0x5e, 0x0d);
mipi_dsi_generic_write_seq(dsi, 0x11, 0x00);
msleep(100);
mipi_dsi_generic_write_seq(dsi, 0x29, 0x00);
mipi_dsi_generic_write_seq(dsi, 0x53, 0x24);
return 0;
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0xff, 0x05);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0xfb, 0x01);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0xc5, 0x31);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0xff, 0x04);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x01, 0x84);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x05, 0x25);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x06, 0x01);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x07, 0x20);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x08, 0x06);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x09, 0x08);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x0a, 0x10);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x0b, 0x10);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x0c, 0x10);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x0d, 0x14);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x0e, 0x14);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x0f, 0x14);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x10, 0x14);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x11, 0x14);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x12, 0x14);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x17, 0xf3);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x18, 0xc0);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x19, 0xc0);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x1a, 0xc0);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x1b, 0xb3);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x1c, 0xb3);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x1d, 0xb3);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x1e, 0xb3);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x1f, 0xb3);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x20, 0xb3);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0xfb, 0x01);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0xff, 0x00);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0xfb, 0x01);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x35, 0x01);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0xd3, 0x06);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0xd4, 0x04);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x5e, 0x0d);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x11, 0x00);
mipi_dsi_msleep(dsi_ctx, 100);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x29, 0x00);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x53, 0x24);
}
static int tm5p5_nt35596_off(struct tm5p5_nt35596 *ctx)
static void tm5p5_nt35596_off(struct mipi_dsi_multi_context *dsi_ctx)
{
struct mipi_dsi_device *dsi = ctx->dsi;
struct device *dev = &dsi->dev;
int ret;
ret = mipi_dsi_dcs_set_display_off(dsi);
if (ret < 0) {
dev_err(dev, "Failed to set display off: %d\n", ret);
return ret;
}
msleep(60);
mipi_dsi_dcs_set_display_off_multi(dsi_ctx);
ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
if (ret < 0) {
dev_err(dev, "Failed to enter sleep mode: %d\n", ret);
return ret;
}
mipi_dsi_msleep(dsi_ctx, 60);
mipi_dsi_dcs_write_seq(dsi, 0x4f, 0x01);
mipi_dsi_dcs_enter_sleep_mode_multi(dsi_ctx);
return 0;
mipi_dsi_dcs_write_seq_multi(dsi_ctx, 0x4f, 0x01);
}
static int tm5p5_nt35596_prepare(struct drm_panel *panel)
{
struct tm5p5_nt35596 *ctx = to_tm5p5_nt35596(panel);
struct device *dev = &ctx->dsi->dev;
int ret;
struct mipi_dsi_multi_context dsi_ctx = {.dsi = ctx->dsi};
ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
if (ret < 0) {
dev_err(dev, "Failed to enable regulators: %d\n", ret);
return ret;
}
dsi_ctx.accum_err = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
if (dsi_ctx.accum_err)
return dsi_ctx.accum_err;
tm5p5_nt35596_reset(ctx);
ret = tm5p5_nt35596_on(ctx);
if (ret < 0) {
dev_err(dev, "Failed to initialize panel: %d\n", ret);
tm5p5_nt35596_on(&dsi_ctx);
if (dsi_ctx.accum_err) {
gpiod_set_value_cansleep(ctx->reset_gpio, 0);
regulator_bulk_disable(ARRAY_SIZE(ctx->supplies),
ctx->supplies);
return ret;
}
return 0;
return dsi_ctx.accum_err;
}
static int tm5p5_nt35596_unprepare(struct drm_panel *panel)
{
struct tm5p5_nt35596 *ctx = to_tm5p5_nt35596(panel);
struct device *dev = &ctx->dsi->dev;
int ret;
struct mipi_dsi_multi_context dsi_ctx = {.dsi = ctx->dsi};
ret = tm5p5_nt35596_off(ctx);
if (ret < 0)
dev_err(dev, "Failed to un-initialize panel: %d\n", ret);
tm5p5_nt35596_off(&dsi_ctx);
gpiod_set_value_cansleep(ctx->reset_gpio, 0);
regulator_bulk_disable(ARRAY_SIZE(ctx->supplies),
ctx->supplies);
return 0;
return dsi_ctx.accum_err;
}
static const struct drm_display_mode tm5p5_nt35596_mode = {
......
This diff is collapsed.
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2024 BayLibre, SAS
* Author: Jerome Brunet <jbrunet@baylibre.com>
*/
#include <linux/gpio/consumer.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/regulator/consumer.h>
#include <video/mipi_display.h>
#include <drm/drm_device.h>
#include <drm/drm_probe_helper.h>
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_modes.h>
#include <drm/drm_panel.h>
struct lincoln_lcd197_panel {
struct drm_panel panel;
struct mipi_dsi_device *dsi;
struct regulator *supply;
struct gpio_desc *enable_gpio;
struct gpio_desc *reset_gpio;
};
static inline
struct lincoln_lcd197_panel *to_lincoln_lcd197_panel(struct drm_panel *panel)
{
return container_of(panel, struct lincoln_lcd197_panel, panel);
}
static int lincoln_lcd197_panel_prepare(struct drm_panel *panel)
{
struct lincoln_lcd197_panel *lcd = to_lincoln_lcd197_panel(panel);
struct mipi_dsi_multi_context ctx = { .dsi = lcd->dsi };
int err;
gpiod_set_value_cansleep(lcd->enable_gpio, 0);
err = regulator_enable(lcd->supply);
if (err < 0)
return err;
gpiod_set_value_cansleep(lcd->enable_gpio, 1);
usleep_range(1000, 2000);
gpiod_set_value_cansleep(lcd->reset_gpio, 1);
usleep_range(5000, 6000);
gpiod_set_value_cansleep(lcd->reset_gpio, 0);
msleep(50);
mipi_dsi_dcs_write_seq_multi(&ctx, 0xb9, 0xff, 0x83, 0x99);
mipi_dsi_dcs_write_seq_multi(&ctx, 0xd2, 0x55);
mipi_dsi_dcs_write_seq_multi(&ctx, 0xb1, 0x02, 0x04, 0x70, 0x90, 0x01,
0x32, 0x33, 0x11, 0x11, 0x4d, 0x57, 0x56, 0x73,
0x02, 0x02);
mipi_dsi_dcs_write_seq_multi(&ctx, 0xb2, 0x00, 0x80, 0x80, 0xae, 0x0a,
0x0e, 0x75, 0x11, 0x00, 0x00, 0x00);
mipi_dsi_dcs_write_seq_multi(&ctx, 0xb4, 0x00, 0xff, 0x04, 0xa4, 0x02,
0xa0, 0x00, 0x00, 0x10, 0x00, 0x00, 0x02, 0x00,
0x24, 0x02, 0x04, 0x0a, 0x21, 0x03, 0x00, 0x00,
0x08, 0xa6, 0x88, 0x04, 0xa4, 0x02, 0xa0, 0x00,
0x00, 0x10, 0x00, 0x00, 0x02, 0x00, 0x24, 0x02,
0x04, 0x0a, 0x00, 0x00, 0x08, 0xa6, 0x00, 0x08,
0x11);
mipi_dsi_dcs_write_seq_multi(&ctx, 0xd3, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x18, 0x18, 0x32, 0x10, 0x09, 0x00, 0x09,
0x32, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x11, 0x00, 0x02, 0x02, 0x03, 0x00,
0x00, 0x00, 0x0a, 0x40);
mipi_dsi_dcs_write_seq_multi(&ctx, 0xd5, 0x18, 0x18, 0x18, 0x18, 0x21,
0x20, 0x18, 0x18, 0x19, 0x19, 0x19, 0x19, 0x18,
0x18, 0x18, 0x18, 0x03, 0x02, 0x01, 0x00, 0x2f,
0x2f, 0x30, 0x30, 0x31, 0x31, 0x18, 0x18, 0x18,
0x18, 0x18, 0x18);
mipi_dsi_dcs_write_seq_multi(&ctx, 0xd6, 0x18, 0x18, 0x18, 0x18, 0x20,
0x21, 0x19, 0x19, 0x18, 0x18, 0x19, 0x19, 0x18,
0x18, 0x18, 0x18, 0x00, 0x01, 0x02, 0x03, 0x2f,
0x2f, 0x30, 0x30, 0x31, 0x31, 0x18, 0x18, 0x18,
0x18, 0x18, 0x18);
mipi_dsi_dcs_write_seq_multi(&ctx, 0xbd, 0x01);
mipi_dsi_dcs_write_seq_multi(&ctx, 0xd8, 0x0a, 0xbe, 0xfa, 0xa0, 0x0a,
0xbe, 0xfa, 0xa0);
mipi_dsi_dcs_write_seq_multi(&ctx, 0xd8, 0x0f, 0xff, 0xff, 0xe0, 0x0f,
0xff, 0xff, 0xe0);
mipi_dsi_dcs_write_seq_multi(&ctx, 0xbd, 0x02);
mipi_dsi_dcs_write_seq_multi(&ctx, 0xd8, 0x0f, 0xff, 0xff, 0xe0, 0x0f,
0xff, 0xff, 0xe0);
mipi_dsi_dcs_write_seq_multi(&ctx, 0xe0, 0x01, 0x11, 0x1c, 0x17, 0x39,
0x43, 0x54, 0x51, 0x5a, 0x64, 0x6c, 0x74, 0x7a,
0x83, 0x8d, 0x92, 0x99, 0xa4, 0xa9, 0xb4, 0xaa,
0xba, 0xbe, 0x63, 0x5e, 0x69, 0x73, 0x01, 0x11,
0x1c, 0x17, 0x39, 0x43, 0x54, 0x51, 0x5a, 0x64,
0x6c, 0x74, 0x7a, 0x83, 0x8d, 0x92, 0x99, 0xa4,
0xa7, 0xb2, 0xa9, 0xba, 0xbe, 0x63, 0x5e, 0x69,
0x73);
mipi_dsi_usleep_range(&ctx, 200, 300);
mipi_dsi_dcs_write_seq_multi(&ctx, 0xb6, 0x92, 0x92);
mipi_dsi_dcs_write_seq_multi(&ctx, 0xcc, 0x00);
mipi_dsi_dcs_write_seq_multi(&ctx, 0xbf, 0x40, 0x41, 0x50, 0x49);
mipi_dsi_dcs_write_seq_multi(&ctx, 0xc6, 0xff, 0xf9);
mipi_dsi_dcs_write_seq_multi(&ctx, 0xc0, 0x25, 0x5a);
mipi_dsi_dcs_write_seq_multi(&ctx, MIPI_DCS_SET_ADDRESS_MODE, 0x02);
mipi_dsi_dcs_exit_sleep_mode_multi(&ctx);
mipi_dsi_msleep(&ctx, 120);
if (ctx.accum_err) {
gpiod_set_value_cansleep(lcd->enable_gpio, 0);
gpiod_set_value_cansleep(lcd->reset_gpio, 1);
regulator_disable(lcd->supply);
}
return ctx.accum_err;
}
static int lincoln_lcd197_panel_unprepare(struct drm_panel *panel)
{
struct lincoln_lcd197_panel *lcd = to_lincoln_lcd197_panel(panel);
struct mipi_dsi_multi_context ctx = { .dsi = lcd->dsi };
mipi_dsi_dcs_enter_sleep_mode_multi(&ctx);
mipi_dsi_usleep_range(&ctx, 5000, 6000);
gpiod_set_value_cansleep(lcd->enable_gpio, 0);
gpiod_set_value_cansleep(lcd->reset_gpio, 1);
regulator_disable(lcd->supply);
return ctx.accum_err;
}
static int lincoln_lcd197_panel_enable(struct drm_panel *panel)
{
struct lincoln_lcd197_panel *lcd = to_lincoln_lcd197_panel(panel);
struct mipi_dsi_multi_context ctx = { .dsi = lcd->dsi };
mipi_dsi_dcs_set_display_on_multi(&ctx);
mipi_dsi_msleep(&ctx, 20);
return ctx.accum_err;
}
static int lincoln_lcd197_panel_disable(struct drm_panel *panel)
{
struct lincoln_lcd197_panel *lcd = to_lincoln_lcd197_panel(panel);
struct mipi_dsi_multi_context ctx = { .dsi = lcd->dsi };
mipi_dsi_dcs_set_display_off_multi(&ctx);
mipi_dsi_msleep(&ctx, 50);
return ctx.accum_err;
}
static const struct drm_display_mode lcd197_mode = {
.clock = 154002,
.hdisplay = 1080,
.hsync_start = 1080 + 20,
.hsync_end = 1080 + 20 + 6,
.htotal = 1080 + 204,
.vdisplay = 1920,
.vsync_start = 1920 + 4,
.vsync_end = 1920 + 4 + 4,
.vtotal = 1920 + 79,
.flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
.width_mm = 79,
.height_mm = 125,
.type = DRM_MODE_TYPE_DRIVER,
};
static int lincoln_lcd197_panel_get_modes(struct drm_panel *panel,
struct drm_connector *connector)
{
return drm_connector_helper_get_modes_fixed(connector, &lcd197_mode);
}
static const struct drm_panel_funcs lincoln_lcd197_panel_funcs = {
.prepare = lincoln_lcd197_panel_prepare,
.unprepare = lincoln_lcd197_panel_unprepare,
.enable = lincoln_lcd197_panel_enable,
.disable = lincoln_lcd197_panel_disable,
.get_modes = lincoln_lcd197_panel_get_modes,
};
static int lincoln_lcd197_panel_probe(struct mipi_dsi_device *dsi)
{
struct lincoln_lcd197_panel *lcd;
struct device *dev = &dsi->dev;
int err;
dsi->lanes = 4;
dsi->format = MIPI_DSI_FMT_RGB888;
dsi->mode_flags = (MIPI_DSI_MODE_VIDEO |
MIPI_DSI_MODE_VIDEO_BURST);
lcd = devm_kzalloc(&dsi->dev, sizeof(*lcd), GFP_KERNEL);
if (!lcd)
return -ENOMEM;
mipi_dsi_set_drvdata(dsi, lcd);
lcd->dsi = dsi;
lcd->supply = devm_regulator_get(dev, "power");
if (IS_ERR(lcd->supply))
return dev_err_probe(dev, PTR_ERR(lcd->supply),
"failed to get power supply");
lcd->enable_gpio = devm_gpiod_get(dev, "enable",
GPIOD_OUT_HIGH);
if (IS_ERR(lcd->enable_gpio))
return dev_err_probe(dev, PTR_ERR(lcd->enable_gpio),
"failed to get enable gpio");
lcd->reset_gpio = devm_gpiod_get(dev, "reset",
GPIOD_OUT_HIGH);
if (IS_ERR(lcd->reset_gpio))
return dev_err_probe(dev, PTR_ERR(lcd->reset_gpio),
"failed to get reset gpio");
drm_panel_init(&lcd->panel, dev,
&lincoln_lcd197_panel_funcs, DRM_MODE_CONNECTOR_DSI);
err = drm_panel_of_backlight(&lcd->panel);
if (err)
return err;
drm_panel_add(&lcd->panel);
err = mipi_dsi_attach(dsi);
if (err)
drm_panel_remove(&lcd->panel);
return err;
}
static void lincoln_lcd197_panel_remove(struct mipi_dsi_device *dsi)
{
struct lincoln_lcd197_panel *lcd = mipi_dsi_get_drvdata(dsi);
int err;
err = mipi_dsi_detach(dsi);
if (err < 0)
dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", err);
drm_panel_remove(&lcd->panel);
}
static const struct of_device_id lincoln_lcd197_of_match[] = {
{ .compatible = "lincolntech,lcd197", },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, lincoln_lcd197_of_match);
static struct mipi_dsi_driver lincoln_lcd197_panel_driver = {
.driver = {
.name = "panel-lincolntech-lcd197",
.of_match_table = lincoln_lcd197_of_match,
},
.probe = lincoln_lcd197_panel_probe,
.remove = lincoln_lcd197_panel_remove,
};
module_mipi_dsi_driver(lincoln_lcd197_panel_driver);
MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
MODULE_DESCRIPTION("Lincoln Technologies LCD197 panel driver");
MODULE_LICENSE("GPL");
......@@ -236,6 +236,9 @@ static int qxl_add_mode(struct drm_connector *connector,
return 0;
mode = drm_cvt_mode(dev, width, height, 60, false, false, false);
if (!mode)
return 0;
if (preferred)
mode->type |= DRM_MODE_TYPE_PREFERRED;
mode->hdisplay = width;
......
......@@ -13,6 +13,7 @@
#include <linux/of.h>
#include <linux/of_graph.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <linux/reset.h>
#include <linux/clk.h>
......@@ -92,7 +93,7 @@ static int rockchip_dp_pre_init(struct rockchip_dp_device *dp)
return 0;
}
static int rockchip_dp_poweron_start(struct analogix_dp_plat_data *plat_data)
static int rockchip_dp_poweron(struct analogix_dp_plat_data *plat_data)
{
struct rockchip_dp_device *dp = pdata_encoder_to_dp(plat_data);
int ret;
......@@ -397,7 +398,7 @@ static int rockchip_dp_probe(struct platform_device *pdev)
dp->data = dp_data;
dp->plat_data.panel = panel;
dp->plat_data.dev_type = dp->data->chip_type;
dp->plat_data.power_on_start = rockchip_dp_poweron_start;
dp->plat_data.power_on = rockchip_dp_poweron;
dp->plat_data.power_off = rockchip_dp_powerdown;
dp->plat_data.get_modes = rockchip_dp_get_modes;
......@@ -413,24 +414,16 @@ static int rockchip_dp_probe(struct platform_device *pdev)
ret = component_add(dev, &rockchip_dp_component_ops);
if (ret)
goto err_dp_remove;
return ret;
return 0;
err_dp_remove:
analogix_dp_remove(dp->adp);
return ret;
}
static void rockchip_dp_remove(struct platform_device *pdev)
{
struct rockchip_dp_device *dp = platform_get_drvdata(pdev);
component_del(&pdev->dev, &rockchip_dp_component_ops);
analogix_dp_remove(dp->adp);
}
#ifdef CONFIG_PM_SLEEP
static int rockchip_dp_suspend(struct device *dev)
{
struct rockchip_dp_device *dp = dev_get_drvdata(dev);
......@@ -450,14 +443,9 @@ static int rockchip_dp_resume(struct device *dev)
return analogix_dp_resume(dp->adp);
}
#endif
static const struct dev_pm_ops rockchip_dp_pm_ops = {
#ifdef CONFIG_PM_SLEEP
.suspend_late = rockchip_dp_suspend,
.resume_early = rockchip_dp_resume,
#endif
};
static DEFINE_RUNTIME_DEV_PM_OPS(rockchip_dp_pm_ops, rockchip_dp_suspend,
rockchip_dp_resume, NULL);
static const struct rockchip_dp_chip_data rk3399_edp = {
.lcdsel_grf_reg = RK3399_GRF_SOC_CON20,
......@@ -485,7 +473,7 @@ struct platform_driver rockchip_dp_driver = {
.remove_new = rockchip_dp_remove,
.driver = {
.name = "rockchip-dp",
.pm = &rockchip_dp_pm_ops,
.pm = pm_ptr(&rockchip_dp_pm_ops),
.of_match_table = rockchip_dp_dt_ids,
},
};
......@@ -1740,4 +1740,5 @@ kunit_test_suites(
);
MODULE_AUTHOR("Maxime Ripard <mripard@kernel.org>");
MODULE_DESCRIPTION("Kunit test for drm_hdmi_state_helper functions");
MODULE_LICENSE("GPL");
CONFIG_KUNIT=y
CONFIG_DRM=y
CONFIG_DRM_KUNIT_TEST_HELPERS=y
CONFIG_DRM_TTM_KUNIT_TEST=y
......@@ -6,4 +6,6 @@ obj-$(CONFIG_DRM_TTM_KUNIT_TEST) += \
ttm_resource_test.o \
ttm_tt_test.o \
ttm_bo_test.o \
ttm_bo_validate_test.o \
ttm_mock_manager.o \
ttm_kunit_helpers.o
TODO
=====
- Add a test case where the only evictable BO is busy
- Update eviction tests so they use parametrized "from" memory type
- Improve mock manager's implementation, e.g. allocate a block of
dummy memory that can be used when testing page mapping functions
- Suggestion: Add test cases with external BOs
- Suggestion: randomize the number and size of tested buffers in
ttm_bo_validate()
- Agree on the naming convention
- Rewrite the mock manager: drop use_tt and manage mock memory using
drm_mm manager
Notes and gotchas
=================
- These tests are built and run with a UML kernel, because
1) We are interested in hardware-independent testing
2) We don't want to have actual DRM devices interacting with TTM
at the same time as the test one. Getting these to work in
parallel would require some time (...and that's a "todo" in itself!)
- Triggering ttm_bo_vm_ops callbacks from KUnit (i.e. kernel) might be
a challenge, but is worth trying. Look at selftests like
i915/gem/selftests/i915_gem_mman.c for inspiration
- The test suite uses UML where ioremap() call returns NULL, meaning that
ttm_bo_ioremap() can't be tested, unless we find a way to stub it
......@@ -18,6 +18,12 @@
#define BO_SIZE SZ_8K
#ifdef CONFIG_PREEMPT_RT
#define ww_mutex_base_lock(b) rt_mutex_lock(b)
#else
#define ww_mutex_base_lock(b) mutex_lock(b)
#endif
struct ttm_bo_test_case {
const char *description;
bool interruptible;
......@@ -56,7 +62,7 @@ static void ttm_bo_reserve_optimistic_no_ticket(struct kunit *test)
struct ttm_buffer_object *bo;
int err;
bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE);
bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE, NULL);
err = ttm_bo_reserve(bo, params->interruptible, params->no_wait, NULL);
KUNIT_ASSERT_EQ(test, err, 0);
......@@ -71,7 +77,7 @@ static void ttm_bo_reserve_locked_no_sleep(struct kunit *test)
bool no_wait = true;
int err;
bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE);
bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE, NULL);
/* Let's lock it beforehand */
dma_resv_lock(bo->base.resv, NULL);
......@@ -92,7 +98,7 @@ static void ttm_bo_reserve_no_wait_ticket(struct kunit *test)
ww_acquire_init(&ctx, &reservation_ww_class);
bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE);
bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE, NULL);
err = ttm_bo_reserve(bo, interruptible, no_wait, &ctx);
KUNIT_ASSERT_EQ(test, err, -EBUSY);
......@@ -110,7 +116,7 @@ static void ttm_bo_reserve_double_resv(struct kunit *test)
ww_acquire_init(&ctx, &reservation_ww_class);
bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE);
bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE, NULL);
err = ttm_bo_reserve(bo, interruptible, no_wait, &ctx);
KUNIT_ASSERT_EQ(test, err, 0);
......@@ -138,11 +144,11 @@ static void ttm_bo_reserve_deadlock(struct kunit *test)
bool no_wait = false;
int err;
bo1 = ttm_bo_kunit_init(test, test->priv, BO_SIZE);
bo2 = ttm_bo_kunit_init(test, test->priv, BO_SIZE);
bo1 = ttm_bo_kunit_init(test, test->priv, BO_SIZE, NULL);
bo2 = ttm_bo_kunit_init(test, test->priv, BO_SIZE, NULL);
ww_acquire_init(&ctx1, &reservation_ww_class);
mutex_lock(&bo2->base.resv->lock.base);
ww_mutex_base_lock(&bo2->base.resv->lock.base);
/* The deadlock will be caught by WW mutex, don't warn about it */
lock_release(&bo2->base.resv->lock.base.dep_map, 1);
......@@ -208,7 +214,7 @@ static void ttm_bo_reserve_interrupted(struct kunit *test)
struct task_struct *task;
int err;
bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE);
bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE, NULL);
task = kthread_create(threaded_ttm_bo_reserve, bo, "ttm-bo-reserve");
......@@ -237,7 +243,7 @@ static void ttm_bo_unreserve_basic(struct kunit *test)
struct ttm_place *place;
struct ttm_resource_manager *man;
unsigned int bo_prio = TTM_MAX_BO_PRIORITY - 1;
uint32_t mem_type = TTM_PL_SYSTEM;
u32 mem_type = TTM_PL_SYSTEM;
int err;
place = ttm_place_kunit_init(test, mem_type, 0);
......@@ -249,7 +255,7 @@ static void ttm_bo_unreserve_basic(struct kunit *test)
KUNIT_ASSERT_EQ(test, err, 0);
priv->ttm_dev = ttm_dev;
bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE);
bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE, NULL);
bo->priority = bo_prio;
err = ttm_resource_alloc(bo, place, &res1);
......@@ -278,7 +284,7 @@ static void ttm_bo_unreserve_pinned(struct kunit *test)
struct ttm_device *ttm_dev;
struct ttm_resource *res1, *res2;
struct ttm_place *place;
uint32_t mem_type = TTM_PL_SYSTEM;
u32 mem_type = TTM_PL_SYSTEM;
int err;
ttm_dev = kunit_kzalloc(test, sizeof(*ttm_dev), GFP_KERNEL);
......@@ -288,7 +294,7 @@ static void ttm_bo_unreserve_pinned(struct kunit *test)
KUNIT_ASSERT_EQ(test, err, 0);
priv->ttm_dev = ttm_dev;
bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE);
bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE, NULL);
place = ttm_place_kunit_init(test, mem_type, 0);
dma_resv_lock(bo->base.resv, NULL);
......@@ -321,7 +327,8 @@ static void ttm_bo_unreserve_bulk(struct kunit *test)
struct ttm_resource *res1, *res2;
struct ttm_device *ttm_dev;
struct ttm_place *place;
uint32_t mem_type = TTM_PL_SYSTEM;
struct dma_resv *resv;
u32 mem_type = TTM_PL_SYSTEM;
unsigned int bo_priority = 0;
int err;
......@@ -332,12 +339,17 @@ static void ttm_bo_unreserve_bulk(struct kunit *test)
ttm_dev = kunit_kzalloc(test, sizeof(*ttm_dev), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, ttm_dev);
resv = kunit_kzalloc(test, sizeof(*resv), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, ttm_dev);
err = ttm_device_kunit_init(priv, ttm_dev, false, false);
KUNIT_ASSERT_EQ(test, err, 0);
priv->ttm_dev = ttm_dev;
bo1 = ttm_bo_kunit_init(test, test->priv, BO_SIZE);
bo2 = ttm_bo_kunit_init(test, test->priv, BO_SIZE);
dma_resv_init(resv);
bo1 = ttm_bo_kunit_init(test, test->priv, BO_SIZE, resv);
bo2 = ttm_bo_kunit_init(test, test->priv, BO_SIZE, resv);
dma_resv_lock(bo1->base.resv, NULL);
ttm_bo_set_bulk_move(bo1, &lru_bulk_move);
......@@ -363,6 +375,8 @@ static void ttm_bo_unreserve_bulk(struct kunit *test)
ttm_resource_free(bo1, &res1);
ttm_resource_free(bo2, &res2);
dma_resv_fini(resv);
}
static void ttm_bo_put_basic(struct kunit *test)
......@@ -372,7 +386,7 @@ static void ttm_bo_put_basic(struct kunit *test)
struct ttm_resource *res;
struct ttm_device *ttm_dev;
struct ttm_place *place;
uint32_t mem_type = TTM_PL_SYSTEM;
u32 mem_type = TTM_PL_SYSTEM;
int err;
place = ttm_place_kunit_init(test, mem_type, 0);
......@@ -384,7 +398,7 @@ static void ttm_bo_put_basic(struct kunit *test)
KUNIT_ASSERT_EQ(test, err, 0);
priv->ttm_dev = ttm_dev;
bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE);
bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE, NULL);
bo->type = ttm_bo_type_device;
err = ttm_resource_alloc(bo, place, &res);
......@@ -445,7 +459,7 @@ static void ttm_bo_put_shared_resv(struct kunit *test)
dma_fence_signal(fence);
bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE);
bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE, NULL);
bo->type = ttm_bo_type_device;
bo->base.resv = external_resv;
......@@ -467,7 +481,7 @@ static void ttm_bo_pin_basic(struct kunit *test)
KUNIT_ASSERT_EQ(test, err, 0);
priv->ttm_dev = ttm_dev;
bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE);
bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE, NULL);
for (int i = 0; i < no_pins; i++) {
dma_resv_lock(bo->base.resv, NULL);
......@@ -487,7 +501,7 @@ static void ttm_bo_pin_unpin_resource(struct kunit *test)
struct ttm_resource *res;
struct ttm_device *ttm_dev;
struct ttm_place *place;
uint32_t mem_type = TTM_PL_SYSTEM;
u32 mem_type = TTM_PL_SYSTEM;
unsigned int bo_priority = 0;
int err;
......@@ -502,7 +516,7 @@ static void ttm_bo_pin_unpin_resource(struct kunit *test)
KUNIT_ASSERT_EQ(test, err, 0);
priv->ttm_dev = ttm_dev;
bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE);
bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE, NULL);
err = ttm_resource_alloc(bo, place, &res);
KUNIT_ASSERT_EQ(test, err, 0);
......@@ -538,7 +552,7 @@ static void ttm_bo_multiple_pin_one_unpin(struct kunit *test)
struct ttm_resource *res;
struct ttm_device *ttm_dev;
struct ttm_place *place;
uint32_t mem_type = TTM_PL_SYSTEM;
u32 mem_type = TTM_PL_SYSTEM;
unsigned int bo_priority = 0;
int err;
......@@ -553,7 +567,7 @@ static void ttm_bo_multiple_pin_one_unpin(struct kunit *test)
KUNIT_ASSERT_EQ(test, err, 0);
priv->ttm_dev = ttm_dev;
bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE);
bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE, NULL);
err = ttm_resource_alloc(bo, place, &res);
KUNIT_ASSERT_EQ(test, err, 0);
......@@ -619,4 +633,5 @@ static struct kunit_suite ttm_bo_test_suite = {
kunit_test_suites(&ttm_bo_test_suite);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("KUnit tests for ttm_bo APIs");
MODULE_LICENSE("GPL and additional rights");
This diff is collapsed.
......@@ -209,4 +209,5 @@ static struct kunit_suite ttm_device_test_suite = {
kunit_test_suites(&ttm_device_test_suite);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("KUnit tests for ttm_device APIs");
MODULE_LICENSE("GPL and additional rights");
......@@ -6,8 +6,43 @@
#include "ttm_kunit_helpers.h"
static struct ttm_tt *ttm_tt_simple_create(struct ttm_buffer_object *bo,
uint32_t page_flags)
static const struct ttm_place sys_place = {
.fpfn = 0,
.lpfn = 0,
.mem_type = TTM_PL_SYSTEM,
.flags = TTM_PL_FLAG_FALLBACK,
};
static const struct ttm_place mock1_place = {
.fpfn = 0,
.lpfn = 0,
.mem_type = TTM_PL_MOCK1,
.flags = TTM_PL_FLAG_FALLBACK,
};
static const struct ttm_place mock2_place = {
.fpfn = 0,
.lpfn = 0,
.mem_type = TTM_PL_MOCK2,
.flags = TTM_PL_FLAG_FALLBACK,
};
static struct ttm_placement sys_placement = {
.num_placement = 1,
.placement = &sys_place,
};
static struct ttm_placement bad_placement = {
.num_placement = 1,
.placement = &mock1_place,
};
static struct ttm_placement mock_placement = {
.num_placement = 1,
.placement = &mock2_place,
};
static struct ttm_tt *ttm_tt_simple_create(struct ttm_buffer_object *bo, u32 page_flags)
{
struct ttm_tt *tt;
......@@ -22,13 +57,84 @@ static void ttm_tt_simple_destroy(struct ttm_device *bdev, struct ttm_tt *ttm)
kfree(ttm);
}
static void dummy_ttm_bo_destroy(struct ttm_buffer_object *bo)
static int mock_move(struct ttm_buffer_object *bo, bool evict,
struct ttm_operation_ctx *ctx,
struct ttm_resource *new_mem,
struct ttm_place *hop)
{
struct ttm_resource *old_mem = bo->resource;
if (!old_mem || (old_mem->mem_type == TTM_PL_SYSTEM && !bo->ttm)) {
ttm_bo_move_null(bo, new_mem);
return 0;
}
if (bo->resource->mem_type == TTM_PL_VRAM &&
new_mem->mem_type == TTM_PL_SYSTEM) {
hop->mem_type = TTM_PL_TT;
hop->flags = TTM_PL_FLAG_TEMPORARY;
hop->fpfn = 0;
hop->lpfn = 0;
return -EMULTIHOP;
}
if ((old_mem->mem_type == TTM_PL_SYSTEM &&
new_mem->mem_type == TTM_PL_TT) ||
(old_mem->mem_type == TTM_PL_TT &&
new_mem->mem_type == TTM_PL_SYSTEM)) {
ttm_bo_move_null(bo, new_mem);
return 0;
}
return ttm_bo_move_memcpy(bo, ctx, new_mem);
}
static void mock_evict_flags(struct ttm_buffer_object *bo,
struct ttm_placement *placement)
{
switch (bo->resource->mem_type) {
case TTM_PL_VRAM:
case TTM_PL_SYSTEM:
*placement = sys_placement;
break;
case TTM_PL_TT:
*placement = mock_placement;
break;
case TTM_PL_MOCK1:
/* Purge objects coming from this domain */
break;
}
}
static void bad_evict_flags(struct ttm_buffer_object *bo,
struct ttm_placement *placement)
{
*placement = bad_placement;
}
static int ttm_device_kunit_init_with_funcs(struct ttm_test_devices *priv,
struct ttm_device *ttm,
bool use_dma_alloc,
bool use_dma32,
struct ttm_device_funcs *funcs)
{
struct drm_device *drm = priv->drm;
int err;
err = ttm_device_init(ttm, funcs, drm->dev,
drm->anon_inode->i_mapping,
drm->vma_offset_manager,
use_dma_alloc, use_dma32);
return err;
}
struct ttm_device_funcs ttm_dev_funcs = {
.ttm_tt_create = ttm_tt_simple_create,
.ttm_tt_destroy = ttm_tt_simple_destroy,
.move = mock_move,
.eviction_valuable = ttm_bo_eviction_valuable,
.evict_flags = mock_evict_flags,
};
EXPORT_SYMBOL_GPL(ttm_dev_funcs);
......@@ -37,21 +143,34 @@ int ttm_device_kunit_init(struct ttm_test_devices *priv,
bool use_dma_alloc,
bool use_dma32)
{
struct drm_device *drm = priv->drm;
int err;
return ttm_device_kunit_init_with_funcs(priv, ttm, use_dma_alloc,
use_dma32, &ttm_dev_funcs);
}
EXPORT_SYMBOL_GPL(ttm_device_kunit_init);
err = ttm_device_init(ttm, &ttm_dev_funcs, drm->dev,
drm->anon_inode->i_mapping,
drm->vma_offset_manager,
use_dma_alloc, use_dma32);
struct ttm_device_funcs ttm_dev_funcs_bad_evict = {
.ttm_tt_create = ttm_tt_simple_create,
.ttm_tt_destroy = ttm_tt_simple_destroy,
.move = mock_move,
.eviction_valuable = ttm_bo_eviction_valuable,
.evict_flags = bad_evict_flags,
};
EXPORT_SYMBOL_GPL(ttm_dev_funcs_bad_evict);
return err;
int ttm_device_kunit_init_bad_evict(struct ttm_test_devices *priv,
struct ttm_device *ttm,
bool use_dma_alloc,
bool use_dma32)
{
return ttm_device_kunit_init_with_funcs(priv, ttm, use_dma_alloc,
use_dma32, &ttm_dev_funcs_bad_evict);
}
EXPORT_SYMBOL_GPL(ttm_device_kunit_init);
EXPORT_SYMBOL_GPL(ttm_device_kunit_init_bad_evict);
struct ttm_buffer_object *ttm_bo_kunit_init(struct kunit *test,
struct ttm_test_devices *devs,
size_t size)
size_t size,
struct dma_resv *obj)
{
struct drm_gem_object gem_obj = { };
struct ttm_buffer_object *bo;
......@@ -61,6 +180,10 @@ struct ttm_buffer_object *ttm_bo_kunit_init(struct kunit *test,
KUNIT_ASSERT_NOT_NULL(test, bo);
bo->base = gem_obj;
if (obj)
bo->base.resv = obj;
err = drm_gem_object_init(devs->drm, &bo->base, size);
KUNIT_ASSERT_EQ(test, err, 0);
......@@ -73,8 +196,7 @@ struct ttm_buffer_object *ttm_bo_kunit_init(struct kunit *test,
}
EXPORT_SYMBOL_GPL(ttm_bo_kunit_init);
struct ttm_place *ttm_place_kunit_init(struct kunit *test,
uint32_t mem_type, uint32_t flags)
struct ttm_place *ttm_place_kunit_init(struct kunit *test, u32 mem_type, u32 flags)
{
struct ttm_place *place;
......@@ -88,6 +210,12 @@ struct ttm_place *ttm_place_kunit_init(struct kunit *test,
}
EXPORT_SYMBOL_GPL(ttm_place_kunit_init);
void dummy_ttm_bo_destroy(struct ttm_buffer_object *bo)
{
drm_gem_object_release(&bo->base);
}
EXPORT_SYMBOL_GPL(dummy_ttm_bo_destroy);
struct ttm_test_devices *ttm_test_devices_basic(struct kunit *test)
{
struct ttm_test_devices *devs;
......@@ -98,6 +226,9 @@ struct ttm_test_devices *ttm_test_devices_basic(struct kunit *test)
devs->dev = drm_kunit_helper_alloc_device(test);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, devs->dev);
/* Set mask for alloc_coherent mappings to enable ttm_pool_alloc testing */
devs->dev->coherent_dma_mask = -1;
devs->drm = __drm_kunit_helper_alloc_drm_device(test, devs->dev,
sizeof(*devs->drm), 0,
DRIVER_GEM);
......@@ -150,10 +281,25 @@ int ttm_test_devices_init(struct kunit *test)
}
EXPORT_SYMBOL_GPL(ttm_test_devices_init);
int ttm_test_devices_all_init(struct kunit *test)
{
struct ttm_test_devices *priv;
priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, priv);
priv = ttm_test_devices_all(test);
test->priv = priv;
return 0;
}
EXPORT_SYMBOL_GPL(ttm_test_devices_all_init);
void ttm_test_devices_fini(struct kunit *test)
{
ttm_test_devices_put(test, test->priv);
}
EXPORT_SYMBOL_GPL(ttm_test_devices_fini);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("TTM KUnit test helper functions");
MODULE_LICENSE("GPL and additional rights");
......@@ -13,7 +13,11 @@
#include <drm/drm_kunit_helpers.h>
#include <kunit/test.h>
#define TTM_PL_MOCK1 (TTM_PL_PRIV + 1)
#define TTM_PL_MOCK2 (TTM_PL_PRIV + 2)
extern struct ttm_device_funcs ttm_dev_funcs;
extern struct ttm_device_funcs ttm_dev_funcs_bad_evict;
struct ttm_test_devices {
struct drm_device *drm;
......@@ -26,11 +30,17 @@ int ttm_device_kunit_init(struct ttm_test_devices *priv,
struct ttm_device *ttm,
bool use_dma_alloc,
bool use_dma32);
int ttm_device_kunit_init_bad_evict(struct ttm_test_devices *priv,
struct ttm_device *ttm,
bool use_dma_alloc,
bool use_dma32);
struct ttm_buffer_object *ttm_bo_kunit_init(struct kunit *test,
struct ttm_test_devices *devs,
size_t size);
struct ttm_place *ttm_place_kunit_init(struct kunit *test,
uint32_t mem_type, uint32_t flags);
size_t size,
struct dma_resv *obj);
struct ttm_place *ttm_place_kunit_init(struct kunit *test, u32 mem_type,
u32 flags);
void dummy_ttm_bo_destroy(struct ttm_buffer_object *bo);
struct ttm_test_devices *ttm_test_devices_basic(struct kunit *test);
struct ttm_test_devices *ttm_test_devices_all(struct kunit *test);
......@@ -39,6 +49,7 @@ void ttm_test_devices_put(struct kunit *test, struct ttm_test_devices *devs);
/* Generic init/fini for tests that only need DRM/TTM devices */
int ttm_test_devices_init(struct kunit *test);
int ttm_test_devices_all_init(struct kunit *test);
void ttm_test_devices_fini(struct kunit *test);
#endif // TTM_KUNIT_HELPERS_H
// SPDX-License-Identifier: GPL-2.0 AND MIT
/*
* Copyright © 2023 Intel Corporation
*/
#include <drm/ttm/ttm_resource.h>
#include <drm/ttm/ttm_device.h>
#include <drm/ttm/ttm_placement.h>
#include "ttm_mock_manager.h"
static inline struct ttm_mock_manager *
to_mock_mgr(struct ttm_resource_manager *man)
{
return container_of(man, struct ttm_mock_manager, man);
}
static inline struct ttm_mock_resource *
to_mock_mgr_resource(struct ttm_resource *res)
{
return container_of(res, struct ttm_mock_resource, base);
}
static int ttm_mock_manager_alloc(struct ttm_resource_manager *man,
struct ttm_buffer_object *bo,
const struct ttm_place *place,
struct ttm_resource **res)
{
struct ttm_mock_manager *manager = to_mock_mgr(man);
struct ttm_mock_resource *mock_res;
struct drm_buddy *mm = &manager->mm;
u64 lpfn, fpfn, alloc_size;
int err;
mock_res = kzalloc(sizeof(*mock_res), GFP_KERNEL);
if (!mock_res)
return -ENOMEM;
fpfn = 0;
lpfn = man->size;
ttm_resource_init(bo, place, &mock_res->base);
INIT_LIST_HEAD(&mock_res->blocks);
if (place->flags & TTM_PL_FLAG_TOPDOWN)
mock_res->flags |= DRM_BUDDY_TOPDOWN_ALLOCATION;
if (place->flags & TTM_PL_FLAG_CONTIGUOUS)
mock_res->flags |= DRM_BUDDY_CONTIGUOUS_ALLOCATION;
alloc_size = (uint64_t)mock_res->base.size;
mutex_lock(&manager->lock);
err = drm_buddy_alloc_blocks(mm, fpfn, lpfn, alloc_size,
manager->default_page_size,
&mock_res->blocks,
mock_res->flags);
if (err)
goto error_free_blocks;
mutex_unlock(&manager->lock);
*res = &mock_res->base;
return 0;
error_free_blocks:
drm_buddy_free_list(mm, &mock_res->blocks, 0);
ttm_resource_fini(man, &mock_res->base);
mutex_unlock(&manager->lock);
return err;
}
static void ttm_mock_manager_free(struct ttm_resource_manager *man,
struct ttm_resource *res)
{
struct ttm_mock_manager *manager = to_mock_mgr(man);
struct ttm_mock_resource *mock_res = to_mock_mgr_resource(res);
struct drm_buddy *mm = &manager->mm;
mutex_lock(&manager->lock);
drm_buddy_free_list(mm, &mock_res->blocks, 0);
mutex_unlock(&manager->lock);
ttm_resource_fini(man, res);
kfree(mock_res);
}
static const struct ttm_resource_manager_func ttm_mock_manager_funcs = {
.alloc = ttm_mock_manager_alloc,
.free = ttm_mock_manager_free,
};
int ttm_mock_manager_init(struct ttm_device *bdev, u32 mem_type, u32 size)
{
struct ttm_mock_manager *manager;
struct ttm_resource_manager *base;
int err;
manager = kzalloc(sizeof(*manager), GFP_KERNEL);
if (!manager)
return -ENOMEM;
mutex_init(&manager->lock);
err = drm_buddy_init(&manager->mm, size, PAGE_SIZE);
if (err) {
kfree(manager);
return err;
}
manager->default_page_size = PAGE_SIZE;
base = &manager->man;
base->func = &ttm_mock_manager_funcs;
base->use_tt = true;
ttm_resource_manager_init(base, bdev, size);
ttm_set_driver_manager(bdev, mem_type, base);
ttm_resource_manager_set_used(base, true);
return 0;
}
EXPORT_SYMBOL_GPL(ttm_mock_manager_init);
void ttm_mock_manager_fini(struct ttm_device *bdev, u32 mem_type)
{
struct ttm_resource_manager *man;
struct ttm_mock_manager *mock_man;
int err;
man = ttm_manager_type(bdev, mem_type);
mock_man = to_mock_mgr(man);
err = ttm_resource_manager_evict_all(bdev, man);
if (err)
return;
ttm_resource_manager_set_used(man, false);
mutex_lock(&mock_man->lock);
drm_buddy_fini(&mock_man->mm);
mutex_unlock(&mock_man->lock);
ttm_set_driver_manager(bdev, mem_type, NULL);
}
EXPORT_SYMBOL_GPL(ttm_mock_manager_fini);
static int ttm_bad_manager_alloc(struct ttm_resource_manager *man,
struct ttm_buffer_object *bo,
const struct ttm_place *place,
struct ttm_resource **res)
{
return -ENOSPC;
}
static int ttm_busy_manager_alloc(struct ttm_resource_manager *man,
struct ttm_buffer_object *bo,
const struct ttm_place *place,
struct ttm_resource **res)
{
return -EBUSY;
}
static void ttm_bad_manager_free(struct ttm_resource_manager *man,
struct ttm_resource *res)
{
}
static bool ttm_bad_manager_compatible(struct ttm_resource_manager *man,
struct ttm_resource *res,
const struct ttm_place *place,
size_t size)
{
return true;
}
static const struct ttm_resource_manager_func ttm_bad_manager_funcs = {
.alloc = ttm_bad_manager_alloc,
.free = ttm_bad_manager_free,
.compatible = ttm_bad_manager_compatible
};
static const struct ttm_resource_manager_func ttm_bad_busy_manager_funcs = {
.alloc = ttm_busy_manager_alloc,
.free = ttm_bad_manager_free,
.compatible = ttm_bad_manager_compatible
};
int ttm_bad_manager_init(struct ttm_device *bdev, u32 mem_type, u32 size)
{
struct ttm_resource_manager *man;
man = kzalloc(sizeof(*man), GFP_KERNEL);
if (!man)
return -ENOMEM;
man->func = &ttm_bad_manager_funcs;
ttm_resource_manager_init(man, bdev, size);
ttm_set_driver_manager(bdev, mem_type, man);
ttm_resource_manager_set_used(man, true);
return 0;
}
EXPORT_SYMBOL_GPL(ttm_bad_manager_init);
int ttm_busy_manager_init(struct ttm_device *bdev, u32 mem_type, u32 size)
{
struct ttm_resource_manager *man;
ttm_bad_manager_init(bdev, mem_type, size);
man = ttm_manager_type(bdev, mem_type);
man->func = &ttm_bad_busy_manager_funcs;
return 0;
}
EXPORT_SYMBOL_GPL(ttm_busy_manager_init);
void ttm_bad_manager_fini(struct ttm_device *bdev, uint32_t mem_type)
{
struct ttm_resource_manager *man;
man = ttm_manager_type(bdev, mem_type);
ttm_resource_manager_set_used(man, false);
ttm_set_driver_manager(bdev, mem_type, NULL);
kfree(man);
}
EXPORT_SYMBOL_GPL(ttm_bad_manager_fini);
MODULE_DESCRIPTION("KUnit tests for ttm with mock resource managers");
MODULE_LICENSE("GPL and additional rights");
/* SPDX-License-Identifier: GPL-2.0 AND MIT */
/*
* Copyright © 2023 Intel Corporation
*/
#ifndef TTM_MOCK_MANAGER_H
#define TTM_MOCK_MANAGER_H
#include <drm/drm_buddy.h>
struct ttm_mock_manager {
struct ttm_resource_manager man;
struct drm_buddy mm;
u64 default_page_size;
/* protects allocations of mock buffer objects */
struct mutex lock;
};
struct ttm_mock_resource {
struct ttm_resource base;
struct list_head blocks;
unsigned long flags;
};
int ttm_mock_manager_init(struct ttm_device *bdev, u32 mem_type, u32 size);
int ttm_bad_manager_init(struct ttm_device *bdev, u32 mem_type, u32 size);
int ttm_busy_manager_init(struct ttm_device *bdev, u32 mem_type, u32 size);
void ttm_mock_manager_fini(struct ttm_device *bdev, u32 mem_type);
void ttm_bad_manager_fini(struct ttm_device *bdev, u32 mem_type);
#endif // TTM_MOCK_MANAGER_H
......@@ -48,7 +48,7 @@ static void ttm_pool_test_fini(struct kunit *test)
}
static struct ttm_tt *ttm_tt_kunit_init(struct kunit *test,
uint32_t page_flags,
u32 page_flags,
enum ttm_caching caching,
size_t size)
{
......@@ -57,7 +57,7 @@ static struct ttm_tt *ttm_tt_kunit_init(struct kunit *test,
struct ttm_tt *tt;
int err;
bo = ttm_bo_kunit_init(test, priv->devs, size);
bo = ttm_bo_kunit_init(test, priv->devs, size, NULL);
KUNIT_ASSERT_NOT_NULL(test, bo);
priv->mock_bo = bo;
......@@ -209,7 +209,7 @@ static void ttm_pool_alloc_basic_dma_addr(struct kunit *test)
tt = kunit_kzalloc(test, sizeof(*tt), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, tt);
bo = ttm_bo_kunit_init(test, devs, size);
bo = ttm_bo_kunit_init(test, devs, size, NULL);
KUNIT_ASSERT_NOT_NULL(test, bo);
err = ttm_sg_tt_init(tt, bo, 0, caching);
......@@ -433,4 +433,5 @@ static struct kunit_suite ttm_pool_test_suite = {
kunit_test_suites(&ttm_pool_test_suite);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("KUnit tests for ttm_pool APIs");
MODULE_LICENSE("GPL and additional rights");
......@@ -11,8 +11,8 @@
struct ttm_resource_test_case {
const char *description;
uint32_t mem_type;
uint32_t flags;
u32 mem_type;
u32 flags;
};
struct ttm_resource_test_priv {
......@@ -47,20 +47,20 @@ static void ttm_resource_test_fini(struct kunit *test)
static void ttm_init_test_mocks(struct kunit *test,
struct ttm_resource_test_priv *priv,
uint32_t mem_type, uint32_t flags)
u32 mem_type, u32 flags)
{
size_t size = RES_SIZE;
/* Make sure we have what we need for a good BO mock */
KUNIT_ASSERT_NOT_NULL(test, priv->devs->ttm_dev);
priv->bo = ttm_bo_kunit_init(test, priv->devs, size);
priv->bo = ttm_bo_kunit_init(test, priv->devs, size, NULL);
priv->place = ttm_place_kunit_init(test, mem_type, flags);
}
static void ttm_init_test_manager(struct kunit *test,
struct ttm_resource_test_priv *priv,
uint32_t mem_type)
u32 mem_type)
{
struct ttm_device *ttm_dev = priv->devs->ttm_dev;
struct ttm_resource_manager *man;
......@@ -112,7 +112,7 @@ static void ttm_resource_init_basic(struct kunit *test)
struct ttm_buffer_object *bo;
struct ttm_place *place;
struct ttm_resource_manager *man;
uint64_t expected_usage;
u64 expected_usage;
ttm_init_test_mocks(test, priv, params->mem_type, params->flags);
bo = priv->bo;
......@@ -230,7 +230,7 @@ static void ttm_resource_manager_usage_basic(struct kunit *test)
struct ttm_buffer_object *bo;
struct ttm_place *place;
struct ttm_resource_manager *man;
uint64_t actual_usage;
u64 actual_usage;
ttm_init_test_mocks(test, priv, TTM_PL_SYSTEM, TTM_PL_FLAG_TOPDOWN);
bo = priv->bo;
......@@ -268,7 +268,7 @@ static void ttm_sys_man_alloc_basic(struct kunit *test)
struct ttm_buffer_object *bo;
struct ttm_place *place;
struct ttm_resource *res;
uint32_t mem_type = TTM_PL_SYSTEM;
u32 mem_type = TTM_PL_SYSTEM;
int ret;
ttm_init_test_mocks(test, priv, mem_type, 0);
......@@ -293,7 +293,7 @@ static void ttm_sys_man_free_basic(struct kunit *test)
struct ttm_buffer_object *bo;
struct ttm_place *place;
struct ttm_resource *res;
uint32_t mem_type = TTM_PL_SYSTEM;
u32 mem_type = TTM_PL_SYSTEM;
ttm_init_test_mocks(test, priv, mem_type, 0);
bo = priv->bo;
......@@ -332,4 +332,5 @@ static struct kunit_suite ttm_resource_test_suite = {
kunit_test_suites(&ttm_resource_test_suite);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("KUnit tests for ttm_resource and ttm_sys_man APIs");
MODULE_LICENSE("GPL and additional rights");
......@@ -11,23 +11,10 @@
struct ttm_tt_test_case {
const char *description;
uint32_t size;
uint32_t extra_pages_num;
u32 size;
u32 extra_pages_num;
};
static int ttm_tt_test_init(struct kunit *test)
{
struct ttm_test_devices *priv;
priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, priv);
priv = ttm_test_devices_all(test);
test->priv = priv;
return 0;
}
static const struct ttm_tt_test_case ttm_tt_init_basic_cases[] = {
{
.description = "Page-aligned size",
......@@ -54,16 +41,16 @@ static void ttm_tt_init_basic(struct kunit *test)
const struct ttm_tt_test_case *params = test->param_value;
struct ttm_buffer_object *bo;
struct ttm_tt *tt;
uint32_t page_flags = TTM_TT_FLAG_ZERO_ALLOC;
u32 page_flags = TTM_TT_FLAG_ZERO_ALLOC;
enum ttm_caching caching = ttm_cached;
uint32_t extra_pages = params->extra_pages_num;
u32 extra_pages = params->extra_pages_num;
int num_pages = params->size >> PAGE_SHIFT;
int err;
tt = kunit_kzalloc(test, sizeof(*tt), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, tt);
bo = ttm_bo_kunit_init(test, test->priv, params->size);
bo = ttm_bo_kunit_init(test, test->priv, params->size, NULL);
err = ttm_tt_init(tt, bo, page_flags, caching, extra_pages);
KUNIT_ASSERT_EQ(test, err, 0);
......@@ -82,14 +69,14 @@ static void ttm_tt_init_misaligned(struct kunit *test)
struct ttm_buffer_object *bo;
struct ttm_tt *tt;
enum ttm_caching caching = ttm_cached;
uint32_t size = SZ_8K;
u32 size = SZ_8K;
int num_pages = (size + SZ_4K) >> PAGE_SHIFT;
int err;
tt = kunit_kzalloc(test, sizeof(*tt), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, tt);
bo = ttm_bo_kunit_init(test, test->priv, size);
bo = ttm_bo_kunit_init(test, test->priv, size, NULL);
/* Make the object size misaligned */
bo->base.size += 1;
......@@ -110,7 +97,7 @@ static void ttm_tt_fini_basic(struct kunit *test)
tt = kunit_kzalloc(test, sizeof(*tt), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, tt);
bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE);
bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE, NULL);
err = ttm_tt_init(tt, bo, 0, caching, 0);
KUNIT_ASSERT_EQ(test, err, 0);
......@@ -130,7 +117,7 @@ static void ttm_tt_fini_sg(struct kunit *test)
tt = kunit_kzalloc(test, sizeof(*tt), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, tt);
bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE);
bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE, NULL);
err = ttm_sg_tt_init(tt, bo, 0, caching);
KUNIT_ASSERT_EQ(test, err, 0);
......@@ -151,7 +138,7 @@ static void ttm_tt_fini_shmem(struct kunit *test)
tt = kunit_kzalloc(test, sizeof(*tt), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, tt);
bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE);
bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE, NULL);
err = ttm_tt_init(tt, bo, 0, caching, 0);
KUNIT_ASSERT_EQ(test, err, 0);
......@@ -168,7 +155,7 @@ static void ttm_tt_create_basic(struct kunit *test)
struct ttm_buffer_object *bo;
int err;
bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE);
bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE, NULL);
bo->type = ttm_bo_type_device;
dma_resv_lock(bo->base.resv, NULL);
......@@ -187,7 +174,7 @@ static void ttm_tt_create_invalid_bo_type(struct kunit *test)
struct ttm_buffer_object *bo;
int err;
bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE);
bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE, NULL);
bo->type = ttm_bo_type_sg + 1;
dma_resv_lock(bo->base.resv, NULL);
......@@ -208,7 +195,7 @@ static void ttm_tt_create_ttm_exists(struct kunit *test)
tt = kunit_kzalloc(test, sizeof(*tt), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, tt);
bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE);
bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE, NULL);
err = ttm_tt_init(tt, bo, 0, caching, 0);
KUNIT_ASSERT_EQ(test, err, 0);
......@@ -224,7 +211,7 @@ static void ttm_tt_create_ttm_exists(struct kunit *test)
}
static struct ttm_tt *ttm_tt_null_create(struct ttm_buffer_object *bo,
uint32_t page_flags)
u32 page_flags)
{
return NULL;
}
......@@ -239,7 +226,7 @@ static void ttm_tt_create_failed(struct kunit *test)
struct ttm_buffer_object *bo;
int err;
bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE);
bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE, NULL);
/* Update ttm_device_funcs so we don't alloc ttm_tt */
devs->ttm_dev->funcs = &ttm_dev_empty_funcs;
......@@ -257,7 +244,7 @@ static void ttm_tt_destroy_basic(struct kunit *test)
struct ttm_buffer_object *bo;
int err;
bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE);
bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE, NULL);
dma_resv_lock(bo->base.resv, NULL);
err = ttm_tt_create(bo, false);
......@@ -269,6 +256,120 @@ static void ttm_tt_destroy_basic(struct kunit *test)
ttm_tt_destroy(devs->ttm_dev, bo->ttm);
}
static void ttm_tt_populate_null_ttm(struct kunit *test)
{
const struct ttm_test_devices *devs = test->priv;
struct ttm_operation_ctx ctx = { };
int err;
err = ttm_tt_populate(devs->ttm_dev, NULL, &ctx);
KUNIT_ASSERT_EQ(test, err, -EINVAL);
}
static void ttm_tt_populate_populated_ttm(struct kunit *test)
{
const struct ttm_test_devices *devs = test->priv;
struct ttm_operation_ctx ctx = { };
struct ttm_buffer_object *bo;
struct ttm_tt *tt;
struct page *populated_page;
int err;
bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE, NULL);
tt = kunit_kzalloc(test, sizeof(*tt), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, tt);
err = ttm_tt_init(tt, bo, 0, ttm_cached, 0);
KUNIT_ASSERT_EQ(test, err, 0);
err = ttm_tt_populate(devs->ttm_dev, tt, &ctx);
KUNIT_ASSERT_EQ(test, err, 0);
populated_page = *tt->pages;
err = ttm_tt_populate(devs->ttm_dev, tt, &ctx);
KUNIT_ASSERT_PTR_EQ(test, populated_page, *tt->pages);
}
static void ttm_tt_unpopulate_basic(struct kunit *test)
{
const struct ttm_test_devices *devs = test->priv;
struct ttm_operation_ctx ctx = { };
struct ttm_buffer_object *bo;
struct ttm_tt *tt;
int err;
bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE, NULL);
tt = kunit_kzalloc(test, sizeof(*tt), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, tt);
err = ttm_tt_init(tt, bo, 0, ttm_cached, 0);
KUNIT_ASSERT_EQ(test, err, 0);
err = ttm_tt_populate(devs->ttm_dev, tt, &ctx);
KUNIT_ASSERT_EQ(test, err, 0);
KUNIT_ASSERT_TRUE(test, ttm_tt_is_populated(tt));
ttm_tt_unpopulate(devs->ttm_dev, tt);
KUNIT_ASSERT_FALSE(test, ttm_tt_is_populated(tt));
}
static void ttm_tt_unpopulate_empty_ttm(struct kunit *test)
{
const struct ttm_test_devices *devs = test->priv;
struct ttm_buffer_object *bo;
struct ttm_tt *tt;
int err;
bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE, NULL);
tt = kunit_kzalloc(test, sizeof(*tt), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, tt);
err = ttm_tt_init(tt, bo, 0, ttm_cached, 0);
KUNIT_ASSERT_EQ(test, err, 0);
ttm_tt_unpopulate(devs->ttm_dev, tt);
/* Expect graceful handling of unpopulated TTs */
}
static void ttm_tt_swapin_basic(struct kunit *test)
{
const struct ttm_test_devices *devs = test->priv;
int expected_num_pages = BO_SIZE >> PAGE_SHIFT;
struct ttm_operation_ctx ctx = { };
struct ttm_buffer_object *bo;
struct ttm_tt *tt;
int err, num_pages;
bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE, NULL);
tt = kunit_kzalloc(test, sizeof(*tt), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, tt);
err = ttm_tt_init(tt, bo, 0, ttm_cached, 0);
KUNIT_ASSERT_EQ(test, err, 0);
err = ttm_tt_populate(devs->ttm_dev, tt, &ctx);
KUNIT_ASSERT_EQ(test, err, 0);
KUNIT_ASSERT_TRUE(test, ttm_tt_is_populated(tt));
num_pages = ttm_tt_swapout(devs->ttm_dev, tt, GFP_KERNEL);
KUNIT_ASSERT_EQ(test, num_pages, expected_num_pages);
KUNIT_ASSERT_NOT_NULL(test, tt->swap_storage);
KUNIT_ASSERT_TRUE(test, tt->page_flags & TTM_TT_FLAG_SWAPPED);
/* Swapout depopulates TT, allocate pages and then swap them in */
err = ttm_pool_alloc(&devs->ttm_dev->pool, tt, &ctx);
KUNIT_ASSERT_EQ(test, err, 0);
err = ttm_tt_swapin(tt);
KUNIT_ASSERT_EQ(test, err, 0);
KUNIT_ASSERT_NULL(test, tt->swap_storage);
KUNIT_ASSERT_FALSE(test, tt->page_flags & TTM_TT_FLAG_SWAPPED);
}
static struct kunit_case ttm_tt_test_cases[] = {
KUNIT_CASE_PARAM(ttm_tt_init_basic, ttm_tt_init_basic_gen_params),
KUNIT_CASE(ttm_tt_init_misaligned),
......@@ -280,16 +381,22 @@ static struct kunit_case ttm_tt_test_cases[] = {
KUNIT_CASE(ttm_tt_create_ttm_exists),
KUNIT_CASE(ttm_tt_create_failed),
KUNIT_CASE(ttm_tt_destroy_basic),
KUNIT_CASE(ttm_tt_populate_null_ttm),
KUNIT_CASE(ttm_tt_populate_populated_ttm),
KUNIT_CASE(ttm_tt_unpopulate_basic),
KUNIT_CASE(ttm_tt_unpopulate_empty_ttm),
KUNIT_CASE(ttm_tt_swapin_basic),
{}
};
static struct kunit_suite ttm_tt_test_suite = {
.name = "ttm_tt",
.init = ttm_tt_test_init,
.init = ttm_test_devices_all_init,
.exit = ttm_test_devices_fini,
.test_cases = ttm_tt_test_cases,
};
kunit_test_suites(&ttm_tt_test_suite);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("KUnit tests for ttm_tt APIs");
MODULE_LICENSE("GPL and additional rights");
......@@ -251,6 +251,7 @@ int ttm_tt_swapin(struct ttm_tt *ttm)
out_err:
return ret;
}
EXPORT_SYMBOL_FOR_TESTS_ONLY(ttm_tt_swapin);
/**
* ttm_tt_swapout - swap out tt object
......@@ -308,6 +309,7 @@ int ttm_tt_swapout(struct ttm_device *bdev, struct ttm_tt *ttm,
return ret;
}
EXPORT_SYMBOL_FOR_TESTS_ONLY(ttm_tt_swapout);
int ttm_tt_populate(struct ttm_device *bdev,
struct ttm_tt *ttm, struct ttm_operation_ctx *ctx)
......@@ -386,6 +388,7 @@ void ttm_tt_unpopulate(struct ttm_device *bdev, struct ttm_tt *ttm)
ttm->page_flags &= ~TTM_TT_FLAG_PRIV_POPULATED;
}
EXPORT_SYMBOL_FOR_TESTS_ONLY(ttm_tt_unpopulate);
#ifdef CONFIG_DEBUG_FS
......
This diff is collapsed.
This diff is collapsed.
......@@ -287,7 +287,7 @@ int ipu_prg_channel_configure(struct ipuv3_channel *ipu_chan,
chan = &prg->chan[prg_chan];
if (chan->enabled) {
ipu_pre_update(prg->pres[chan->used_pre], *eba);
ipu_pre_update(prg->pres[chan->used_pre], modifier, *eba);
return 0;
}
......
......@@ -263,7 +263,7 @@ u32 ipu_pre_get_baddr(struct ipu_pre *pre);
void ipu_pre_configure(struct ipu_pre *pre, unsigned int width,
unsigned int height, unsigned int stride, u32 format,
uint64_t modifier, unsigned int bufaddr);
void ipu_pre_update(struct ipu_pre *pre, unsigned int bufaddr);
void ipu_pre_update(struct ipu_pre *pre, uint64_t modifier, unsigned int bufaddr);
bool ipu_pre_update_pending(struct ipu_pre *pre);
struct ipu_prg *ipu_prg_lookup_by_phandle(struct device *dev, const char *name,
......
......@@ -8,6 +8,8 @@ menuconfig LOGO
depends on FB_CORE || SGI_NEWPORT_CONSOLE
help
Enable and select frame buffer bootup logos.
Monochrome logos will also be used by the DRM panic handler, if
enabled.
if LOGO
......
......@@ -29,8 +29,7 @@ struct analogix_dp_plat_data {
struct drm_connector *connector;
bool skip_connector;
int (*power_on_start)(struct analogix_dp_plat_data *);
int (*power_on_end)(struct analogix_dp_plat_data *);
int (*power_on)(struct analogix_dp_plat_data *);
int (*power_off)(struct analogix_dp_plat_data *);
int (*attach)(struct analogix_dp_plat_data *, struct drm_bridge *,
struct drm_connector *);
......@@ -45,7 +44,6 @@ struct analogix_dp_device *
analogix_dp_probe(struct device *dev, struct analogix_dp_plat_data *plat_data);
int analogix_dp_bind(struct analogix_dp_device *dp, struct drm_device *drm_dev);
void analogix_dp_unbind(struct analogix_dp_device *dp);
void analogix_dp_remove(struct analogix_dp_device *dp);
int analogix_dp_start_crc(struct drm_connector *connector);
int analogix_dp_stop_crc(struct drm_connector *connector);
......
......@@ -16,7 +16,7 @@ int drm_atomic_helper_connector_hdmi_check(struct drm_connector *connector,
int drm_atomic_helper_connector_hdmi_update_audio_infoframe(struct drm_connector *connector,
struct hdmi_audio_infoframe *frame);
int drm_atomic_helper_connector_hdmi_disable_audio_infoframe(struct drm_connector *connector);
int drm_atomic_helper_connector_hdmi_clear_audio_infoframe(struct drm_connector *connector);
int drm_atomic_helper_connector_hdmi_update_infoframes(struct drm_connector *connector,
struct drm_atomic_state *state);
......
This diff is collapsed.
......@@ -39,7 +39,11 @@
#include "ttm_device.h"
/* Default number of pre-faulted pages in the TTM fault handler */
#if CONFIG_PGTABLE_LEVELS > 2
#define TTM_BO_VM_NUM_PREFAULT (1 << (PMD_SHIFT - PAGE_SHIFT))
#else
#define TTM_BO_VM_NUM_PREFAULT 16
#endif
struct iosys_map;
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment