drm-misc-next for $kernel-version:

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,
 -----BEGIN PGP SIGNATURE-----
 
 iHUEABYKAB0WIQRcEzekXsqa64kGDp7j7w1vZxhRxQUCZn1DmQAKCRDj7w1vZxhR
 xYj3AP9ThM8q3HoCqXKerpEfnb5LYDB4NocLjn/Bamtm134oNQD+M4Gu2zLSVymV
 74PwtPYuQGKWrmXdw0tD70/MtTAihQc=
 =fSI4
 -----END PGP SIGNATURE-----

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: Dave Airlie <airlied@redhat.com>

From: Maxime Ripard <mripard@redhat.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20240627-congenial-pistachio-nyala-848cf4@houat
This commit is contained in:
Dave Airlie 2024-06-28 08:10:08 +10:00
commit 91fdc5e765
54 changed files with 3864 additions and 1244 deletions

View File

@ -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>;

View File

@ -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

View File

@ -25,8 +25,8 @@ properties:
reg:
enum:
- 0x68
- 0x0f
- 0x68
description: |
i2c address of the bridge, 0x68 or 0x0f, depending on bootstrap pins

View File

@ -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:

View File

@ -0,0 +1,63 @@
# 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>;
};
};
};
};
...

View File

@ -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

View File

@ -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

View File

@ -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/

View File

@ -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

View File

@ -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);

View File

@ -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,40 +1766,16 @@ 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);
if (IS_ENABLED(CONFIG_PM)) {
pm_runtime_dont_use_autosuspend(dp->dev);
pm_runtime_disable(dp->dev);
} else {
analogix_dp_suspend(dp);
}
}
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;
}
return 0;
}
EXPORT_SYMBOL_GPL(analogix_dp_resume);
#endif
int analogix_dp_start_crc(struct drm_connector *connector)
{
struct analogix_dp_device *dp = to_dp(connector);

View File

@ -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,

View File

@ -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;
}

View File

@ -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)

View File

@ -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)

View File

@ -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);

View File

@ -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;

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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_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_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);
mipi_dsi_msleep(dsi_ctx, 100);
return 0;
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;
mipi_dsi_dcs_set_display_off_multi(dsi_ctx);
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_msleep(dsi_ctx, 60);
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_dcs_enter_sleep_mode_multi(dsi_ctx);
mipi_dsi_dcs_write_seq(dsi, 0x4f, 0x01);
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 = {

View File

@ -0,0 +1,402 @@
// SPDX-License-Identifier: GPL-2.0
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/errno.h>
#include <linux/gpio/consumer.h>
#include <linux/kernel.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/property.h>
#include <linux/regulator/consumer.h>
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_modes.h>
#include <drm/drm_panel.h>
#include <drm/drm_probe_helper.h>
#include <video/mipi_display.h>
struct panel_desc {
const struct drm_display_mode *display_mode;
unsigned long mode_flags;
enum mipi_dsi_pixel_format format;
unsigned int lanes;
void (*init_sequence)(struct mipi_dsi_multi_context *ctx);
};
struct ili9806e_panel {
struct drm_panel panel;
struct mipi_dsi_device *dsi;
struct gpio_desc *reset_gpio;
struct regulator_bulk_data supplies[2];
const struct panel_desc *desc;
enum drm_panel_orientation orientation;
};
static const char * const regulator_names[] = {
"vdd",
"vccio",
};
static inline struct ili9806e_panel *to_ili9806e_panel(struct drm_panel *panel)
{
return container_of(panel, struct ili9806e_panel, panel);
}
static int ili9806e_power_on(struct ili9806e_panel *ctx)
{
struct mipi_dsi_device *dsi = ctx->dsi;
int ret;
gpiod_set_value(ctx->reset_gpio, 1);
ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
if (ret < 0) {
dev_err(&dsi->dev, "regulator bulk enable failed: %d\n", ret);
return ret;
}
usleep_range(10000, 20000);
gpiod_set_value(ctx->reset_gpio, 0);
usleep_range(10000, 20000);
return 0;
}
static int ili9806e_power_off(struct ili9806e_panel *ctx)
{
struct mipi_dsi_device *dsi = ctx->dsi;
int ret;
gpiod_set_value(ctx->reset_gpio, 1);
ret = regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
if (ret)
dev_err(&dsi->dev, "regulator bulk disable failed: %d\n", ret);
return ret;
}
static int ili9806e_on(struct ili9806e_panel *ili9806e)
{
struct mipi_dsi_multi_context ctx = { .dsi = ili9806e->dsi };
if (ili9806e->desc->init_sequence)
ili9806e->desc->init_sequence(&ctx);
mipi_dsi_dcs_exit_sleep_mode_multi(&ctx);
mipi_dsi_msleep(&ctx, 120);
mipi_dsi_dcs_set_display_on_multi(&ctx);
return ctx.accum_err;
}
static int ili9806e_off(struct ili9806e_panel *panel)
{
struct mipi_dsi_multi_context ctx = { .dsi = panel->dsi };
mipi_dsi_dcs_set_display_off_multi(&ctx);
mipi_dsi_dcs_enter_sleep_mode_multi(&ctx);
mipi_dsi_msleep(&ctx, 120);
return ctx.accum_err;
}
static int ili9806e_prepare(struct drm_panel *panel)
{
struct ili9806e_panel *ctx = to_ili9806e_panel(panel);
int ret;
ret = ili9806e_power_on(ctx);
if (ret < 0)
return ret;
ret = ili9806e_on(ctx);
if (ret < 0) {
ili9806e_power_off(ctx);
return ret;
}
return 0;
}
static int ili9806e_unprepare(struct drm_panel *panel)
{
struct ili9806e_panel *ctx = to_ili9806e_panel(panel);
struct mipi_dsi_device *dsi = ctx->dsi;
int ret;
ili9806e_off(ctx);
ret = ili9806e_power_off(ctx);
if (ret < 0)
dev_err(&dsi->dev, "power off failed: %d\n", ret);
return ret;
}
static int ili9806e_get_modes(struct drm_panel *panel,
struct drm_connector *connector)
{
struct ili9806e_panel *ctx = to_ili9806e_panel(panel);
const struct drm_display_mode *mode = ctx->desc->display_mode;
return drm_connector_helper_get_modes_fixed(connector, mode);
}
static enum drm_panel_orientation ili9806e_get_orientation(struct drm_panel *panel)
{
struct ili9806e_panel *ctx = to_ili9806e_panel(panel);
return ctx->orientation;
}
static const struct drm_panel_funcs ili9806e_funcs = {
.prepare = ili9806e_prepare,
.unprepare = ili9806e_unprepare,
.get_modes = ili9806e_get_modes,
.get_orientation = ili9806e_get_orientation,
};
static int ili9806e_dsi_probe(struct mipi_dsi_device *dsi)
{
struct device *dev = &dsi->dev;
struct ili9806e_panel *ctx;
int i, ret;
ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx)
return -ENOMEM;
ctx->desc = device_get_match_data(dev);
for (i = 0; i < ARRAY_SIZE(ctx->supplies); i++)
ctx->supplies[i].supply = regulator_names[i];
ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ctx->supplies),
ctx->supplies);
if (ret < 0)
return ret;
ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
if (IS_ERR(ctx->reset_gpio))
return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio),
"Failed to get reset-gpios\n");
mipi_dsi_set_drvdata(dsi, ctx);
ctx->dsi = dsi;
dsi->mode_flags = ctx->desc->mode_flags;
dsi->format = ctx->desc->format;
dsi->lanes = ctx->desc->lanes;
drm_panel_init(&ctx->panel, dev, &ili9806e_funcs,
DRM_MODE_CONNECTOR_DSI);
ret = of_drm_get_panel_orientation(dev->of_node, &ctx->orientation);
if (ret)
return dev_err_probe(dev, ret, "Failed to get orientation\n");
ret = drm_panel_of_backlight(&ctx->panel);
if (ret)
return dev_err_probe(dev, ret, "Failed to get backlight\n");
ctx->panel.prepare_prev_first = true;
drm_panel_add(&ctx->panel);
ret = mipi_dsi_attach(dsi);
if (ret < 0) {
dev_err_probe(dev, ret, "Failed to attach to DSI host\n");
drm_panel_remove(&ctx->panel);
return ret;
}
return 0;
}
static void ili9806e_dsi_remove(struct mipi_dsi_device *dsi)
{
struct ili9806e_panel *ctx = mipi_dsi_get_drvdata(dsi);
mipi_dsi_detach(dsi);
drm_panel_remove(&ctx->panel);
}
static void com35h3p70ulc_init(struct mipi_dsi_multi_context *ctx)
{
/* Switch to page 1 */
mipi_dsi_dcs_write_seq_multi(ctx, 0xff, 0xff, 0x98, 0x06, 0x04, 0x01);
/* Interface Settings */
mipi_dsi_dcs_write_seq_multi(ctx, 0x08, 0x18);
mipi_dsi_dcs_write_seq_multi(ctx, 0x21, 0x01);
/* Panel Settings */
mipi_dsi_dcs_write_seq_multi(ctx, 0x30, 0x03);
mipi_dsi_dcs_write_seq_multi(ctx, 0x31, 0x00);
mipi_dsi_dcs_write_seq_multi(ctx, 0x60, 0x0d);
mipi_dsi_dcs_write_seq_multi(ctx, 0x61, 0x08);
mipi_dsi_dcs_write_seq_multi(ctx, 0x62, 0x08);
mipi_dsi_dcs_write_seq_multi(ctx, 0x63, 0x09);
/* Power Control */
mipi_dsi_dcs_write_seq_multi(ctx, 0x40, 0x30);
mipi_dsi_dcs_write_seq_multi(ctx, 0x41, 0x44);
mipi_dsi_dcs_write_seq_multi(ctx, 0x42, 0x00);
mipi_dsi_dcs_write_seq_multi(ctx, 0x43, 0x89);
mipi_dsi_dcs_write_seq_multi(ctx, 0x44, 0x8e);
mipi_dsi_dcs_write_seq_multi(ctx, 0x45, 0xd9);
mipi_dsi_dcs_write_seq_multi(ctx, 0x46, 0x33);
mipi_dsi_dcs_write_seq_multi(ctx, 0x47, 0x33);
mipi_dsi_dcs_write_seq_multi(ctx, 0x50, 0x90);
mipi_dsi_dcs_write_seq_multi(ctx, 0x51, 0x90);
mipi_dsi_dcs_write_seq_multi(ctx, 0x56, 0x00);
/* Gamma Settings */
mipi_dsi_dcs_write_seq_multi(ctx, 0xa0, 0x00);
mipi_dsi_dcs_write_seq_multi(ctx, 0xa1, 0x0c);
mipi_dsi_dcs_write_seq_multi(ctx, 0xa2, 0x13);
mipi_dsi_dcs_write_seq_multi(ctx, 0xa3, 0x0f);
mipi_dsi_dcs_write_seq_multi(ctx, 0xa4, 0x0a);
mipi_dsi_dcs_write_seq_multi(ctx, 0xa5, 0x0d);
mipi_dsi_dcs_write_seq_multi(ctx, 0xa6, 0x0c);
mipi_dsi_dcs_write_seq_multi(ctx, 0xa7, 0x0b);
mipi_dsi_dcs_write_seq_multi(ctx, 0xa8, 0x01);
mipi_dsi_dcs_write_seq_multi(ctx, 0xa9, 0x06);
mipi_dsi_dcs_write_seq_multi(ctx, 0xaa, 0x15);
mipi_dsi_dcs_write_seq_multi(ctx, 0xab, 0x07);
mipi_dsi_dcs_write_seq_multi(ctx, 0xac, 0x12);
mipi_dsi_dcs_write_seq_multi(ctx, 0xad, 0x28);
mipi_dsi_dcs_write_seq_multi(ctx, 0xae, 0x20);
mipi_dsi_dcs_write_seq_multi(ctx, 0xaf, 0x14);
mipi_dsi_dcs_write_seq_multi(ctx, 0xc0, 0x00);
mipi_dsi_dcs_write_seq_multi(ctx, 0xc1, 0x0c);
mipi_dsi_dcs_write_seq_multi(ctx, 0xc2, 0x13);
mipi_dsi_dcs_write_seq_multi(ctx, 0xc3, 0x0f);
mipi_dsi_dcs_write_seq_multi(ctx, 0xc4, 0x09);
mipi_dsi_dcs_write_seq_multi(ctx, 0xc5, 0x0d);
mipi_dsi_dcs_write_seq_multi(ctx, 0xc6, 0x0c);
mipi_dsi_dcs_write_seq_multi(ctx, 0xc7, 0x0b);
mipi_dsi_dcs_write_seq_multi(ctx, 0xc8, 0x01);
mipi_dsi_dcs_write_seq_multi(ctx, 0xc9, 0x06);
mipi_dsi_dcs_write_seq_multi(ctx, 0xca, 0x14);
mipi_dsi_dcs_write_seq_multi(ctx, 0xcb, 0x07);
mipi_dsi_dcs_write_seq_multi(ctx, 0xcc, 0x0f);
mipi_dsi_dcs_write_seq_multi(ctx, 0xcd, 0x21);
mipi_dsi_dcs_write_seq_multi(ctx, 0xce, 0x17);
mipi_dsi_dcs_write_seq_multi(ctx, 0xcf, 0x0a);
/* Switch to page 7 */
mipi_dsi_dcs_write_seq_multi(ctx, 0xff, 0xff, 0x98, 0x06, 0x04, 0x07);
/* Power Control */
mipi_dsi_dcs_write_seq_multi(ctx, 0x06, 0x00);
mipi_dsi_dcs_write_seq_multi(ctx, 0x18, 0x1d);
mipi_dsi_dcs_write_seq_multi(ctx, 0x17, 0x32);
/* Switch to page 6 */
mipi_dsi_dcs_write_seq_multi(ctx, 0xff, 0xff, 0x98, 0x06, 0x04, 0x06);
/* GIP settings */
mipi_dsi_dcs_write_seq_multi(ctx, 0x00, 0x20);
mipi_dsi_dcs_write_seq_multi(ctx, 0x01, 0x02);
mipi_dsi_dcs_write_seq_multi(ctx, 0x02, 0x00);
mipi_dsi_dcs_write_seq_multi(ctx, 0x03, 0x02);
mipi_dsi_dcs_write_seq_multi(ctx, 0x04, 0x01);
mipi_dsi_dcs_write_seq_multi(ctx, 0x05, 0x01);
mipi_dsi_dcs_write_seq_multi(ctx, 0x06, 0x88);
mipi_dsi_dcs_write_seq_multi(ctx, 0x07, 0x04);
mipi_dsi_dcs_write_seq_multi(ctx, 0x08, 0x03);
mipi_dsi_dcs_write_seq_multi(ctx, 0x09, 0x80);
mipi_dsi_dcs_write_seq_multi(ctx, 0x0a, 0x00);
mipi_dsi_dcs_write_seq_multi(ctx, 0x0b, 0x00);
mipi_dsi_dcs_write_seq_multi(ctx, 0x0c, 0x01);
mipi_dsi_dcs_write_seq_multi(ctx, 0x0d, 0x01);
mipi_dsi_dcs_write_seq_multi(ctx, 0x0e, 0x00);
mipi_dsi_dcs_write_seq_multi(ctx, 0x0f, 0x00);
mipi_dsi_dcs_write_seq_multi(ctx, 0x10, 0x55);
mipi_dsi_dcs_write_seq_multi(ctx, 0x11, 0x50);
mipi_dsi_dcs_write_seq_multi(ctx, 0x12, 0x01);
mipi_dsi_dcs_write_seq_multi(ctx, 0x13, 0x00);
mipi_dsi_dcs_write_seq_multi(ctx, 0x14, 0x00);
mipi_dsi_dcs_write_seq_multi(ctx, 0x15, 0x43);
mipi_dsi_dcs_write_seq_multi(ctx, 0x16, 0x0b);
mipi_dsi_dcs_write_seq_multi(ctx, 0x17, 0x00);
mipi_dsi_dcs_write_seq_multi(ctx, 0x18, 0x00);
mipi_dsi_dcs_write_seq_multi(ctx, 0x19, 0x10);
mipi_dsi_dcs_write_seq_multi(ctx, 0x1a, 0x00);
mipi_dsi_dcs_write_seq_multi(ctx, 0x1b, 0x00);
mipi_dsi_dcs_write_seq_multi(ctx, 0x1c, 0x00);
mipi_dsi_dcs_write_seq_multi(ctx, 0x1d, 0x00);
mipi_dsi_dcs_write_seq_multi(ctx, 0x20, 0x01);
mipi_dsi_dcs_write_seq_multi(ctx, 0x21, 0x23);
mipi_dsi_dcs_write_seq_multi(ctx, 0x22, 0x45);
mipi_dsi_dcs_write_seq_multi(ctx, 0x23, 0x67);
mipi_dsi_dcs_write_seq_multi(ctx, 0x24, 0x01);
mipi_dsi_dcs_write_seq_multi(ctx, 0x25, 0x23);
mipi_dsi_dcs_write_seq_multi(ctx, 0x26, 0x45);
mipi_dsi_dcs_write_seq_multi(ctx, 0x27, 0x67);
mipi_dsi_dcs_write_seq_multi(ctx, 0x30, 0x02);
mipi_dsi_dcs_write_seq_multi(ctx, 0x31, 0x22);
mipi_dsi_dcs_write_seq_multi(ctx, 0x32, 0x22);
mipi_dsi_dcs_write_seq_multi(ctx, 0x33, 0x88);
mipi_dsi_dcs_write_seq_multi(ctx, 0x34, 0xaa);
mipi_dsi_dcs_write_seq_multi(ctx, 0x35, 0xbb);
mipi_dsi_dcs_write_seq_multi(ctx, 0x36, 0x66);
mipi_dsi_dcs_write_seq_multi(ctx, 0x37, 0x22);
mipi_dsi_dcs_write_seq_multi(ctx, 0x38, 0x22);
mipi_dsi_dcs_write_seq_multi(ctx, 0x39, 0x22);
mipi_dsi_dcs_write_seq_multi(ctx, 0x3a, 0x22);
mipi_dsi_dcs_write_seq_multi(ctx, 0x3b, 0x22);
mipi_dsi_dcs_write_seq_multi(ctx, 0x3c, 0x22);
mipi_dsi_dcs_write_seq_multi(ctx, 0x3d, 0x22);
mipi_dsi_dcs_write_seq_multi(ctx, 0x3e, 0x22);
mipi_dsi_dcs_write_seq_multi(ctx, 0x3f, 0x22);
mipi_dsi_dcs_write_seq_multi(ctx, 0x40, 0x22);
mipi_dsi_dcs_write_seq_multi(ctx, 0x53, 0x12);
/* Switch to page 0 */
mipi_dsi_dcs_write_seq_multi(ctx, 0xff, 0xff, 0x98, 0x06, 0x04, 0x00);
/* Interface Pixel format */
mipi_dsi_dcs_write_seq_multi(ctx, 0x3a, 0x60);
};
static const struct drm_display_mode com35h3p70ulc_default_mode = {
.clock = 22400,
.hdisplay = 480,
.hsync_start = 480 + 16,
.hsync_end = 480 + 16 + 16,
.htotal = 480 + 16 + 16 + 16,
.vdisplay = 640,
.vsync_start = 640 + 52,
.vsync_end = 640 + 52 + 4,
.vtotal = 640 + 52 + 4 + 16,
.width_mm = 53,
.height_mm = 71,
};
static const struct panel_desc com35h3p70ulc_desc = {
.init_sequence = com35h3p70ulc_init,
.display_mode = &com35h3p70ulc_default_mode,
.mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
MIPI_DSI_MODE_LPM,
.format = MIPI_DSI_FMT_RGB888,
.lanes = 2,
};
static const struct of_device_id ili9806e_of_match[] = {
{ .compatible = "ortustech,com35h3p70ulc", .data = &com35h3p70ulc_desc },
{ }
};
MODULE_DEVICE_TABLE(of, ili9806e_of_match);
static struct mipi_dsi_driver ili9806e_dsi_driver = {
.driver = {
.name = "ili9806e-dsi",
.of_match_table = ili9806e_of_match,
},
.probe = ili9806e_dsi_probe,
.remove = ili9806e_dsi_remove,
};
module_mipi_dsi_driver(ili9806e_dsi_driver);
MODULE_AUTHOR("Gunnar Dibbern <gunnar.dibbern@lht.dlh.de>");
MODULE_AUTHOR("Michael Walle <mwalle@kernel.org>");
MODULE_DESCRIPTION("Ilitek ILI9806E Controller Driver");
MODULE_LICENSE("GPL");

View File

@ -0,0 +1,262 @@
// 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");

View File

@ -40,176 +40,136 @@ static void rm692e5_reset(struct rm692e5_panel *ctx)
usleep_range(10000, 11000);
}
static int rm692e5_on(struct rm692e5_panel *ctx)
static void rm692e5_on(struct mipi_dsi_multi_context *dsi_ctx)
{
struct mipi_dsi_device *dsi = ctx->dsi;
struct device *dev = &dsi->dev;
int ret;
dsi_ctx->dsi->mode_flags |= MIPI_DSI_MODE_LPM;
dsi->mode_flags |= MIPI_DSI_MODE_LPM;
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0xfe, 0x41);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0xd6, 0x00);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0xfe, 0x16);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x8a, 0x87);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0xfe, 0x71);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x82, 0x01);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0xc6, 0x00);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0xc7, 0x2c);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0xc8, 0x64);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0xc9, 0x3c);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0xca, 0x80);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0xcb, 0x02);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0xcc, 0x02);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0xfe, 0x38);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x18, 0x13);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0xfe, 0xf4);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x00, 0xff);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x01, 0xff);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x02, 0xcf);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x03, 0xbc);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x04, 0xb9);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x05, 0x99);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x06, 0x02);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x07, 0x0a);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x08, 0xe0);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x09, 0x4c);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x0a, 0xeb);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x0b, 0xe8);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x0c, 0x32);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x0d, 0x07);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0xfe, 0xf4);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x0d, 0xc0);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x0e, 0xff);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x0f, 0xff);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x10, 0x33);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x11, 0x6f);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x12, 0x6e);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x13, 0xa6);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x14, 0x80);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x15, 0x02);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x16, 0x38);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x17, 0xd3);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x18, 0x3a);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x19, 0xba);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x1a, 0xcc);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x1b, 0x01);
mipi_dsi_generic_write_seq(dsi, 0xfe, 0x41);
mipi_dsi_generic_write_seq(dsi, 0xd6, 0x00);
mipi_dsi_generic_write_seq(dsi, 0xfe, 0x16);
mipi_dsi_generic_write_seq(dsi, 0x8a, 0x87);
mipi_dsi_generic_write_seq(dsi, 0xfe, 0x71);
mipi_dsi_generic_write_seq(dsi, 0x82, 0x01);
mipi_dsi_generic_write_seq(dsi, 0xc6, 0x00);
mipi_dsi_generic_write_seq(dsi, 0xc7, 0x2c);
mipi_dsi_generic_write_seq(dsi, 0xc8, 0x64);
mipi_dsi_generic_write_seq(dsi, 0xc9, 0x3c);
mipi_dsi_generic_write_seq(dsi, 0xca, 0x80);
mipi_dsi_generic_write_seq(dsi, 0xcb, 0x02);
mipi_dsi_generic_write_seq(dsi, 0xcc, 0x02);
mipi_dsi_generic_write_seq(dsi, 0xfe, 0x38);
mipi_dsi_generic_write_seq(dsi, 0x18, 0x13);
mipi_dsi_generic_write_seq(dsi, 0xfe, 0xf4);
mipi_dsi_generic_write_seq(dsi, 0x00, 0xff);
mipi_dsi_generic_write_seq(dsi, 0x01, 0xff);
mipi_dsi_generic_write_seq(dsi, 0x02, 0xcf);
mipi_dsi_generic_write_seq(dsi, 0x03, 0xbc);
mipi_dsi_generic_write_seq(dsi, 0x04, 0xb9);
mipi_dsi_generic_write_seq(dsi, 0x05, 0x99);
mipi_dsi_generic_write_seq(dsi, 0x06, 0x02);
mipi_dsi_generic_write_seq(dsi, 0x07, 0x0a);
mipi_dsi_generic_write_seq(dsi, 0x08, 0xe0);
mipi_dsi_generic_write_seq(dsi, 0x09, 0x4c);
mipi_dsi_generic_write_seq(dsi, 0x0a, 0xeb);
mipi_dsi_generic_write_seq(dsi, 0x0b, 0xe8);
mipi_dsi_generic_write_seq(dsi, 0x0c, 0x32);
mipi_dsi_generic_write_seq(dsi, 0x0d, 0x07);
mipi_dsi_generic_write_seq(dsi, 0xfe, 0xf4);
mipi_dsi_generic_write_seq(dsi, 0x0d, 0xc0);
mipi_dsi_generic_write_seq(dsi, 0x0e, 0xff);
mipi_dsi_generic_write_seq(dsi, 0x0f, 0xff);
mipi_dsi_generic_write_seq(dsi, 0x10, 0x33);
mipi_dsi_generic_write_seq(dsi, 0x11, 0x6f);
mipi_dsi_generic_write_seq(dsi, 0x12, 0x6e);
mipi_dsi_generic_write_seq(dsi, 0x13, 0xa6);
mipi_dsi_generic_write_seq(dsi, 0x14, 0x80);
mipi_dsi_generic_write_seq(dsi, 0x15, 0x02);
mipi_dsi_generic_write_seq(dsi, 0x16, 0x38);
mipi_dsi_generic_write_seq(dsi, 0x17, 0xd3);
mipi_dsi_generic_write_seq(dsi, 0x18, 0x3a);
mipi_dsi_generic_write_seq(dsi, 0x19, 0xba);
mipi_dsi_generic_write_seq(dsi, 0x1a, 0xcc);
mipi_dsi_generic_write_seq(dsi, 0x1b, 0x01);
mipi_dsi_dcs_nop_multi(dsi_ctx);
ret = mipi_dsi_dcs_nop(dsi);
if (ret < 0) {
dev_err(dev, "Failed to nop: %d\n", ret);
return ret;
}
msleep(32);
mipi_dsi_msleep(dsi_ctx, 32);
mipi_dsi_generic_write_seq(dsi, 0xfe, 0x38);
mipi_dsi_generic_write_seq(dsi, 0x18, 0x13);
mipi_dsi_generic_write_seq(dsi, 0xfe, 0xd1);
mipi_dsi_generic_write_seq(dsi, 0xd3, 0x00);
mipi_dsi_generic_write_seq(dsi, 0xd0, 0x00);
mipi_dsi_generic_write_seq(dsi, 0xd2, 0x00);
mipi_dsi_generic_write_seq(dsi, 0xd4, 0x00);
mipi_dsi_generic_write_seq(dsi, 0xb4, 0x01);
mipi_dsi_generic_write_seq(dsi, 0xfe, 0xf9);
mipi_dsi_generic_write_seq(dsi, 0x00, 0xaf);
mipi_dsi_generic_write_seq(dsi, 0x1d, 0x37);
mipi_dsi_generic_write_seq(dsi, 0x44, 0x0a, 0x7b);
mipi_dsi_generic_write_seq(dsi, 0xfe, 0x00);
mipi_dsi_generic_write_seq(dsi, 0xfa, 0x01);
mipi_dsi_generic_write_seq(dsi, 0xc2, 0x08);
mipi_dsi_generic_write_seq(dsi, 0x35, 0x00);
mipi_dsi_generic_write_seq(dsi, 0x51, 0x05, 0x42);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0xfe, 0x38);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x18, 0x13);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0xfe, 0xd1);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0xd3, 0x00);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0xd0, 0x00);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0xd2, 0x00);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0xd4, 0x00);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0xb4, 0x01);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0xfe, 0xf9);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x00, 0xaf);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x1d, 0x37);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x44, 0x0a, 0x7b);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0xfe, 0x00);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0xfa, 0x01);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0xc2, 0x08);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x35, 0x00);
mipi_dsi_generic_write_seq_multi(dsi_ctx, 0x51, 0x05, 0x42);
ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
if (ret < 0) {
dev_err(dev, "Failed to exit sleep mode: %d\n", ret);
return ret;
}
msleep(100);
ret = mipi_dsi_dcs_set_display_on(dsi);
if (ret < 0) {
dev_err(dev, "Failed to set display on: %d\n", ret);
return ret;
}
return 0;
mipi_dsi_dcs_exit_sleep_mode_multi(dsi_ctx);
mipi_dsi_msleep(dsi_ctx, 100);
mipi_dsi_dcs_set_display_on_multi(dsi_ctx);
}
static int rm692e5_disable(struct drm_panel *panel)
{
struct rm692e5_panel *ctx = to_rm692e5_panel(panel);
struct mipi_dsi_device *dsi = ctx->dsi;
struct device *dev = &dsi->dev;
int ret;
struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi };
dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
mipi_dsi_generic_write_seq(dsi, 0xfe, 0x00);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfe, 0x00);
ret = mipi_dsi_dcs_set_display_off(dsi);
if (ret < 0) {
dev_err(dev, "Failed to set display off: %d\n", ret);
return ret;
}
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;
}
msleep(100);
mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx);
return 0;
mipi_dsi_msleep(&dsi_ctx, 100);
return dsi_ctx.accum_err;
}
static int rm692e5_prepare(struct drm_panel *panel)
{
struct rm692e5_panel *ctx = to_rm692e5_panel(panel);
struct drm_dsc_picture_parameter_set pps;
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;
rm692e5_reset(ctx);
ret = rm692e5_on(ctx);
if (ret < 0) {
dev_err(dev, "Failed to initialize panel: %d\n", ret);
gpiod_set_value_cansleep(ctx->reset_gpio, 1);
regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
return ret;
}
rm692e5_on(&dsi_ctx);
drm_dsc_pps_payload_pack(&pps, &ctx->dsc);
ret = mipi_dsi_picture_parameter_set(ctx->dsi, &pps);
if (ret < 0) {
dev_err(panel->dev, "failed to transmit PPS: %d\n", ret);
return ret;
}
mipi_dsi_picture_parameter_set_multi(&dsi_ctx, &pps);
mipi_dsi_compression_mode_ext_multi(&dsi_ctx, true, MIPI_DSI_COMPRESSION_DSC, 0);
mipi_dsi_msleep(&dsi_ctx, 28);
ret = mipi_dsi_compression_mode(ctx->dsi, true);
if (ret < 0) {
dev_err(dev, "failed to enable compression mode: %d\n", ret);
return ret;
}
msleep(28);
mipi_dsi_generic_write_seq(ctx->dsi, 0xfe, 0x40);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfe, 0x40);
/* 0x05 -> 90Hz, 0x00 -> 60Hz */
mipi_dsi_generic_write_seq(ctx->dsi, 0xbd, 0x05);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xbd, 0x05);
mipi_dsi_generic_write_seq(ctx->dsi, 0xfe, 0x00);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xfe, 0x00);
return 0;
if (dsi_ctx.accum_err) {
gpiod_set_value_cansleep(ctx->reset_gpio, 1);
regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
}
return dsi_ctx.accum_err;
}
static int rm692e5_unprepare(struct drm_panel *panel)

View File

@ -69,7 +69,7 @@ struct st7703_panel_desc {
unsigned int lanes;
unsigned long mode_flags;
enum mipi_dsi_pixel_format format;
int (*init_sequence)(struct st7703 *ctx);
void (*init_sequence)(struct mipi_dsi_multi_context *dsi_ctx);
};
static inline struct st7703 *panel_to_st7703(struct drm_panel *panel)
@ -77,62 +77,58 @@ static inline struct st7703 *panel_to_st7703(struct drm_panel *panel)
return container_of(panel, struct st7703, panel);
}
static int jh057n_init_sequence(struct st7703 *ctx)
static void jh057n_init_sequence(struct mipi_dsi_multi_context *dsi_ctx)
{
struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
/*
* Init sequence was supplied by the panel vendor. Most of the commands
* resemble the ST7703 but the number of parameters often don't match
* so it's likely a clone.
*/
mipi_dsi_generic_write_seq(dsi, ST7703_CMD_SETEXTC,
0xF1, 0x12, 0x83);
mipi_dsi_generic_write_seq(dsi, ST7703_CMD_SETRGBIF,
0x10, 0x10, 0x05, 0x05, 0x03, 0xFF, 0x00, 0x00,
0x00, 0x00);
mipi_dsi_generic_write_seq(dsi, ST7703_CMD_SETSCR,
0x73, 0x73, 0x50, 0x50, 0x00, 0x00, 0x08, 0x70,
0x00);
mipi_dsi_generic_write_seq(dsi, ST7703_CMD_SETVDC, 0x4E);
mipi_dsi_generic_write_seq(dsi, ST7703_CMD_SETPANEL, 0x0B);
mipi_dsi_generic_write_seq(dsi, ST7703_CMD_SETCYC, 0x80);
mipi_dsi_generic_write_seq(dsi, ST7703_CMD_SETDISP, 0xF0, 0x12, 0x30);
mipi_dsi_generic_write_seq(dsi, ST7703_CMD_SETEQ,
0x07, 0x07, 0x0B, 0x0B, 0x03, 0x0B, 0x00, 0x00,
0x00, 0x00, 0xFF, 0x00, 0xC0, 0x10);
mipi_dsi_generic_write_seq(dsi, ST7703_CMD_SETBGP, 0x08, 0x08);
msleep(20);
mipi_dsi_generic_write_seq_multi(dsi_ctx, ST7703_CMD_SETEXTC,
0xF1, 0x12, 0x83);
mipi_dsi_generic_write_seq_multi(dsi_ctx, ST7703_CMD_SETRGBIF,
0x10, 0x10, 0x05, 0x05, 0x03, 0xFF, 0x00, 0x00,
0x00, 0x00);
mipi_dsi_generic_write_seq_multi(dsi_ctx, ST7703_CMD_SETSCR,
0x73, 0x73, 0x50, 0x50, 0x00, 0x00, 0x08, 0x70,
0x00);
mipi_dsi_generic_write_seq_multi(dsi_ctx, ST7703_CMD_SETVDC, 0x4E);
mipi_dsi_generic_write_seq_multi(dsi_ctx, ST7703_CMD_SETPANEL, 0x0B);
mipi_dsi_generic_write_seq_multi(dsi_ctx, ST7703_CMD_SETCYC, 0x80);
mipi_dsi_generic_write_seq_multi(dsi_ctx, ST7703_CMD_SETDISP, 0xF0, 0x12, 0x30);
mipi_dsi_generic_write_seq_multi(dsi_ctx, ST7703_CMD_SETEQ,
0x07, 0x07, 0x0B, 0x0B, 0x03, 0x0B, 0x00, 0x00,
0x00, 0x00, 0xFF, 0x00, 0xC0, 0x10);
mipi_dsi_generic_write_seq_multi(dsi_ctx, ST7703_CMD_SETBGP, 0x08, 0x08);
mipi_dsi_msleep(dsi_ctx, 20);
mipi_dsi_generic_write_seq(dsi, ST7703_CMD_SETVCOM, 0x3F, 0x3F);
mipi_dsi_generic_write_seq(dsi, ST7703_CMD_UNKNOWN_BF, 0x02, 0x11, 0x00);
mipi_dsi_generic_write_seq(dsi, ST7703_CMD_SETGIP1,
0x82, 0x10, 0x06, 0x05, 0x9E, 0x0A, 0xA5, 0x12,
0x31, 0x23, 0x37, 0x83, 0x04, 0xBC, 0x27, 0x38,
0x0C, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0C, 0x00,
0x03, 0x00, 0x00, 0x00, 0x75, 0x75, 0x31, 0x88,
0x88, 0x88, 0x88, 0x88, 0x88, 0x13, 0x88, 0x64,
0x64, 0x20, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
0x02, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
mipi_dsi_generic_write_seq(dsi, ST7703_CMD_SETGIP2,
0x02, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x02, 0x46, 0x02, 0x88,
0x88, 0x88, 0x88, 0x88, 0x88, 0x64, 0x88, 0x13,
0x57, 0x13, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
0x75, 0x88, 0x23, 0x14, 0x00, 0x00, 0x02, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x0A,
0xA5, 0x00, 0x00, 0x00, 0x00);
mipi_dsi_generic_write_seq(dsi, ST7703_CMD_SETGAMMA,
0x00, 0x09, 0x0E, 0x29, 0x2D, 0x3C, 0x41, 0x37,
0x07, 0x0B, 0x0D, 0x10, 0x11, 0x0F, 0x10, 0x11,
0x18, 0x00, 0x09, 0x0E, 0x29, 0x2D, 0x3C, 0x41,
0x37, 0x07, 0x0B, 0x0D, 0x10, 0x11, 0x0F, 0x10,
0x11, 0x18);
msleep(20);
return 0;
mipi_dsi_generic_write_seq_multi(dsi_ctx, ST7703_CMD_SETVCOM, 0x3F, 0x3F);
mipi_dsi_generic_write_seq_multi(dsi_ctx, ST7703_CMD_UNKNOWN_BF, 0x02, 0x11, 0x00);
mipi_dsi_generic_write_seq_multi(dsi_ctx, ST7703_CMD_SETGIP1,
0x82, 0x10, 0x06, 0x05, 0x9E, 0x0A, 0xA5, 0x12,
0x31, 0x23, 0x37, 0x83, 0x04, 0xBC, 0x27, 0x38,
0x0C, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0C, 0x00,
0x03, 0x00, 0x00, 0x00, 0x75, 0x75, 0x31, 0x88,
0x88, 0x88, 0x88, 0x88, 0x88, 0x13, 0x88, 0x64,
0x64, 0x20, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
0x02, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
mipi_dsi_generic_write_seq_multi(dsi_ctx, ST7703_CMD_SETGIP2,
0x02, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x02, 0x46, 0x02, 0x88,
0x88, 0x88, 0x88, 0x88, 0x88, 0x64, 0x88, 0x13,
0x57, 0x13, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
0x75, 0x88, 0x23, 0x14, 0x00, 0x00, 0x02, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x0A,
0xA5, 0x00, 0x00, 0x00, 0x00);
mipi_dsi_generic_write_seq_multi(dsi_ctx, ST7703_CMD_SETGAMMA,
0x00, 0x09, 0x0E, 0x29, 0x2D, 0x3C, 0x41, 0x37,
0x07, 0x0B, 0x0D, 0x10, 0x11, 0x0F, 0x10, 0x11,
0x18, 0x00, 0x09, 0x0E, 0x29, 0x2D, 0x3C, 0x41,
0x37, 0x07, 0x0B, 0x0D, 0x10, 0x11, 0x0F, 0x10,
0x11, 0x18);
mipi_dsi_msleep(dsi_ctx, 20);
}
static const struct drm_display_mode jh057n00900_mode = {
@ -159,163 +155,159 @@ static const struct st7703_panel_desc jh057n00900_panel_desc = {
.init_sequence = jh057n_init_sequence,
};
static int xbd599_init_sequence(struct st7703 *ctx)
static void xbd599_init_sequence(struct mipi_dsi_multi_context *dsi_ctx)
{
struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
/*
* Init sequence was supplied by the panel vendor.
*/
/* Magic sequence to unlock user commands below. */
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETEXTC, 0xF1, 0x12, 0x83);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETEXTC, 0xF1, 0x12, 0x83);
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETMIPI,
0x33, /* VC_main = 0, Lane_Number = 3 (4 lanes) */
0x81, /* DSI_LDO_SEL = 1.7V, RTERM = 90 Ohm */
0x05, /* IHSRX = x6 (Low High Speed driving ability) */
0xF9, /* TX_CLK_SEL = fDSICLK/16 */
0x0E, /* HFP_OSC (min. HFP number in DSI mode) */
0x0E, /* HBP_OSC (min. HBP number in DSI mode) */
/* The rest is undocumented in ST7703 datasheet */
0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x44, 0x25, 0x00, 0x91, 0x0a, 0x00, 0x00, 0x02,
0x4F, 0x11, 0x00, 0x00, 0x37);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETMIPI,
0x33, /* VC_main = 0, Lane_Number = 3 (4 lanes) */
0x81, /* DSI_LDO_SEL = 1.7V, RTERM = 90 Ohm */
0x05, /* IHSRX = x6 (Low High Speed driving ability) */
0xF9, /* TX_CLK_SEL = fDSICLK/16 */
0x0E, /* HFP_OSC (min. HFP number in DSI mode) */
0x0E, /* HBP_OSC (min. HBP number in DSI mode) */
/* The rest is undocumented in ST7703 datasheet */
0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x44, 0x25, 0x00, 0x91, 0x0a, 0x00, 0x00, 0x02,
0x4F, 0x11, 0x00, 0x00, 0x37);
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETPOWER_EXT,
0x25, /* PCCS = 2, ECP_DC_DIV = 1/4 HSYNC */
0x22, /* DT = 15ms XDK_ECP = x2 */
0x20, /* PFM_DC_DIV = /1 */
0x03 /* ECP_SYNC_EN = 1, VGX_SYNC_EN = 1 */);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETPOWER_EXT,
0x25, /* PCCS = 2, ECP_DC_DIV = 1/4 HSYNC */
0x22, /* DT = 15ms XDK_ECP = x2 */
0x20, /* PFM_DC_DIV = /1 */
0x03 /* ECP_SYNC_EN = 1, VGX_SYNC_EN = 1 */);
/* RGB I/F porch timing */
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETRGBIF,
0x10, /* VBP_RGB_GEN */
0x10, /* VFP_RGB_GEN */
0x05, /* DE_BP_RGB_GEN */
0x05, /* DE_FP_RGB_GEN */
/* The rest is undocumented in ST7703 datasheet */
0x03, 0xFF,
0x00, 0x00,
0x00, 0x00);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETRGBIF,
0x10, /* VBP_RGB_GEN */
0x10, /* VFP_RGB_GEN */
0x05, /* DE_BP_RGB_GEN */
0x05, /* DE_FP_RGB_GEN */
/* The rest is undocumented in ST7703 datasheet */
0x03, 0xFF,
0x00, 0x00,
0x00, 0x00);
/* Source driving settings. */
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETSCR,
0x73, /* N_POPON */
0x73, /* N_NOPON */
0x50, /* I_POPON */
0x50, /* I_NOPON */
0x00, /* SCR[31,24] */
0xC0, /* SCR[23,16] */
0x08, /* SCR[15,8] */
0x70, /* SCR[7,0] */
0x00 /* Undocumented */);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETSCR,
0x73, /* N_POPON */
0x73, /* N_NOPON */
0x50, /* I_POPON */
0x50, /* I_NOPON */
0x00, /* SCR[31,24] */
0xC0, /* SCR[23,16] */
0x08, /* SCR[15,8] */
0x70, /* SCR[7,0] */
0x00 /* Undocumented */);
/* NVDDD_SEL = -1.8V, VDDD_SEL = out of range (possibly 1.9V?) */
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETVDC, 0x4E);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETVDC, 0x4E);
/*
* SS_PANEL = 1 (reverse scan), GS_PANEL = 0 (normal scan)
* REV_PANEL = 1 (normally black panel), BGR_PANEL = 1 (BGR)
*/
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETPANEL, 0x0B);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETPANEL, 0x0B);
/* Zig-Zag Type C column inversion. */
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETCYC, 0x80);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETCYC, 0x80);
/* Set display resolution. */
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETDISP,
0xF0, /* NL = 240 */
0x12, /* RES_V_LSB = 0, BLK_CON = VSSD,
* RESO_SEL = 720RGB
*/
0xF0 /* WHITE_GND_EN = 1 (GND),
* WHITE_FRAME_SEL = 7 frames,
* ISC = 0 frames
*/);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETDISP,
0xF0, /* NL = 240 */
0x12, /* RES_V_LSB = 0, BLK_CON = VSSD,
* RESO_SEL = 720RGB
*/
0xF0 /* WHITE_GND_EN = 1 (GND),
* WHITE_FRAME_SEL = 7 frames,
* ISC = 0 frames
*/);
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETEQ,
0x00, /* PNOEQ */
0x00, /* NNOEQ */
0x0B, /* PEQGND */
0x0B, /* NEQGND */
0x10, /* PEQVCI */
0x10, /* NEQVCI */
0x00, /* PEQVCI1 */
0x00, /* NEQVCI1 */
0x00, /* reserved */
0x00, /* reserved */
0xFF, /* reserved */
0x00, /* reserved */
0xC0, /* ESD_DET_DATA_WHITE = 1, ESD_WHITE_EN = 1 */
0x10 /* SLPIN_OPTION = 1 (no need vsync after sleep-in)
* VEDIO_NO_CHECK_EN = 0
* ESD_WHITE_GND_EN = 0
* ESD_DET_TIME_SEL = 0 frames
*/);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETEQ,
0x00, /* PNOEQ */
0x00, /* NNOEQ */
0x0B, /* PEQGND */
0x0B, /* NEQGND */
0x10, /* PEQVCI */
0x10, /* NEQVCI */
0x00, /* PEQVCI1 */
0x00, /* NEQVCI1 */
0x00, /* reserved */
0x00, /* reserved */
0xFF, /* reserved */
0x00, /* reserved */
0xC0, /* ESD_DET_DATA_WHITE = 1, ESD_WHITE_EN = 1 */
0x10 /* SLPIN_OPTION = 1 (no need vsync after sleep-in)
* VEDIO_NO_CHECK_EN = 0
* ESD_WHITE_GND_EN = 0
* ESD_DET_TIME_SEL = 0 frames
*/);
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETECO, 0x01, 0x00, 0xFF, 0xFF, 0x00);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETECO, 0x01, 0x00, 0xFF, 0xFF, 0x00);
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETPOWER,
0x74, /* VBTHS, VBTLS: VGH = 17V, VBL = -11V */
0x00, /* FBOFF_VGH = 0, FBOFF_VGL = 0 */
0x32, /* VRP */
0x32, /* VRN */
0x77, /* reserved */
0xF1, /* APS = 1 (small),
* VGL_DET_EN = 1, VGH_DET_EN = 1,
* VGL_TURBO = 1, VGH_TURBO = 1
*/
0xFF, /* VGH1_L_DIV, VGL1_L_DIV (1.5MHz) */
0xFF, /* VGH1_R_DIV, VGL1_R_DIV (1.5MHz) */
0xCC, /* VGH2_L_DIV, VGL2_L_DIV (2.6MHz) */
0xCC, /* VGH2_R_DIV, VGL2_R_DIV (2.6MHz) */
0x77, /* VGH3_L_DIV, VGL3_L_DIV (4.5MHz) */
0x77 /* VGH3_R_DIV, VGL3_R_DIV (4.5MHz) */);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETPOWER,
0x74, /* VBTHS, VBTLS: VGH = 17V, VBL = -11V */
0x00, /* FBOFF_VGH = 0, FBOFF_VGL = 0 */
0x32, /* VRP */
0x32, /* VRN */
0x77, /* reserved */
0xF1, /* APS = 1 (small),
* VGL_DET_EN = 1, VGH_DET_EN = 1,
* VGL_TURBO = 1, VGH_TURBO = 1
*/
0xFF, /* VGH1_L_DIV, VGL1_L_DIV (1.5MHz) */
0xFF, /* VGH1_R_DIV, VGL1_R_DIV (1.5MHz) */
0xCC, /* VGH2_L_DIV, VGL2_L_DIV (2.6MHz) */
0xCC, /* VGH2_R_DIV, VGL2_R_DIV (2.6MHz) */
0x77, /* VGH3_L_DIV, VGL3_L_DIV (4.5MHz) */
0x77 /* VGH3_R_DIV, VGL3_R_DIV (4.5MHz) */);
/* Reference voltage. */
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETBGP,
0x07, /* VREF_SEL = 4.2V */
0x07 /* NVREF_SEL = 4.2V */);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETBGP,
0x07, /* VREF_SEL = 4.2V */
0x07 /* NVREF_SEL = 4.2V */);
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETVCOM,
0x2C, /* VCOMDC_F = -0.67V */
0x2C /* VCOMDC_B = -0.67V */);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETVCOM,
0x2C, /* VCOMDC_F = -0.67V */
0x2C /* VCOMDC_B = -0.67V */);
/* Undocumented command. */
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_UNKNOWN_BF, 0x02, 0x11, 0x00);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_UNKNOWN_BF, 0x02, 0x11, 0x00);
/* This command is to set forward GIP timing. */
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETGIP1,
0x82, 0x10, 0x06, 0x05, 0xA2, 0x0A, 0xA5, 0x12,
0x31, 0x23, 0x37, 0x83, 0x04, 0xBC, 0x27, 0x38,
0x0C, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0C, 0x00,
0x03, 0x00, 0x00, 0x00, 0x75, 0x75, 0x31, 0x88,
0x88, 0x88, 0x88, 0x88, 0x88, 0x13, 0x88, 0x64,
0x64, 0x20, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
0x02, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETGIP1,
0x82, 0x10, 0x06, 0x05, 0xA2, 0x0A, 0xA5, 0x12,
0x31, 0x23, 0x37, 0x83, 0x04, 0xBC, 0x27, 0x38,
0x0C, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0C, 0x00,
0x03, 0x00, 0x00, 0x00, 0x75, 0x75, 0x31, 0x88,
0x88, 0x88, 0x88, 0x88, 0x88, 0x13, 0x88, 0x64,
0x64, 0x20, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
0x02, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
/* This command is to set backward GIP timing. */
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETGIP2,
0x02, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x02, 0x46, 0x02, 0x88,
0x88, 0x88, 0x88, 0x88, 0x88, 0x64, 0x88, 0x13,
0x57, 0x13, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
0x75, 0x88, 0x23, 0x14, 0x00, 0x00, 0x02, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0A,
0xA5, 0x00, 0x00, 0x00, 0x00);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETGIP2,
0x02, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x02, 0x46, 0x02, 0x88,
0x88, 0x88, 0x88, 0x88, 0x88, 0x64, 0x88, 0x13,
0x57, 0x13, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
0x75, 0x88, 0x23, 0x14, 0x00, 0x00, 0x02, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0A,
0xA5, 0x00, 0x00, 0x00, 0x00);
/* Adjust the gamma characteristics of the panel. */
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETGAMMA,
0x00, 0x09, 0x0D, 0x23, 0x27, 0x3C, 0x41, 0x35,
0x07, 0x0D, 0x0E, 0x12, 0x13, 0x10, 0x12, 0x12,
0x18, 0x00, 0x09, 0x0D, 0x23, 0x27, 0x3C, 0x41,
0x35, 0x07, 0x0D, 0x0E, 0x12, 0x13, 0x10, 0x12,
0x12, 0x18);
return 0;
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETGAMMA,
0x00, 0x09, 0x0D, 0x23, 0x27, 0x3C, 0x41, 0x35,
0x07, 0x0D, 0x0E, 0x12, 0x13, 0x10, 0x12, 0x12,
0x18, 0x00, 0x09, 0x0D, 0x23, 0x27, 0x3C, 0x41,
0x35, 0x07, 0x0D, 0x0E, 0x12, 0x13, 0x10, 0x12,
0x12, 0x18);
}
static const struct drm_display_mode xbd599_mode = {
@ -341,72 +333,68 @@ static const struct st7703_panel_desc xbd599_desc = {
.init_sequence = xbd599_init_sequence,
};
static int rg353v2_init_sequence(struct st7703 *ctx)
static void rg353v2_init_sequence(struct mipi_dsi_multi_context *dsi_ctx)
{
struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
/*
* Init sequence was supplied by the panel vendor.
*/
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETEXTC, 0xf1, 0x12, 0x83);
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETAPID, 0x00, 0x00, 0x00,
0xda, 0x80);
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETDISP, 0x00, 0x13, 0x70);
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETRGBIF, 0x10, 0x10, 0x28,
0x28, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00);
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETCYC, 0x80);
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETBGP, 0x0a, 0x0a);
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETVCOM, 0x92, 0x92);
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETPOWER_EXT, 0x25, 0x22,
0xf0, 0x63);
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETMIPI, 0x33, 0x81, 0x05,
0xf9, 0x0e, 0x0e, 0x20, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x44, 0x25, 0x00, 0x90, 0x0a,
0x00, 0x00, 0x01, 0x4f, 0x01, 0x00, 0x00, 0x37);
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETVDC, 0x47);
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_UNKNOWN_BF, 0x02, 0x11, 0x00);
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETSCR, 0x73, 0x73, 0x50, 0x50,
0x00, 0x00, 0x12, 0x50, 0x00);
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETPOWER, 0x53, 0xc0, 0x32,
0x32, 0x77, 0xe1, 0xdd, 0xdd, 0x77, 0x77, 0x33,
0x33);
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETECO, 0x82, 0x00, 0xbf, 0xff,
0x00, 0xff);
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETIO, 0xb8, 0x00, 0x0a, 0x00,
0x00, 0x00);
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETCABC, 0x10, 0x40, 0x1e,
0x02);
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETPANEL, 0x0b);
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETGAMMA, 0x00, 0x07, 0x0d,
0x37, 0x35, 0x3f, 0x41, 0x44, 0x06, 0x0c, 0x0d,
0x0f, 0x11, 0x10, 0x12, 0x14, 0x1a, 0x00, 0x07,
0x0d, 0x37, 0x35, 0x3f, 0x41, 0x44, 0x06, 0x0c,
0x0d, 0x0f, 0x11, 0x10, 0x12, 0x14, 0x1a);
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETEQ, 0x07, 0x07, 0x0b, 0x0b,
0x0b, 0x0b, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
0xc0, 0x10);
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETGIP1, 0xc8, 0x10, 0x02, 0x00,
0x00, 0xb0, 0xb1, 0x11, 0x31, 0x23, 0x28, 0x80,
0xb0, 0xb1, 0x27, 0x08, 0x00, 0x04, 0x02, 0x00,
0x00, 0x00, 0x00, 0x04, 0x02, 0x00, 0x00, 0x00,
0x88, 0x88, 0xba, 0x60, 0x24, 0x08, 0x88, 0x88,
0x88, 0x88, 0x88, 0x88, 0x88, 0xba, 0x71, 0x35,
0x18, 0x88, 0x88, 0x88, 0x88, 0x88, 0x00, 0x00,
0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00);
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETGIP2, 0x97, 0x0a, 0x82, 0x02,
0x03, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x81, 0x88, 0xba, 0x17, 0x53, 0x88, 0x88, 0x88,
0x88, 0x88, 0x88, 0x80, 0x88, 0xba, 0x06, 0x42,
0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x23, 0x00,
0x00, 0x02, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00);
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_UNKNOWN_EF, 0xff, 0xff, 0x01);
return 0;
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETEXTC, 0xf1, 0x12, 0x83);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETAPID, 0x00, 0x00, 0x00,
0xda, 0x80);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETDISP, 0x00, 0x13, 0x70);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETRGBIF, 0x10, 0x10, 0x28,
0x28, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETCYC, 0x80);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETBGP, 0x0a, 0x0a);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETVCOM, 0x92, 0x92);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETPOWER_EXT, 0x25, 0x22,
0xf0, 0x63);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETMIPI, 0x33, 0x81, 0x05,
0xf9, 0x0e, 0x0e, 0x20, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x44, 0x25, 0x00, 0x90, 0x0a,
0x00, 0x00, 0x01, 0x4f, 0x01, 0x00, 0x00, 0x37);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETVDC, 0x47);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_UNKNOWN_BF, 0x02, 0x11, 0x00);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETSCR, 0x73, 0x73, 0x50, 0x50,
0x00, 0x00, 0x12, 0x50, 0x00);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETPOWER, 0x53, 0xc0, 0x32,
0x32, 0x77, 0xe1, 0xdd, 0xdd, 0x77, 0x77, 0x33,
0x33);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETECO, 0x82, 0x00, 0xbf, 0xff,
0x00, 0xff);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETIO, 0xb8, 0x00, 0x0a, 0x00,
0x00, 0x00);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETCABC, 0x10, 0x40, 0x1e,
0x02);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETPANEL, 0x0b);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETGAMMA, 0x00, 0x07, 0x0d,
0x37, 0x35, 0x3f, 0x41, 0x44, 0x06, 0x0c, 0x0d,
0x0f, 0x11, 0x10, 0x12, 0x14, 0x1a, 0x00, 0x07,
0x0d, 0x37, 0x35, 0x3f, 0x41, 0x44, 0x06, 0x0c,
0x0d, 0x0f, 0x11, 0x10, 0x12, 0x14, 0x1a);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETEQ, 0x07, 0x07, 0x0b, 0x0b,
0x0b, 0x0b, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
0xc0, 0x10);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETGIP1, 0xc8, 0x10, 0x02, 0x00,
0x00, 0xb0, 0xb1, 0x11, 0x31, 0x23, 0x28, 0x80,
0xb0, 0xb1, 0x27, 0x08, 0x00, 0x04, 0x02, 0x00,
0x00, 0x00, 0x00, 0x04, 0x02, 0x00, 0x00, 0x00,
0x88, 0x88, 0xba, 0x60, 0x24, 0x08, 0x88, 0x88,
0x88, 0x88, 0x88, 0x88, 0x88, 0xba, 0x71, 0x35,
0x18, 0x88, 0x88, 0x88, 0x88, 0x88, 0x00, 0x00,
0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETGIP2, 0x97, 0x0a, 0x82, 0x02,
0x03, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x81, 0x88, 0xba, 0x17, 0x53, 0x88, 0x88, 0x88,
0x88, 0x88, 0x88, 0x80, 0x88, 0xba, 0x06, 0x42,
0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x23, 0x00,
0x00, 0x02, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_UNKNOWN_EF, 0xff, 0xff, 0x01);
}
static const struct drm_display_mode rg353v2_mode = {
@ -433,68 +421,64 @@ static const struct st7703_panel_desc rg353v2_desc = {
.init_sequence = rg353v2_init_sequence,
};
static int rgb30panel_init_sequence(struct st7703 *ctx)
static void rgb30panel_init_sequence(struct mipi_dsi_multi_context *dsi_ctx)
{
struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
/* Init sequence extracted from Powkiddy RGB30 BSP kernel. */
/*
* For some reason this specific panel must be taken out of sleep
* before the full init sequence, or else it will not display.
*/
mipi_dsi_dcs_exit_sleep_mode(dsi);
msleep(250);
mipi_dsi_dcs_exit_sleep_mode_multi(dsi_ctx);
mipi_dsi_msleep(dsi_ctx, 250);
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETEXTC, 0xf1, 0x12, 0x83);
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETMIPI, 0x33, 0x81, 0x05, 0xf9,
0x0e, 0x0e, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x44, 0x25, 0x00, 0x90, 0x0a, 0x00,
0x00, 0x01, 0x4f, 0x01, 0x00, 0x00, 0x37);
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETPOWER_EXT, 0x25, 0x22, 0xf0,
0x63);
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_UNKNOWN_BF, 0x02, 0x11, 0x00);
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETRGBIF, 0x10, 0x10, 0x28,
0x28, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00);
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETSCR, 0x73, 0x73, 0x50, 0x50,
0x00, 0x00, 0x12, 0x70, 0x00);
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETVDC, 0x46);
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETPANEL, 0x0b);
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETCYC, 0x80);
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETDISP, 0x3c, 0x12, 0x30);
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETEQ, 0x07, 0x07, 0x0b, 0x0b,
0x03, 0x0b, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
0xc0, 0x10);
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETPOWER, 0x36, 0x00, 0x32,
0x32, 0x77, 0xf1, 0xcc, 0xcc, 0x77, 0x77, 0x33,
0x33);
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETBGP, 0x0a, 0x0a);
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETVCOM, 0x88, 0x88);
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETGIP1, 0xc8, 0x10, 0x0a, 0x10,
0x0f, 0xa1, 0x80, 0x12, 0x31, 0x23, 0x47, 0x86,
0xa1, 0x80, 0x47, 0x08, 0x00, 0x00, 0x0d, 0x00,
0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,
0x48, 0x02, 0x8b, 0xaf, 0x46, 0x02, 0x88, 0x88,
0x88, 0x88, 0x88, 0x48, 0x13, 0x8b, 0xaf, 0x57,
0x13, 0x88, 0x88, 0x88, 0x88, 0x88, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00);
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETGIP2, 0x96, 0x12, 0x01, 0x01,
0x01, 0x78, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
0x4f, 0x31, 0x8b, 0xa8, 0x31, 0x75, 0x88, 0x88,
0x88, 0x88, 0x88, 0x4f, 0x20, 0x8b, 0xa8, 0x20,
0x64, 0x88, 0x88, 0x88, 0x88, 0x88, 0x23, 0x00,
0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x40, 0xa1, 0x80, 0x00, 0x00, 0x00,
0x00);
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETGAMMA, 0x00, 0x0a, 0x0f,
0x29, 0x3b, 0x3f, 0x42, 0x39, 0x06, 0x0d, 0x10,
0x13, 0x15, 0x14, 0x15, 0x10, 0x17, 0x00, 0x0a,
0x0f, 0x29, 0x3b, 0x3f, 0x42, 0x39, 0x06, 0x0d,
0x10, 0x13, 0x15, 0x14, 0x15, 0x10, 0x17);
return 0;
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETEXTC, 0xf1, 0x12, 0x83);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETMIPI, 0x33, 0x81, 0x05, 0xf9,
0x0e, 0x0e, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x44, 0x25, 0x00, 0x90, 0x0a, 0x00,
0x00, 0x01, 0x4f, 0x01, 0x00, 0x00, 0x37);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETPOWER_EXT, 0x25, 0x22, 0xf0,
0x63);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_UNKNOWN_BF, 0x02, 0x11, 0x00);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETRGBIF, 0x10, 0x10, 0x28,
0x28, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETSCR, 0x73, 0x73, 0x50, 0x50,
0x00, 0x00, 0x12, 0x70, 0x00);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETVDC, 0x46);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETPANEL, 0x0b);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETCYC, 0x80);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETDISP, 0x3c, 0x12, 0x30);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETEQ, 0x07, 0x07, 0x0b, 0x0b,
0x03, 0x0b, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
0xc0, 0x10);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETPOWER, 0x36, 0x00, 0x32,
0x32, 0x77, 0xf1, 0xcc, 0xcc, 0x77, 0x77, 0x33,
0x33);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETBGP, 0x0a, 0x0a);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETVCOM, 0x88, 0x88);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETGIP1, 0xc8, 0x10, 0x0a, 0x10,
0x0f, 0xa1, 0x80, 0x12, 0x31, 0x23, 0x47, 0x86,
0xa1, 0x80, 0x47, 0x08, 0x00, 0x00, 0x0d, 0x00,
0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,
0x48, 0x02, 0x8b, 0xaf, 0x46, 0x02, 0x88, 0x88,
0x88, 0x88, 0x88, 0x48, 0x13, 0x8b, 0xaf, 0x57,
0x13, 0x88, 0x88, 0x88, 0x88, 0x88, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETGIP2, 0x96, 0x12, 0x01, 0x01,
0x01, 0x78, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
0x4f, 0x31, 0x8b, 0xa8, 0x31, 0x75, 0x88, 0x88,
0x88, 0x88, 0x88, 0x4f, 0x20, 0x8b, 0xa8, 0x20,
0x64, 0x88, 0x88, 0x88, 0x88, 0x88, 0x23, 0x00,
0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x40, 0xa1, 0x80, 0x00, 0x00, 0x00,
0x00);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETGAMMA, 0x00, 0x0a, 0x0f,
0x29, 0x3b, 0x3f, 0x42, 0x39, 0x06, 0x0d, 0x10,
0x13, 0x15, 0x14, 0x15, 0x10, 0x17, 0x00, 0x0a,
0x0f, 0x29, 0x3b, 0x3f, 0x42, 0x39, 0x06, 0x0d,
0x10, 0x13, 0x15, 0x14, 0x15, 0x10, 0x17);
}
static const struct drm_display_mode rgb30panel_mode = {
@ -521,70 +505,66 @@ static const struct st7703_panel_desc rgb30panel_desc = {
.init_sequence = rgb30panel_init_sequence,
};
static int rgb10max3_panel_init_sequence(struct st7703 *ctx)
static void rgb10max3_panel_init_sequence(struct mipi_dsi_multi_context *dsi_ctx)
{
struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
/* Init sequence extracted from Powkiddy RGB10MAX3 BSP kernel. */
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETEXTC, 0xf1, 0x12, 0x83);
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETAPID, 0x00, 0x00, 0x00, 0xda,
0x80);
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETDISP, 0xc8, 0x02, 0x30);
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETRGBIF, 0x10, 0x10, 0x28,
0x28, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00);
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETCYC, 0x80);
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETBGP, 0x04, 0x04);
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETVCOM, 0x78, 0x78);
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETPOWER_EXT, 0x25, 0x22, 0xf0,
0x63);
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETMIPI, 0x33, 0x81, 0x05, 0xf9,
0x0e, 0x0e, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x44, 0x25, 0x00, 0x90, 0x0a, 0x00,
0x00, 0x01, 0x4f, 0x01, 0x00, 0x00, 0x37);
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETVDC, 0x47);
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_UNKNOWN_BF, 0x02, 0x11, 0x00);
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETSCR, 0x73, 0x73, 0x50, 0x50,
0x00, 0x00, 0x12, 0x70, 0x00);
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETPOWER, 0x25, 0x00, 0x32,
0x32, 0x77, 0xe1, 0xff, 0xff, 0xcc, 0xcc, 0x77,
0x77);
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETECO, 0x82, 0x00, 0xbf, 0xff,
0x00, 0xff);
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETIO, 0xb8, 0x00, 0x0a, 0x00,
0x00, 0x00);
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETCABC, 0x10, 0x40, 0x1e,
0x02);
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETPANEL, 0x0b);
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETGAMMA, 0x00, 0x04, 0x07,
0x2a, 0x39, 0x3f, 0x36, 0x31, 0x06, 0x0b, 0x0e,
0x12, 0x14, 0x12, 0x13, 0x0f, 0x17, 0x00, 0x04,
0x07, 0x2a, 0x39, 0x3f, 0x36, 0x31, 0x06, 0x0b,
0x0e, 0x12, 0x14, 0x12, 0x13, 0x0f, 0x17);
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETEQ, 0x03, 0x03, 0x03, 0x03,
0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0xff, 0x80,
0xc0, 0x10);
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETGIP1, 0xc8, 0x10, 0x08, 0x00,
0x00, 0x41, 0xf8, 0x12, 0x31, 0x23, 0x37, 0x86,
0x11, 0xc8, 0x37, 0x2a, 0x00, 0x00, 0x0c, 0x00,
0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
0x88, 0x20, 0x46, 0x02, 0x88, 0x88, 0x88, 0x88,
0x88, 0x88, 0xff, 0x88, 0x31, 0x57, 0x13, 0x88,
0x88, 0x88, 0x88, 0x88, 0x88, 0xff, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00);
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETGIP2, 0x00, 0x1a, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x8f, 0x13, 0x31, 0x75, 0x88, 0x88, 0x88, 0x88,
0x88, 0x88, 0xf8, 0x8f, 0x02, 0x20, 0x64, 0x88,
0x88, 0x88, 0x88, 0x88, 0x88, 0xf8, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00);
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_UNKNOWN_EF, 0xff, 0xff, 0x01);
return 0;
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETEXTC, 0xf1, 0x12, 0x83);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETAPID, 0x00, 0x00, 0x00, 0xda,
0x80);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETDISP, 0xc8, 0x02, 0x30);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETRGBIF, 0x10, 0x10, 0x28,
0x28, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETCYC, 0x80);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETBGP, 0x04, 0x04);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETVCOM, 0x78, 0x78);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETPOWER_EXT, 0x25, 0x22, 0xf0,
0x63);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETMIPI, 0x33, 0x81, 0x05, 0xf9,
0x0e, 0x0e, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x44, 0x25, 0x00, 0x90, 0x0a, 0x00,
0x00, 0x01, 0x4f, 0x01, 0x00, 0x00, 0x37);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETVDC, 0x47);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_UNKNOWN_BF, 0x02, 0x11, 0x00);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETSCR, 0x73, 0x73, 0x50, 0x50,
0x00, 0x00, 0x12, 0x70, 0x00);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETPOWER, 0x25, 0x00, 0x32,
0x32, 0x77, 0xe1, 0xff, 0xff, 0xcc, 0xcc, 0x77,
0x77);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETECO, 0x82, 0x00, 0xbf, 0xff,
0x00, 0xff);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETIO, 0xb8, 0x00, 0x0a, 0x00,
0x00, 0x00);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETCABC, 0x10, 0x40, 0x1e,
0x02);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETPANEL, 0x0b);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETGAMMA, 0x00, 0x04, 0x07,
0x2a, 0x39, 0x3f, 0x36, 0x31, 0x06, 0x0b, 0x0e,
0x12, 0x14, 0x12, 0x13, 0x0f, 0x17, 0x00, 0x04,
0x07, 0x2a, 0x39, 0x3f, 0x36, 0x31, 0x06, 0x0b,
0x0e, 0x12, 0x14, 0x12, 0x13, 0x0f, 0x17);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETEQ, 0x03, 0x03, 0x03, 0x03,
0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0xff, 0x80,
0xc0, 0x10);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETGIP1, 0xc8, 0x10, 0x08, 0x00,
0x00, 0x41, 0xf8, 0x12, 0x31, 0x23, 0x37, 0x86,
0x11, 0xc8, 0x37, 0x2a, 0x00, 0x00, 0x0c, 0x00,
0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
0x88, 0x20, 0x46, 0x02, 0x88, 0x88, 0x88, 0x88,
0x88, 0x88, 0xff, 0x88, 0x31, 0x57, 0x13, 0x88,
0x88, 0x88, 0x88, 0x88, 0x88, 0xff, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETGIP2, 0x00, 0x1a, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x8f, 0x13, 0x31, 0x75, 0x88, 0x88, 0x88, 0x88,
0x88, 0x88, 0xf8, 0x8f, 0x02, 0x20, 0x64, 0x88,
0x88, 0x88, 0x88, 0x88, 0x88, 0xf8, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_UNKNOWN_EF, 0xff, 0xff, 0x01);
}
static const struct drm_display_mode rgb10max3_panel_mode = {
@ -611,66 +591,62 @@ static const struct st7703_panel_desc rgb10max3_panel_desc = {
.init_sequence = rgb10max3_panel_init_sequence,
};
static int gameforcechi_init_sequence(struct st7703 *ctx)
static void gameforcechi_init_sequence(struct mipi_dsi_multi_context *dsi_ctx)
{
struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
/*
* Init sequence was supplied by the panel vendor. Panel will not
* respond to commands until it is brought out of sleep mode first.
*/
mipi_dsi_dcs_exit_sleep_mode(dsi);
msleep(250);
mipi_dsi_dcs_exit_sleep_mode_multi(dsi_ctx);
mipi_dsi_msleep(dsi_ctx, 250);
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETEXTC, 0xf1, 0x12, 0x83);
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETMIPI, 0x31, 0x81, 0x05, 0xf9,
0x0e, 0x0e, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x44, 0x25, 0x00, 0x91, 0x0a, 0x00,
0x00, 0x02, 0x4f, 0xd1, 0x00, 0x00, 0x37);
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETPOWER_EXT, 0x25);
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_UNKNOWN_BF, 0x02, 0x11, 0x00);
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETRGBIF, 0x0c, 0x10, 0x0a,
0x50, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00);
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETSCR, 0x73, 0x73, 0x50, 0x50,
0x00, 0x00, 0x08, 0x70, 0x00);
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETVDC, 0x46);
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETPANEL, 0x0b);
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETCYC, 0x80);
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETDISP, 0x00, 0x13, 0xf0);
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETEQ, 0x07, 0x07, 0x0b, 0x0b,
0x03, 0x0b, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
0xc0, 0x10);
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETPOWER, 0x53, 0x00, 0x1e,
0x1e, 0x77, 0xe1, 0xcc, 0xdd, 0x67, 0x77, 0x33,
0x33);
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETBGP, 0x10, 0x10);
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETVCOM, 0x6c, 0x7c);
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETGIP1, 0x08, 0x00, 0x0e, 0x00,
0x00, 0xb0, 0xb1, 0x11, 0x31, 0x23, 0x28, 0x10,
0xb0, 0xb1, 0x27, 0x08, 0x00, 0x04, 0x02, 0x00,
0x00, 0x00, 0x00, 0x04, 0x02, 0x00, 0x00, 0x00,
0x88, 0x88, 0xba, 0x60, 0x24, 0x08, 0x88, 0x88,
0x88, 0x88, 0x88, 0x88, 0x88, 0xba, 0x71, 0x35,
0x18, 0x88, 0x88, 0x88, 0x88, 0x88, 0x00, 0x00,
0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00);
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETGIP2, 0x97, 0x0a, 0x82, 0x02,
0x13, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0x88, 0xba, 0x17, 0x53, 0x88, 0x88, 0x88,
0x88, 0x88, 0x88, 0x81, 0x88, 0xba, 0x06, 0x42,
0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x23, 0x10,
0x00, 0x02, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00);
mipi_dsi_dcs_write_seq(dsi, ST7703_CMD_SETGAMMA, 0x00, 0x07, 0x0b,
0x27, 0x2d, 0x3f, 0x3b, 0x37, 0x05, 0x0a, 0x0b,
0x0f, 0x11, 0x0f, 0x12, 0x12, 0x18, 0x00, 0x07,
0x0b, 0x27, 0x2d, 0x3f, 0x3b, 0x37, 0x05, 0xa0,
0x0b, 0x0f, 0x11, 0x0f, 0x12, 0x12, 0x18);
return 0;
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETEXTC, 0xf1, 0x12, 0x83);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETMIPI, 0x31, 0x81, 0x05, 0xf9,
0x0e, 0x0e, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x44, 0x25, 0x00, 0x91, 0x0a, 0x00,
0x00, 0x02, 0x4f, 0xd1, 0x00, 0x00, 0x37);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETPOWER_EXT, 0x25);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_UNKNOWN_BF, 0x02, 0x11, 0x00);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETRGBIF, 0x0c, 0x10, 0x0a,
0x50, 0x03, 0xff, 0x00, 0x00, 0x00, 0x00);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETSCR, 0x73, 0x73, 0x50, 0x50,
0x00, 0x00, 0x08, 0x70, 0x00);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETVDC, 0x46);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETPANEL, 0x0b);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETCYC, 0x80);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETDISP, 0x00, 0x13, 0xf0);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETEQ, 0x07, 0x07, 0x0b, 0x0b,
0x03, 0x0b, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
0xc0, 0x10);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETPOWER, 0x53, 0x00, 0x1e,
0x1e, 0x77, 0xe1, 0xcc, 0xdd, 0x67, 0x77, 0x33,
0x33);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETBGP, 0x10, 0x10);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETVCOM, 0x6c, 0x7c);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETGIP1, 0x08, 0x00, 0x0e, 0x00,
0x00, 0xb0, 0xb1, 0x11, 0x31, 0x23, 0x28, 0x10,
0xb0, 0xb1, 0x27, 0x08, 0x00, 0x04, 0x02, 0x00,
0x00, 0x00, 0x00, 0x04, 0x02, 0x00, 0x00, 0x00,
0x88, 0x88, 0xba, 0x60, 0x24, 0x08, 0x88, 0x88,
0x88, 0x88, 0x88, 0x88, 0x88, 0xba, 0x71, 0x35,
0x18, 0x88, 0x88, 0x88, 0x88, 0x88, 0x00, 0x00,
0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETGIP2, 0x97, 0x0a, 0x82, 0x02,
0x13, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0x88, 0xba, 0x17, 0x53, 0x88, 0x88, 0x88,
0x88, 0x88, 0x88, 0x81, 0x88, 0xba, 0x06, 0x42,
0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x23, 0x10,
0x00, 0x02, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00);
mipi_dsi_dcs_write_seq_multi(dsi_ctx, ST7703_CMD_SETGAMMA, 0x00, 0x07, 0x0b,
0x27, 0x2d, 0x3f, 0x3b, 0x37, 0x05, 0x0a, 0x0b,
0x0f, 0x11, 0x0f, 0x12, 0x12, 0x18, 0x00, 0x07,
0x0b, 0x27, 0x2d, 0x3f, 0x3b, 0x37, 0x05, 0xa0,
0x0b, 0x0f, 0x11, 0x0f, 0x12, 0x12, 0x18);
}
static const struct drm_display_mode gameforcechi_mode = {
@ -701,50 +677,37 @@ static int st7703_enable(struct drm_panel *panel)
{
struct st7703 *ctx = panel_to_st7703(panel);
struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
int ret;
struct mipi_dsi_multi_context dsi_ctx = {.dsi = dsi};
ret = ctx->desc->init_sequence(ctx);
if (ret < 0) {
dev_err(ctx->dev, "Panel init sequence failed: %d\n", ret);
return ret;
}
ctx->desc->init_sequence(&dsi_ctx);
ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
if (ret < 0) {
dev_err(ctx->dev, "Failed to exit sleep mode: %d\n", ret);
return ret;
}
mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx);
/* It takes the controller 120 msec to wake up after sleep. */
msleep(120);
mipi_dsi_msleep(&dsi_ctx, 120);
ret = mipi_dsi_dcs_set_display_on(dsi);
if (ret)
return ret;
mipi_dsi_dcs_set_display_on_multi(&dsi_ctx);
dev_dbg(ctx->dev, "Panel init sequence done\n");
if (!dsi_ctx.accum_err)
dev_dbg(ctx->dev, "Panel init sequence done\n");
return 0;
return dsi_ctx.accum_err;
}
static int st7703_disable(struct drm_panel *panel)
{
struct st7703 *ctx = panel_to_st7703(panel);
struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
int ret;
struct mipi_dsi_multi_context dsi_ctx = {.dsi = dsi};
ret = mipi_dsi_dcs_set_display_off(dsi);
if (ret < 0)
dev_err(ctx->dev, "Failed to turn off the display: %d\n", ret);
mipi_dsi_dcs_set_display_off_multi(&dsi_ctx);
ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
if (ret < 0)
dev_err(ctx->dev, "Failed to enter sleep mode: %d\n", ret);
mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx);
/* It takes the controller 120 msec to enter sleep mode. */
msleep(120);
mipi_dsi_msleep(&dsi_ctx, 120);
return 0;
return dsi_ctx.accum_err;
}
static int st7703_unprepare(struct drm_panel *panel)
@ -840,10 +803,11 @@ static int allpixelson_set(void *data, u64 val)
{
struct st7703 *ctx = data;
struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
struct mipi_dsi_multi_context dsi_ctx = {.dsi = dsi};
dev_dbg(ctx->dev, "Setting all pixels on\n");
mipi_dsi_generic_write_seq(dsi, ST7703_CMD_ALL_PIXEL_ON);
msleep(val * 1000);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, ST7703_CMD_ALL_PIXEL_ON);
mipi_dsi_msleep(&dsi_ctx, val * 1000);
/*
* Reset the panel to get video back. NOTE: This isn't a
@ -856,7 +820,7 @@ static int allpixelson_set(void *data, u64 val)
drm_panel_prepare(&ctx->panel);
drm_panel_enable(&ctx->panel);
return 0;
return dsi_ctx.accum_err;
}
DEFINE_SIMPLE_ATTRIBUTE(allpixelson_fops, NULL,

View File

@ -44,248 +44,229 @@ static void truly_nt35521_reset(struct truly_nt35521 *ctx)
static int truly_nt35521_on(struct truly_nt35521 *ctx)
{
struct mipi_dsi_device *dsi = ctx->dsi;
struct device *dev = &dsi->dev;
int ret;
struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi };
dsi->mode_flags |= MIPI_DSI_MODE_LPM;
mipi_dsi_generic_write_seq(dsi, 0xf0, 0x55, 0xaa, 0x52, 0x08, 0x00);
mipi_dsi_generic_write_seq(dsi, 0xff, 0xaa, 0x55, 0xa5, 0x80);
mipi_dsi_generic_write_seq(dsi, 0x6f, 0x11, 0x00);
mipi_dsi_generic_write_seq(dsi, 0xf7, 0x20, 0x00);
mipi_dsi_generic_write_seq(dsi, 0x6f, 0x01);
mipi_dsi_generic_write_seq(dsi, 0xb1, 0x21);
mipi_dsi_generic_write_seq(dsi, 0xbd, 0x01, 0xa0, 0x10, 0x08, 0x01);
mipi_dsi_generic_write_seq(dsi, 0xb8, 0x01, 0x02, 0x0c, 0x02);
mipi_dsi_generic_write_seq(dsi, 0xbb, 0x11, 0x11);
mipi_dsi_generic_write_seq(dsi, 0xbc, 0x00, 0x00);
mipi_dsi_generic_write_seq(dsi, 0xb6, 0x02);
mipi_dsi_generic_write_seq(dsi, 0xf0, 0x55, 0xaa, 0x52, 0x08, 0x01);
mipi_dsi_generic_write_seq(dsi, 0xb0, 0x09, 0x09);
mipi_dsi_generic_write_seq(dsi, 0xb1, 0x09, 0x09);
mipi_dsi_generic_write_seq(dsi, 0xbc, 0x8c, 0x00);
mipi_dsi_generic_write_seq(dsi, 0xbd, 0x8c, 0x00);
mipi_dsi_generic_write_seq(dsi, 0xca, 0x00);
mipi_dsi_generic_write_seq(dsi, 0xc0, 0x04);
mipi_dsi_generic_write_seq(dsi, 0xbe, 0xb5);
mipi_dsi_generic_write_seq(dsi, 0xb3, 0x35, 0x35);
mipi_dsi_generic_write_seq(dsi, 0xb4, 0x25, 0x25);
mipi_dsi_generic_write_seq(dsi, 0xb9, 0x43, 0x43);
mipi_dsi_generic_write_seq(dsi, 0xba, 0x24, 0x24);
mipi_dsi_generic_write_seq(dsi, 0xf0, 0x55, 0xaa, 0x52, 0x08, 0x02);
mipi_dsi_generic_write_seq(dsi, 0xee, 0x03);
mipi_dsi_generic_write_seq(dsi, 0xb0,
0x00, 0xb2, 0x00, 0xb3, 0x00, 0xb6, 0x00, 0xc3,
0x00, 0xce, 0x00, 0xe1, 0x00, 0xf3, 0x01, 0x11);
mipi_dsi_generic_write_seq(dsi, 0xb1,
0x01, 0x2e, 0x01, 0x5c, 0x01, 0x82, 0x01, 0xc3,
0x01, 0xfe, 0x02, 0x00, 0x02, 0x37, 0x02, 0x77);
mipi_dsi_generic_write_seq(dsi, 0xb2,
0x02, 0xa1, 0x02, 0xd7, 0x02, 0xfe, 0x03, 0x2c,
0x03, 0x4b, 0x03, 0x63, 0x03, 0x8f, 0x03, 0x90);
mipi_dsi_generic_write_seq(dsi, 0xb3, 0x03, 0x96, 0x03, 0x98);
mipi_dsi_generic_write_seq(dsi, 0xb4,
0x00, 0x81, 0x00, 0x8b, 0x00, 0x9c, 0x00, 0xa9,
0x00, 0xb5, 0x00, 0xcb, 0x00, 0xdf, 0x01, 0x02);
mipi_dsi_generic_write_seq(dsi, 0xb5,
0x01, 0x1f, 0x01, 0x51, 0x01, 0x7a, 0x01, 0xbf,
0x01, 0xfa, 0x01, 0xfc, 0x02, 0x34, 0x02, 0x76);
mipi_dsi_generic_write_seq(dsi, 0xb6,
0x02, 0x9f, 0x02, 0xd7, 0x02, 0xfc, 0x03, 0x2c,
0x03, 0x4a, 0x03, 0x63, 0x03, 0x8f, 0x03, 0xa2);
mipi_dsi_generic_write_seq(dsi, 0xb7, 0x03, 0xb8, 0x03, 0xba);
mipi_dsi_generic_write_seq(dsi, 0xb8,
0x00, 0x01, 0x00, 0x02, 0x00, 0x0e, 0x00, 0x2a,
0x00, 0x41, 0x00, 0x67, 0x00, 0x87, 0x00, 0xb9);
mipi_dsi_generic_write_seq(dsi, 0xb9,
0x00, 0xe2, 0x01, 0x22, 0x01, 0x54, 0x01, 0xa3,
0x01, 0xe6, 0x01, 0xe7, 0x02, 0x24, 0x02, 0x67);
mipi_dsi_generic_write_seq(dsi, 0xba,
0x02, 0x93, 0x02, 0xcd, 0x02, 0xf6, 0x03, 0x31,
0x03, 0x6c, 0x03, 0xe9, 0x03, 0xef, 0x03, 0xf4);
mipi_dsi_generic_write_seq(dsi, 0xbb, 0x03, 0xf6, 0x03, 0xf7);
mipi_dsi_generic_write_seq(dsi, 0xf0, 0x55, 0xaa, 0x52, 0x08, 0x03);
mipi_dsi_generic_write_seq(dsi, 0xb0, 0x22, 0x00);
mipi_dsi_generic_write_seq(dsi, 0xb1, 0x22, 0x00);
mipi_dsi_generic_write_seq(dsi, 0xb2, 0x05, 0x00, 0x60, 0x00, 0x00);
mipi_dsi_generic_write_seq(dsi, 0xb3, 0x05, 0x00, 0x60, 0x00, 0x00);
mipi_dsi_generic_write_seq(dsi, 0xb4, 0x05, 0x00, 0x60, 0x00, 0x00);
mipi_dsi_generic_write_seq(dsi, 0xb5, 0x05, 0x00, 0x60, 0x00, 0x00);
mipi_dsi_generic_write_seq(dsi, 0xba, 0x53, 0x00, 0x60, 0x00, 0x00);
mipi_dsi_generic_write_seq(dsi, 0xbb, 0x53, 0x00, 0x60, 0x00, 0x00);
mipi_dsi_generic_write_seq(dsi, 0xbc, 0x53, 0x00, 0x60, 0x00, 0x00);
mipi_dsi_generic_write_seq(dsi, 0xbd, 0x53, 0x00, 0x60, 0x00, 0x00);
mipi_dsi_generic_write_seq(dsi, 0xc0, 0x00, 0x34, 0x00, 0x00);
mipi_dsi_generic_write_seq(dsi, 0xc1, 0x00, 0x00, 0x34, 0x00);
mipi_dsi_generic_write_seq(dsi, 0xc2, 0x00, 0x00, 0x34, 0x00);
mipi_dsi_generic_write_seq(dsi, 0xc3, 0x00, 0x00, 0x34, 0x00);
mipi_dsi_generic_write_seq(dsi, 0xc4, 0x60);
mipi_dsi_generic_write_seq(dsi, 0xc5, 0xc0);
mipi_dsi_generic_write_seq(dsi, 0xc6, 0x00);
mipi_dsi_generic_write_seq(dsi, 0xc7, 0x00);
mipi_dsi_generic_write_seq(dsi, 0xf0, 0x55, 0xaa, 0x52, 0x08, 0x05);
mipi_dsi_generic_write_seq(dsi, 0xb0, 0x17, 0x06);
mipi_dsi_generic_write_seq(dsi, 0xb1, 0x17, 0x06);
mipi_dsi_generic_write_seq(dsi, 0xb2, 0x17, 0x06);
mipi_dsi_generic_write_seq(dsi, 0xb3, 0x17, 0x06);
mipi_dsi_generic_write_seq(dsi, 0xb4, 0x17, 0x06);
mipi_dsi_generic_write_seq(dsi, 0xb5, 0x17, 0x06);
mipi_dsi_generic_write_seq(dsi, 0xb6, 0x17, 0x06);
mipi_dsi_generic_write_seq(dsi, 0xb7, 0x17, 0x06);
mipi_dsi_generic_write_seq(dsi, 0xb8, 0x00);
mipi_dsi_generic_write_seq(dsi, 0xb9, 0x00, 0x03);
mipi_dsi_generic_write_seq(dsi, 0xba, 0x00, 0x00);
mipi_dsi_generic_write_seq(dsi, 0xbb, 0x02, 0x03);
mipi_dsi_generic_write_seq(dsi, 0xbc, 0x02, 0x03);
mipi_dsi_generic_write_seq(dsi, 0xbd, 0x03, 0x03, 0x00, 0x03, 0x03);
mipi_dsi_generic_write_seq(dsi, 0xc0, 0x0b);
mipi_dsi_generic_write_seq(dsi, 0xc1, 0x09);
mipi_dsi_generic_write_seq(dsi, 0xc2, 0xa6);
mipi_dsi_generic_write_seq(dsi, 0xc3, 0x05);
mipi_dsi_generic_write_seq(dsi, 0xc4, 0x00);
mipi_dsi_generic_write_seq(dsi, 0xc5, 0x02);
mipi_dsi_generic_write_seq(dsi, 0xc6, 0x22);
mipi_dsi_generic_write_seq(dsi, 0xc7, 0x03);
mipi_dsi_generic_write_seq(dsi, 0xc8, 0x07, 0x20);
mipi_dsi_generic_write_seq(dsi, 0xc9, 0x03, 0x20);
mipi_dsi_generic_write_seq(dsi, 0xca, 0x01, 0x60);
mipi_dsi_generic_write_seq(dsi, 0xcb, 0x01, 0x60);
mipi_dsi_generic_write_seq(dsi, 0xcc, 0x00, 0x00, 0x02);
mipi_dsi_generic_write_seq(dsi, 0xcd, 0x00, 0x00, 0x02);
mipi_dsi_generic_write_seq(dsi, 0xce, 0x00, 0x00, 0x02);
mipi_dsi_generic_write_seq(dsi, 0xcf, 0x00, 0x00, 0x02);
mipi_dsi_generic_write_seq(dsi, 0xd1, 0x00, 0x05, 0x01, 0x07, 0x10);
mipi_dsi_generic_write_seq(dsi, 0xd2, 0x10, 0x05, 0x05, 0x03, 0x10);
mipi_dsi_generic_write_seq(dsi, 0xd3, 0x20, 0x00, 0x43, 0x07, 0x10);
mipi_dsi_generic_write_seq(dsi, 0xd4, 0x30, 0x00, 0x43, 0x07, 0x10);
mipi_dsi_generic_write_seq(dsi, 0xd0,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
mipi_dsi_generic_write_seq(dsi, 0xd5,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00);
mipi_dsi_generic_write_seq(dsi, 0xd6,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00);
mipi_dsi_generic_write_seq(dsi, 0xd7,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00);
mipi_dsi_generic_write_seq(dsi, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00);
mipi_dsi_generic_write_seq(dsi, 0xe5, 0x06);
mipi_dsi_generic_write_seq(dsi, 0xe6, 0x06);
mipi_dsi_generic_write_seq(dsi, 0xe7, 0x00);
mipi_dsi_generic_write_seq(dsi, 0xe8, 0x06);
mipi_dsi_generic_write_seq(dsi, 0xe9, 0x06);
mipi_dsi_generic_write_seq(dsi, 0xea, 0x06);
mipi_dsi_generic_write_seq(dsi, 0xeb, 0x00);
mipi_dsi_generic_write_seq(dsi, 0xec, 0x00);
mipi_dsi_generic_write_seq(dsi, 0xed, 0x30);
mipi_dsi_generic_write_seq(dsi, 0xf0, 0x55, 0xaa, 0x52, 0x08, 0x06);
mipi_dsi_generic_write_seq(dsi, 0xb0, 0x31, 0x31);
mipi_dsi_generic_write_seq(dsi, 0xb1, 0x31, 0x31);
mipi_dsi_generic_write_seq(dsi, 0xb2, 0x2d, 0x2e);
mipi_dsi_generic_write_seq(dsi, 0xb3, 0x31, 0x34);
mipi_dsi_generic_write_seq(dsi, 0xb4, 0x29, 0x2a);
mipi_dsi_generic_write_seq(dsi, 0xb5, 0x12, 0x10);
mipi_dsi_generic_write_seq(dsi, 0xb6, 0x18, 0x16);
mipi_dsi_generic_write_seq(dsi, 0xb7, 0x00, 0x02);
mipi_dsi_generic_write_seq(dsi, 0xb8, 0x08, 0x31);
mipi_dsi_generic_write_seq(dsi, 0xb9, 0x31, 0x31);
mipi_dsi_generic_write_seq(dsi, 0xba, 0x31, 0x31);
mipi_dsi_generic_write_seq(dsi, 0xbb, 0x31, 0x08);
mipi_dsi_generic_write_seq(dsi, 0xbc, 0x03, 0x01);
mipi_dsi_generic_write_seq(dsi, 0xbd, 0x17, 0x19);
mipi_dsi_generic_write_seq(dsi, 0xbe, 0x11, 0x13);
mipi_dsi_generic_write_seq(dsi, 0xbf, 0x2a, 0x29);
mipi_dsi_generic_write_seq(dsi, 0xc0, 0x34, 0x31);
mipi_dsi_generic_write_seq(dsi, 0xc1, 0x2e, 0x2d);
mipi_dsi_generic_write_seq(dsi, 0xc2, 0x31, 0x31);
mipi_dsi_generic_write_seq(dsi, 0xc3, 0x31, 0x31);
mipi_dsi_generic_write_seq(dsi, 0xc4, 0x31, 0x31);
mipi_dsi_generic_write_seq(dsi, 0xc5, 0x31, 0x31);
mipi_dsi_generic_write_seq(dsi, 0xc6, 0x2e, 0x2d);
mipi_dsi_generic_write_seq(dsi, 0xc7, 0x31, 0x34);
mipi_dsi_generic_write_seq(dsi, 0xc8, 0x29, 0x2a);
mipi_dsi_generic_write_seq(dsi, 0xc9, 0x17, 0x19);
mipi_dsi_generic_write_seq(dsi, 0xca, 0x11, 0x13);
mipi_dsi_generic_write_seq(dsi, 0xcb, 0x03, 0x01);
mipi_dsi_generic_write_seq(dsi, 0xcc, 0x08, 0x31);
mipi_dsi_generic_write_seq(dsi, 0xcd, 0x31, 0x31);
mipi_dsi_generic_write_seq(dsi, 0xce, 0x31, 0x31);
mipi_dsi_generic_write_seq(dsi, 0xcf, 0x31, 0x08);
mipi_dsi_generic_write_seq(dsi, 0xd0, 0x00, 0x02);
mipi_dsi_generic_write_seq(dsi, 0xd1, 0x12, 0x10);
mipi_dsi_generic_write_seq(dsi, 0xd2, 0x18, 0x16);
mipi_dsi_generic_write_seq(dsi, 0xd3, 0x2a, 0x29);
mipi_dsi_generic_write_seq(dsi, 0xd4, 0x34, 0x31);
mipi_dsi_generic_write_seq(dsi, 0xd5, 0x2d, 0x2e);
mipi_dsi_generic_write_seq(dsi, 0xd6, 0x31, 0x31);
mipi_dsi_generic_write_seq(dsi, 0xd7, 0x31, 0x31);
mipi_dsi_generic_write_seq(dsi, 0xe5, 0x31, 0x31);
mipi_dsi_generic_write_seq(dsi, 0xe6, 0x31, 0x31);
mipi_dsi_generic_write_seq(dsi, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00);
mipi_dsi_generic_write_seq(dsi, 0xd9, 0x00, 0x00, 0x00, 0x00, 0x00);
mipi_dsi_generic_write_seq(dsi, 0xe7, 0x00);
mipi_dsi_generic_write_seq(dsi, 0x6f, 0x02);
mipi_dsi_generic_write_seq(dsi, 0xf7, 0x47);
mipi_dsi_generic_write_seq(dsi, 0x6f, 0x0a);
mipi_dsi_generic_write_seq(dsi, 0xf7, 0x02);
mipi_dsi_generic_write_seq(dsi, 0x6f, 0x17);
mipi_dsi_generic_write_seq(dsi, 0xf4, 0x60);
mipi_dsi_generic_write_seq(dsi, 0x6f, 0x01);
mipi_dsi_generic_write_seq(dsi, 0xf9, 0x46);
mipi_dsi_generic_write_seq(dsi, 0x6f, 0x11);
mipi_dsi_generic_write_seq(dsi, 0xf3, 0x01);
mipi_dsi_generic_write_seq(dsi, 0x35, 0x00);
mipi_dsi_generic_write_seq(dsi, 0xf0, 0x55, 0xaa, 0x52, 0x08, 0x00);
mipi_dsi_generic_write_seq(dsi, 0xd9, 0x02, 0x03, 0x00);
mipi_dsi_generic_write_seq(dsi, 0xf0, 0x55, 0xaa, 0x52, 0x00, 0x00);
mipi_dsi_generic_write_seq(dsi, 0xf0, 0x55, 0xaa, 0x52, 0x08, 0x00);
mipi_dsi_generic_write_seq(dsi, 0xb1, 0x6c, 0x21);
mipi_dsi_generic_write_seq(dsi, 0xf0, 0x55, 0xaa, 0x52, 0x00, 0x00);
mipi_dsi_generic_write_seq(dsi, 0x35, 0x00);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf0, 0x55, 0xaa, 0x52, 0x08, 0x00);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xff, 0xaa, 0x55, 0xa5, 0x80);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x6f, 0x11, 0x00);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf7, 0x20, 0x00);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x6f, 0x01);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb1, 0x21);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xbd, 0x01, 0xa0, 0x10, 0x08, 0x01);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb8, 0x01, 0x02, 0x0c, 0x02);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xbb, 0x11, 0x11);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xbc, 0x00, 0x00);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb6, 0x02);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf0, 0x55, 0xaa, 0x52, 0x08, 0x01);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb0, 0x09, 0x09);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb1, 0x09, 0x09);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xbc, 0x8c, 0x00);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xbd, 0x8c, 0x00);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xca, 0x00);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc0, 0x04);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xbe, 0xb5);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb3, 0x35, 0x35);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb4, 0x25, 0x25);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb9, 0x43, 0x43);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xba, 0x24, 0x24);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf0, 0x55, 0xaa, 0x52, 0x08, 0x02);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xee, 0x03);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb0,
0x00, 0xb2, 0x00, 0xb3, 0x00, 0xb6, 0x00, 0xc3,
0x00, 0xce, 0x00, 0xe1, 0x00, 0xf3, 0x01, 0x11);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb1,
0x01, 0x2e, 0x01, 0x5c, 0x01, 0x82, 0x01, 0xc3,
0x01, 0xfe, 0x02, 0x00, 0x02, 0x37, 0x02, 0x77);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb2,
0x02, 0xa1, 0x02, 0xd7, 0x02, 0xfe, 0x03, 0x2c,
0x03, 0x4b, 0x03, 0x63, 0x03, 0x8f, 0x03, 0x90);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb3, 0x03, 0x96, 0x03, 0x98);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb4,
0x00, 0x81, 0x00, 0x8b, 0x00, 0x9c, 0x00, 0xa9,
0x00, 0xb5, 0x00, 0xcb, 0x00, 0xdf, 0x01, 0x02);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb5,
0x01, 0x1f, 0x01, 0x51, 0x01, 0x7a, 0x01, 0xbf,
0x01, 0xfa, 0x01, 0xfc, 0x02, 0x34, 0x02, 0x76);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb6,
0x02, 0x9f, 0x02, 0xd7, 0x02, 0xfc, 0x03, 0x2c,
0x03, 0x4a, 0x03, 0x63, 0x03, 0x8f, 0x03, 0xa2);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb7, 0x03, 0xb8, 0x03, 0xba);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb8,
0x00, 0x01, 0x00, 0x02, 0x00, 0x0e, 0x00, 0x2a,
0x00, 0x41, 0x00, 0x67, 0x00, 0x87, 0x00, 0xb9);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb9,
0x00, 0xe2, 0x01, 0x22, 0x01, 0x54, 0x01, 0xa3,
0x01, 0xe6, 0x01, 0xe7, 0x02, 0x24, 0x02, 0x67);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xba,
0x02, 0x93, 0x02, 0xcd, 0x02, 0xf6, 0x03, 0x31,
0x03, 0x6c, 0x03, 0xe9, 0x03, 0xef, 0x03, 0xf4);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xbb, 0x03, 0xf6, 0x03, 0xf7);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf0, 0x55, 0xaa, 0x52, 0x08, 0x03);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb0, 0x22, 0x00);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb1, 0x22, 0x00);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb2, 0x05, 0x00, 0x60, 0x00, 0x00);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb3, 0x05, 0x00, 0x60, 0x00, 0x00);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb4, 0x05, 0x00, 0x60, 0x00, 0x00);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb5, 0x05, 0x00, 0x60, 0x00, 0x00);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xba, 0x53, 0x00, 0x60, 0x00, 0x00);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xbb, 0x53, 0x00, 0x60, 0x00, 0x00);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xbc, 0x53, 0x00, 0x60, 0x00, 0x00);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xbd, 0x53, 0x00, 0x60, 0x00, 0x00);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc0, 0x00, 0x34, 0x00, 0x00);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc1, 0x00, 0x00, 0x34, 0x00);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc2, 0x00, 0x00, 0x34, 0x00);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc3, 0x00, 0x00, 0x34, 0x00);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc4, 0x60);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc5, 0xc0);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc6, 0x00);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc7, 0x00);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf0, 0x55, 0xaa, 0x52, 0x08, 0x05);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb0, 0x17, 0x06);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb1, 0x17, 0x06);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb2, 0x17, 0x06);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb3, 0x17, 0x06);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb4, 0x17, 0x06);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb5, 0x17, 0x06);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb6, 0x17, 0x06);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb7, 0x17, 0x06);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb8, 0x00);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb9, 0x00, 0x03);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xba, 0x00, 0x00);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xbb, 0x02, 0x03);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xbc, 0x02, 0x03);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xbd, 0x03, 0x03, 0x00, 0x03, 0x03);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc0, 0x0b);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc1, 0x09);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc2, 0xa6);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc3, 0x05);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc4, 0x00);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc5, 0x02);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc6, 0x22);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc7, 0x03);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc8, 0x07, 0x20);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc9, 0x03, 0x20);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xca, 0x01, 0x60);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xcb, 0x01, 0x60);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xcc, 0x00, 0x00, 0x02);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xcd, 0x00, 0x00, 0x02);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xce, 0x00, 0x00, 0x02);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xcf, 0x00, 0x00, 0x02);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd1, 0x00, 0x05, 0x01, 0x07, 0x10);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd2, 0x10, 0x05, 0x05, 0x03, 0x10);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd3, 0x20, 0x00, 0x43, 0x07, 0x10);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd4, 0x30, 0x00, 0x43, 0x07, 0x10);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd0,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd5,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd6,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd7,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe5, 0x06);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe6, 0x06);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe7, 0x00);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe8, 0x06);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe9, 0x06);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xea, 0x06);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xeb, 0x00);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xec, 0x00);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xed, 0x30);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf0, 0x55, 0xaa, 0x52, 0x08, 0x06);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb0, 0x31, 0x31);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb1, 0x31, 0x31);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb2, 0x2d, 0x2e);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb3, 0x31, 0x34);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb4, 0x29, 0x2a);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb5, 0x12, 0x10);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb6, 0x18, 0x16);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb7, 0x00, 0x02);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb8, 0x08, 0x31);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb9, 0x31, 0x31);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xba, 0x31, 0x31);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xbb, 0x31, 0x08);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xbc, 0x03, 0x01);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xbd, 0x17, 0x19);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xbe, 0x11, 0x13);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xbf, 0x2a, 0x29);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc0, 0x34, 0x31);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc1, 0x2e, 0x2d);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc2, 0x31, 0x31);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc3, 0x31, 0x31);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc4, 0x31, 0x31);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc5, 0x31, 0x31);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc6, 0x2e, 0x2d);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc7, 0x31, 0x34);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc8, 0x29, 0x2a);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xc9, 0x17, 0x19);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xca, 0x11, 0x13);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xcb, 0x03, 0x01);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xcc, 0x08, 0x31);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xcd, 0x31, 0x31);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xce, 0x31, 0x31);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xcf, 0x31, 0x08);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd0, 0x00, 0x02);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd1, 0x12, 0x10);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd2, 0x18, 0x16);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd3, 0x2a, 0x29);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd4, 0x34, 0x31);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd5, 0x2d, 0x2e);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd6, 0x31, 0x31);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd7, 0x31, 0x31);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe5, 0x31, 0x31);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe6, 0x31, 0x31);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd9, 0x00, 0x00, 0x00, 0x00, 0x00);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xe7, 0x00);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x6f, 0x02);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf7, 0x47);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x6f, 0x0a);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf7, 0x02);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x6f, 0x17);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf4, 0x60);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x6f, 0x01);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf9, 0x46);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x6f, 0x11);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf3, 0x01);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x35, 0x00);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf0, 0x55, 0xaa, 0x52, 0x08, 0x00);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xd9, 0x02, 0x03, 0x00);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf0, 0x55, 0xaa, 0x52, 0x00, 0x00);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf0, 0x55, 0xaa, 0x52, 0x08, 0x00);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xb1, 0x6c, 0x21);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0xf0, 0x55, 0xaa, 0x52, 0x00, 0x00);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x35, 0x00);
ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
if (ret < 0) {
dev_err(dev, "Failed to exit sleep mode: %d\n", ret);
return ret;
}
msleep(120);
mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx);
mipi_dsi_msleep(&dsi_ctx, 120);
mipi_dsi_dcs_set_display_on_multi(&dsi_ctx);
ret = mipi_dsi_dcs_set_display_on(dsi);
if (ret < 0) {
dev_err(dev, "Failed to set display on: %d\n", ret);
return ret;
}
usleep_range(1000, 2000);
mipi_dsi_generic_write_seq(dsi, 0x53, 0x24);
mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x53, 0x24);
return 0;
return dsi_ctx.accum_err;
}
static int truly_nt35521_off(struct truly_nt35521 *ctx)
{
struct mipi_dsi_device *dsi = ctx->dsi;
struct device *dev = &dsi->dev;
int ret;
struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi };
dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
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(50);
mipi_dsi_dcs_set_display_off_multi(&dsi_ctx);
mipi_dsi_msleep(&dsi_ctx, 50);
mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx);
mipi_dsi_msleep(&dsi_ctx, 150);
ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
if (ret < 0) {
dev_err(dev, "Failed to enter sleep mode: %d\n", ret);
return ret;
}
msleep(150);
return 0;
return dsi_ctx.accum_err;
}
static int truly_nt35521_prepare(struct drm_panel *panel)

View File

@ -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;

View File

@ -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,
},
};

View File

@ -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");

View File

@ -1,4 +1,3 @@
CONFIG_KUNIT=y
CONFIG_DRM=y
CONFIG_DRM_KUNIT_TEST_HELPERS=y
CONFIG_DRM_TTM_KUNIT_TEST=y

View File

@ -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

View File

@ -0,0 +1,27 @@
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

View File

@ -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");

File diff suppressed because it is too large Load Diff

View File

@ -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");

View File

@ -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;
err = ttm_device_init(ttm, &ttm_dev_funcs, drm->dev,
drm->anon_inode->i_mapping,
drm->vma_offset_manager,
use_dma_alloc, use_dma32);
return 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);
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);
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_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");

View File

@ -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

View File

@ -0,0 +1,234 @@
// 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");

View File

@ -0,0 +1,30 @@
/* 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

View File

@ -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");

View File

@ -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");

View File

@ -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");

View File

@ -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

View File

@ -234,6 +234,7 @@ enum vc4_vec_tv_mode_id {
VC4_VEC_TV_MODE_PAL_60,
VC4_VEC_TV_MODE_PAL_N,
VC4_VEC_TV_MODE_SECAM,
VC4_VEC_TV_MODE_MONOCHROME,
};
struct vc4_vec_tv_mode {
@ -324,6 +325,22 @@ static const struct vc4_vec_tv_mode vc4_vec_tv_modes[] = {
.config1 = VEC_CONFIG1_C_CVBS_CVBS,
.custom_freq = 0x29c71c72,
},
{
/* 50Hz mono */
.mode = DRM_MODE_TV_MODE_MONOCHROME,
.expected_htotal = 864,
.config0 = VEC_CONFIG0_PAL_BDGHI_STD | VEC_CONFIG0_BURDIS |
VEC_CONFIG0_CHRDIS,
.config1 = VEC_CONFIG1_C_CVBS_CVBS,
},
{
/* 60Hz mono */
.mode = DRM_MODE_TV_MODE_MONOCHROME,
.expected_htotal = 858,
.config0 = VEC_CONFIG0_PAL_M_STD | VEC_CONFIG0_BURDIS |
VEC_CONFIG0_CHRDIS,
.config1 = VEC_CONFIG1_C_CVBS_CVBS,
},
};
static inline const struct vc4_vec_tv_mode *
@ -351,6 +368,7 @@ static const struct drm_prop_enum_list legacy_tv_mode_names[] = {
{ VC4_VEC_TV_MODE_PAL_M, "PAL-M", },
{ VC4_VEC_TV_MODE_PAL_N, "PAL-N", },
{ VC4_VEC_TV_MODE_SECAM, "SECAM", },
{ VC4_VEC_TV_MODE_MONOCHROME, "Mono", },
};
static enum drm_connector_status
@ -406,6 +424,10 @@ vc4_vec_connector_set_property(struct drm_connector *connector,
state->tv.mode = DRM_MODE_TV_MODE_SECAM;
break;
case VC4_VEC_TV_MODE_MONOCHROME:
state->tv.mode = DRM_MODE_TV_MODE_MONOCHROME;
break;
default:
return -EINVAL;
}
@ -453,6 +475,10 @@ vc4_vec_connector_get_property(struct drm_connector *connector,
*val = VC4_VEC_TV_MODE_SECAM;
break;
case DRM_MODE_TV_MODE_MONOCHROME:
*val = VC4_VEC_TV_MODE_MONOCHROME;
break;
default:
return -EINVAL;
}
@ -503,6 +529,8 @@ static int vc4_vec_connector_init(struct drm_device *dev, struct vc4_vec *vec)
drm_object_attach_property(&connector->base, prop, VC4_VEC_TV_MODE_NTSC);
drm_connector_attach_tv_margin_properties(connector);
drm_connector_attach_encoder(connector, &vec->encoder.base);
return 0;
@ -754,7 +782,8 @@ static int vc4_vec_bind(struct device *dev, struct device *master, void *data)
BIT(DRM_MODE_TV_MODE_PAL) |
BIT(DRM_MODE_TV_MODE_PAL_M) |
BIT(DRM_MODE_TV_MODE_PAL_N) |
BIT(DRM_MODE_TV_MODE_SECAM));
BIT(DRM_MODE_TV_MODE_SECAM) |
BIT(DRM_MODE_TV_MODE_MONOCHROME));
if (ret)
return ret;

View File

@ -5,6 +5,7 @@
#include <drm/drm_fourcc.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/genalloc.h>
#include <linux/module.h>
@ -96,9 +97,16 @@ struct ipu_pre {
dma_addr_t buffer_paddr;
void *buffer_virt;
bool in_use;
unsigned int safe_window_end;
unsigned int last_bufaddr;
struct {
bool in_use;
uint64_t modifier;
unsigned int height;
unsigned int safe_window_end;
unsigned int bufaddr;
u32 ctrl;
u8 cpp;
} cur;
};
static DEFINE_MUTEX(ipu_pre_list_mutex);
@ -113,8 +121,8 @@ int ipu_pre_get_available_count(void)
struct ipu_pre *
ipu_pre_lookup_by_phandle(struct device *dev, const char *name, int index)
{
struct device_node *pre_node = of_parse_phandle(dev->of_node,
name, index);
struct device_node *pre_node __free(device_node) =
of_parse_phandle(dev->of_node, name, index);
struct ipu_pre *pre;
mutex_lock(&ipu_pre_list_mutex);
@ -123,14 +131,11 @@ ipu_pre_lookup_by_phandle(struct device *dev, const char *name, int index)
mutex_unlock(&ipu_pre_list_mutex);
device_link_add(dev, pre->dev,
DL_FLAG_AUTOREMOVE_CONSUMER);
of_node_put(pre_node);
return pre;
}
}
mutex_unlock(&ipu_pre_list_mutex);
of_node_put(pre_node);
return NULL;
}
@ -138,7 +143,7 @@ int ipu_pre_get(struct ipu_pre *pre)
{
u32 val;
if (pre->in_use)
if (pre->cur.in_use)
return -EBUSY;
/* first get the engine out of reset and remove clock gating */
@ -151,7 +156,7 @@ int ipu_pre_get(struct ipu_pre *pre)
IPU_PRE_CTRL_SDW_UPDATE;
writel(val, pre->regs + IPU_PRE_CTRL);
pre->in_use = true;
pre->cur.in_use = true;
return 0;
}
@ -159,7 +164,41 @@ void ipu_pre_put(struct ipu_pre *pre)
{
writel(IPU_PRE_CTRL_SFTRST, pre->regs + IPU_PRE_CTRL);
pre->in_use = false;
pre->cur.in_use = false;
}
static inline void
ipu_pre_update_safe_window(struct ipu_pre *pre)
{
if (pre->cur.modifier == DRM_FORMAT_MOD_LINEAR)
pre->cur.safe_window_end = pre->cur.height - 2;
else
pre->cur.safe_window_end = DIV_ROUND_UP(pre->cur.height, 4) - 1;
}
static void
ipu_pre_configure_modifier(struct ipu_pre *pre, uint64_t modifier)
{
u32 val;
val = readl(pre->regs + IPU_PRE_TPR_CTRL);
val &= ~IPU_PRE_TPR_CTRL_TILE_FORMAT_MASK;
if (modifier != DRM_FORMAT_MOD_LINEAR) {
/* only support single buffer formats for now */
val |= IPU_PRE_TPR_CTRL_TILE_FORMAT_SINGLE_BUF;
if (modifier == DRM_FORMAT_MOD_VIVANTE_SUPER_TILED)
val |= IPU_PRE_TPR_CTRL_TILE_FORMAT_SUPER_TILED;
if (pre->cur.cpp == 2)
val |= IPU_PRE_TPR_CTRL_TILE_FORMAT_16_BIT;
}
writel(val, pre->regs + IPU_PRE_TPR_CTRL);
if (modifier == DRM_FORMAT_MOD_LINEAR)
pre->cur.ctrl &= ~IPU_PRE_CTRL_BLOCK_EN;
else
pre->cur.ctrl |= IPU_PRE_CTRL_BLOCK_EN;
pre->cur.modifier = modifier;
}
void ipu_pre_configure(struct ipu_pre *pre, unsigned int width,
@ -170,15 +209,16 @@ void ipu_pre_configure(struct ipu_pre *pre, unsigned int width,
u32 active_bpp = info->cpp[0] >> 1;
u32 val;
pre->cur.bufaddr = bufaddr;
pre->cur.height = height;
pre->cur.cpp = info->cpp[0];
pre->cur.ctrl = readl(pre->regs + IPU_PRE_CTRL);
/* calculate safe window for ctrl register updates */
if (modifier == DRM_FORMAT_MOD_LINEAR)
pre->safe_window_end = height - 2;
else
pre->safe_window_end = DIV_ROUND_UP(height, 4) - 1;
ipu_pre_update_safe_window(pre);
writel(bufaddr, pre->regs + IPU_PRE_CUR_BUF);
writel(bufaddr, pre->regs + IPU_PRE_NEXT_BUF);
pre->last_bufaddr = bufaddr;
val = IPU_PRE_PREF_ENG_CTRL_INPUT_PIXEL_FORMAT(0) |
IPU_PRE_PREF_ENG_CTRL_INPUT_ACTIVE_BPP(active_bpp) |
@ -208,42 +248,30 @@ void ipu_pre_configure(struct ipu_pre *pre, unsigned int width,
writel(pre->buffer_paddr, pre->regs + IPU_PRE_STORE_ENG_ADDR);
val = readl(pre->regs + IPU_PRE_TPR_CTRL);
val &= ~IPU_PRE_TPR_CTRL_TILE_FORMAT_MASK;
if (modifier != DRM_FORMAT_MOD_LINEAR) {
/* only support single buffer formats for now */
val |= IPU_PRE_TPR_CTRL_TILE_FORMAT_SINGLE_BUF;
if (modifier == DRM_FORMAT_MOD_VIVANTE_SUPER_TILED)
val |= IPU_PRE_TPR_CTRL_TILE_FORMAT_SUPER_TILED;
if (info->cpp[0] == 2)
val |= IPU_PRE_TPR_CTRL_TILE_FORMAT_16_BIT;
}
writel(val, pre->regs + IPU_PRE_TPR_CTRL);
ipu_pre_configure_modifier(pre, modifier);
val = readl(pre->regs + IPU_PRE_CTRL);
val |= IPU_PRE_CTRL_EN_REPEAT | IPU_PRE_CTRL_ENABLE |
IPU_PRE_CTRL_SDW_UPDATE;
if (modifier == DRM_FORMAT_MOD_LINEAR)
val &= ~IPU_PRE_CTRL_BLOCK_EN;
else
val |= IPU_PRE_CTRL_BLOCK_EN;
writel(val, pre->regs + IPU_PRE_CTRL);
pre->cur.ctrl |= IPU_PRE_CTRL_EN_REPEAT | IPU_PRE_CTRL_ENABLE;
writel(pre->cur.ctrl | IPU_PRE_CTRL_SDW_UPDATE,
pre->regs + IPU_PRE_CTRL);
}
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)
{
unsigned long timeout = jiffies + msecs_to_jiffies(5);
unsigned short current_yblock;
u32 val;
if (bufaddr == pre->last_bufaddr)
if (bufaddr == pre->cur.bufaddr &&
modifier == pre->cur.modifier)
return;
writel(bufaddr, pre->regs + IPU_PRE_NEXT_BUF);
pre->last_bufaddr = bufaddr;
pre->cur.bufaddr = bufaddr;
do {
if (time_after(jiffies, timeout)) {
if (modifier != pre->cur.modifier)
ipu_pre_configure_modifier(pre, modifier);
for (int i = 0;; i++) {
unsigned short current_yblock;
u32 val;
if (i > 500) {
dev_warn(pre->dev, "timeout waiting for PRE safe window\n");
return;
}
@ -252,9 +280,20 @@ void ipu_pre_update(struct ipu_pre *pre, unsigned int bufaddr)
current_yblock =
(val >> IPU_PRE_STORE_ENG_STATUS_STORE_BLOCK_Y_SHIFT) &
IPU_PRE_STORE_ENG_STATUS_STORE_BLOCK_Y_MASK;
} while (current_yblock == 0 || current_yblock >= pre->safe_window_end);
writel(IPU_PRE_CTRL_SDW_UPDATE, pre->regs + IPU_PRE_CTRL_SET);
if (current_yblock != 0 &&
current_yblock < pre->cur.safe_window_end)
break;
udelay(10);
cpu_relax();
}
writel(pre->cur.ctrl | IPU_PRE_CTRL_SDW_UPDATE,
pre->regs + IPU_PRE_CTRL);
/* calculate safe window for the next update with the new modifier */
ipu_pre_update_safe_window(pre);
}
bool ipu_pre_update_pending(struct ipu_pre *pre)

View File

@ -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;
}

View File

@ -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,

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -10,6 +10,7 @@
#define __DRM_MIPI_DSI_H__
#include <linux/device.h>
#include <linux/delay.h>
struct mipi_dsi_host;
struct mipi_dsi_device;
@ -297,6 +298,12 @@ ssize_t mipi_dsi_generic_read(struct mipi_dsi_device *dsi, const void *params,
msleep(delay); \
} while (0)
#define mipi_dsi_usleep_range(ctx, min, max) \
do { \
if (!(ctx)->accum_err) \
usleep_range(min, max); \
} while (0)
/**
* enum mipi_dsi_dcs_tear_mode - Tearing Effect Output Line mode
* @MIPI_DSI_DCS_TEAR_MODE_VBLANK: the TE output line consists of V-Blanking

View File

@ -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;

View File

@ -105,7 +105,8 @@ config FONT_SUN8x16
config FONT_SUN12x22
bool "Sparc console 12x22 font (not supported by all drivers)"
depends on (FRAMEBUFFER_CONSOLE && (!SPARC && FONTS || SPARC)) || DRM_PANIC
depends on FRAMEBUFFER_CONSOLE || DRM_PANIC
depends on !SPARC && FONTS
help
This is the high resolution console font for Sun machines with very
big letters (like the letters used in the SPARC PROM). If the
@ -113,7 +114,8 @@ config FONT_SUN12x22
config FONT_TER16x32
bool "Terminus 16x32 font (not supported by all drivers)"
depends on (FRAMEBUFFER_CONSOLE && (!SPARC && FONTS || SPARC)) || DRM_PANIC
depends on FRAMEBUFFER_CONSOLE || DRM_PANIC
depends on !SPARC && FONTS || SPARC
help
Terminus Font is a clean, fixed width bitmap font, designed
for long (8 and more hours per day) work with computers.