适配新七寸屏

This commit is contained in:
2026-11-09 10:18:46 +08:00
parent a19e595794
commit 7f6fd3bd9d
10 changed files with 131 additions and 126 deletions
@@ -8,7 +8,7 @@
//#include "lcd/lcd_g40396_truly_mipi_fhd.dtsi" //#include "lcd/lcd_g40396_truly_mipi_fhd.dtsi"
//#include "lcd/lcd_nt36672e_truly_mipi_fhd_nodsc.dtsi" //#include "lcd/lcd_nt36672e_truly_mipi_fhd_nodsc.dtsi"
#include "lcd/lcd_lt8912b_mipi_hdmi_1080p.dtsi" #include "lcd/lcd_lt8912b_mipi_hdmi_1080p.dtsi"
#include "lcd/lcd_ili9881c_truly_mipi_wxga.dtsi" #include "lcd/lcd_jd9365_mipi_wxga.dtsi"
#include "tp/ums9620-tp.dtsi" #include "tp/ums9620-tp.dtsi"
#include <dt-bindings/mfd/sprd,ump9620-regs.h> #include <dt-bindings/mfd/sprd,ump9620-regs.h>
#include <dt-bindings/mfd/sprd,ump9620-mask.h> #include <dt-bindings/mfd/sprd,ump9620-mask.h>
@@ -594,7 +594,7 @@
sprd,backlight = <&pwm_backlight>; sprd,backlight = <&pwm_backlight>;
avdd-gpio = <&ap_gpio 153 GPIO_ACTIVE_HIGH>; avdd-gpio = <&ap_gpio 153 GPIO_ACTIVE_HIGH>;
avee-gpio = <&ap_gpio 178 GPIO_ACTIVE_HIGH>; avee-gpio = <&ap_gpio 178 GPIO_ACTIVE_HIGH>;
iovdd-gpio = <&ap_gpio 187 GPIO_ACTIVE_HIGH>; /* GPIO187 is kept high by the shared hdmi_5v_en gpio-hog above. */
reset-gpio = <&ap_gpio 152 GPIO_ACTIVE_HIGH>; reset-gpio = <&ap_gpio 152 GPIO_ACTIVE_HIGH>;
}; };
@@ -604,7 +604,7 @@
}; };
&lcd_ili9881c_truly_mipi_wxga { &lcd_jd9365_mipi_wxga {
sprd,sr-width = <800>; sprd,sr-width = <800>;
sprd,sr-height = <1280>; sprd,sr-height = <1280>;
}; };
@@ -11,7 +11,7 @@
sprd,dsi-lane-number = <4>; sprd,dsi-lane-number = <4>;
sprd,dsi-color-format = "rgb888"; sprd,dsi-color-format = "rgb888";
/* Vendor PLL_CLOCK: 407 Mbps per lane. */ /* Last visually verified clean U-Boot configuration. */
sprd,phy-bit-clock = <407000>; sprd,phy-bit-clock = <407000>;
sprd,phy-escape-clock = <20000>; sprd,phy-escape-clock = <20000>;
@@ -28,7 +28,7 @@
sprd,reset-on-sequence = <1 5>, <0 10>, <1 120>; sprd,reset-on-sequence = <1 5>, <0 10>, <1 120>;
sprd,reset-off-sequence = <0 20>; sprd,reset-off-sequence = <0 20>;
sprd,use-dcs-write; /* Vendor table entries are 0x23 generic short writes. */
sprd,initial-command = [ sprd,initial-command = [
23 00 00 02 E0 00 23 00 00 02 E0 00
23 00 00 02 E1 93 23 00 00 02 E1 93
@@ -241,13 +241,14 @@
display-timings { display-timings {
timing0 { timing0 {
clock-frequency = <67750800>; clock-frequency = <64000000>;
hactive = <800>; hactive = <800>;
vactive = <1280>; vactive = <1280>;
hback-porch = <20>; hback-porch = <20>;
hfront-porch = <20>; hfront-porch = <20>;
vback-porch = <8>; /* Keep the U-Boot-only timing that produced a clean logo. */
vfront-porch = <17>; vback-porch = <24>;
vfront-porch = <1>;
hsync-len = <20>; hsync-len = <20>;
vsync-len = <8>; vsync-len = <8>;
}; };
@@ -18,6 +18,23 @@
#include "mipi_dsi_api.h" #include "mipi_dsi_api.h"
#include "mipi_dsi_hal.h" #include "mipi_dsi_hal.h"
static bool use_jd9365_rounded_timing(struct sprd_dsi *dsi)
{
return dsi->panel && dsi->panel->lcd_name &&
!strcmp(dsi->panel->lcd_name, "lcd_jd9365_mipi_wxga");
}
static u16 calc_dpi_byte_cycles(struct sprd_dsi *dsi,
struct dpi_video_param *param, u32 pixels)
{
if (use_jd9365_rounded_timing(dsi))
return DIV_ROUND_CLOSEST_ULL((u64)pixels * param->byte_clk,
param->pixel_clk);
/* Preserve the vendor calculation for every other panel. */
return pixels * (param->byte_clk * 1000 / param->pixel_clk) / 1000;
}
static u16 calc_bytes_per_pixel_x100(int coding) static u16 calc_bytes_per_pixel_x100(int coding)
{ {
u16 bpp_x100; u16 bpp_x100;
@@ -207,6 +224,7 @@ int mipi_dsi_dpi_video(struct sprd_dsi *dsi, struct dpi_video_param *param)
u32 chunk_overhead = 0; u32 chunk_overhead = 0;
const u8 pkt_header = 6; const u8 pkt_header = 6;
u32 div = 0; u32 div = 0;
u16 hline_time;
video_size = round_video_size(param->coding, param->hact); video_size = round_video_size(param->coding, param->hact);
bpp_x100 = calc_bytes_per_pixel_x100(param->coding); bpp_x100 = calc_bytes_per_pixel_x100(param->coding);
@@ -215,15 +233,18 @@ int mipi_dsi_dpi_video(struct sprd_dsi *dsi, struct dpi_video_param *param)
return -1; return -1;
ratio_x1000 = param->byte_clk * 1000 / param->pixel_clk; ratio_x1000 = param->byte_clk * 1000 / param->pixel_clk;
hline_time = calc_dpi_byte_cycles(dsi, param, param->hline);
dsi_hal_power_en(dsi, 0); dsi_hal_power_en(dsi, 0);
dsi_hal_dpi_frame_ack_en(dsi, param->frame_ack_en); dsi_hal_dpi_frame_ack_en(dsi, param->frame_ack_en);
dsi_hal_dpi_color_coding(dsi, param->coding); dsi_hal_dpi_color_coding(dsi, param->coding);
dsi_hal_dpi_video_burst_mode(dsi, param->burst_mode); dsi_hal_dpi_video_burst_mode(dsi, param->burst_mode);
dsi_hal_dpi_sig_delay(dsi, 95 * param->hline * ratio_x1000 / 100000); dsi_hal_dpi_sig_delay(dsi, 95 * hline_time / 100);
dsi_hal_dpi_hline_time(dsi, param->hline * ratio_x1000 / 1000); dsi_hal_dpi_hline_time(dsi, hline_time);
dsi_hal_dpi_hsync_time(dsi, param->hsync * ratio_x1000 / 1000); dsi_hal_dpi_hsync_time(dsi,
dsi_hal_dpi_hbp_time(dsi, param->hbp * ratio_x1000 / 1000); calc_dpi_byte_cycles(dsi, param, param->hsync));
dsi_hal_dpi_hbp_time(dsi,
calc_dpi_byte_cycles(dsi, param, param->hbp));
dsi_hal_dpi_vact(dsi, param->vact); dsi_hal_dpi_vact(dsi, param->vact);
dsi_hal_dpi_vfp(dsi, param->vfp); dsi_hal_dpi_vfp(dsi, param->vfp);
dsi_hal_dpi_vbp(dsi, param->vbp); dsi_hal_dpi_vbp(dsi, param->vbp);
@@ -360,15 +381,17 @@ int mipi_dsi_edpi_video(struct sprd_dsi *dsi, struct edpi_video_param *param)
int mipi_dsi_htime_update(struct sprd_dsi *dsi, struct dpi_video_param *param) int mipi_dsi_htime_update(struct sprd_dsi *dsi, struct dpi_video_param *param)
{ {
u32 ratio_x1000 = 0; u16 hline_time;
ratio_x1000 = param->byte_clk * 1000 / param->pixel_clk; hline_time = calc_dpi_byte_cycles(dsi, param, param->hline);
dsi_hal_power_en(dsi, 0); dsi_hal_power_en(dsi, 0);
dsi_hal_dpi_sig_delay(dsi, 95 * param->hline * ratio_x1000 / 100000); dsi_hal_dpi_sig_delay(dsi, 95 * hline_time / 100);
dsi_hal_dpi_hline_time(dsi, param->hline * ratio_x1000 / 1000); dsi_hal_dpi_hline_time(dsi, hline_time);
dsi_hal_dpi_hsync_time(dsi, param->hsync * ratio_x1000 / 1000); dsi_hal_dpi_hsync_time(dsi,
dsi_hal_dpi_hbp_time(dsi, param->hbp * ratio_x1000 / 1000); calc_dpi_byte_cycles(dsi, param, param->hsync));
dsi_hal_dpi_hbp_time(dsi,
calc_dpi_byte_cycles(dsi, param, param->hbp));
dsi_hal_power_en(dsi, 1); dsi_hal_power_en(dsi, 1);
return 0; return 0;
@@ -10,6 +10,7 @@
__overlay__ { __overlay__ {
lcds { lcds {
lcd_jd9365_mipi_wxga: lcd_jd9365_mipi_wxga { lcd_jd9365_mipi_wxga: lcd_jd9365_mipi_wxga {
/* Match the U-Boot handoff and the stable Unisoc burst path. */
sprd,dsi-work-mode = <1>; sprd,dsi-work-mode = <1>;
sprd,dsi-lane-number = <4>; sprd,dsi-lane-number = <4>;
sprd,dsi-color-format = "rgb888"; sprd,dsi-color-format = "rgb888";
@@ -26,7 +27,13 @@
sprd,reset-on-sequence = <1 5>, <0 10>, <1 120>; sprd,reset-on-sequence = <1 5>, <0 10>, <1 120>;
sprd,reset-off-sequence = <0 20>; sprd,reset-off-sequence = <0 20>;
sprd,use-dcs-write; /*
* The vendor register table uses packet type 0x23
* (generic short write, two parameters). Do not set
* sprd,use-dcs-write here: that makes the panel driver
* recode every entry as a DCS packet and the JD9365
* vendor-page registers are then not programmed.
*/
sprd,initial-command = [ sprd,initial-command = [
23 00 00 02 E0 00 23 00 00 02 E0 00
23 00 00 02 E1 93 23 00 00 02 E1 93
@@ -241,13 +248,18 @@
native-mode = <&jd9365_timing0>; native-mode = <&jd9365_timing0>;
jd9365_timing0: timing0 { jd9365_timing0: timing0 {
clock-frequency = <67750800>; clock-frequency = <64000000>;
hactive = <800>; hactive = <800>;
vactive = <1280>; vactive = <1280>;
hback-porch = <20>; hback-porch = <20>;
hfront-porch = <20>; hfront-porch = <20>;
vback-porch = <8>; /*
vfront-porch = <17>; * DPU r6p0 requires vsync + vback-porch >= 32.
* Keep the 25-line total blanking unchanged while
* matching the visually clean U-Boot handoff.
*/
vback-porch = <24>;
vfront-porch = <1>;
hsync-len = <20>; hsync-len = <20>;
vsync-len = <8>; vsync-len = <8>;
}; };
@@ -8,7 +8,7 @@
//#include "lcd/lcd_g40396_truly_mipi_fhd.dtsi" //#include "lcd/lcd_g40396_truly_mipi_fhd.dtsi"
//#include "lcd/lcd_nt36672e_truly_mipi_fhd_nodsc.dtsi" //#include "lcd/lcd_nt36672e_truly_mipi_fhd_nodsc.dtsi"
#include "lcd/lcd_lt8912b_mipi_hdmi_1080p.dtsi" #include "lcd/lcd_lt8912b_mipi_hdmi_1080p.dtsi"
#include "lcd/lcd_ili9881c_truly_mipi_wxga.dtsi" #include "lcd/lcd_jd9365_mipi_wxga.dtsi"
#include "tp/ums9620-tp.dtsi" #include "tp/ums9620-tp.dtsi"
#include <dt-bindings/mfd/sprd,ump9620-regs.h> #include <dt-bindings/mfd/sprd,ump9620-regs.h>
#include <dt-bindings/mfd/sprd,ump9620-mask.h> #include <dt-bindings/mfd/sprd,ump9620-mask.h>
@@ -594,7 +594,7 @@
sprd,backlight = <&pwm_backlight>; sprd,backlight = <&pwm_backlight>;
avdd-gpio = <&ap_gpio 153 GPIO_ACTIVE_HIGH>; avdd-gpio = <&ap_gpio 153 GPIO_ACTIVE_HIGH>;
avee-gpio = <&ap_gpio 178 GPIO_ACTIVE_HIGH>; avee-gpio = <&ap_gpio 178 GPIO_ACTIVE_HIGH>;
iovdd-gpio = <&ap_gpio 187 GPIO_ACTIVE_HIGH>; /* GPIO187 is kept high by the shared hdmi_5v_en gpio-hog above. */
reset-gpio = <&ap_gpio 152 GPIO_ACTIVE_HIGH>; reset-gpio = <&ap_gpio 152 GPIO_ACTIVE_HIGH>;
}; };
@@ -604,7 +604,7 @@
}; };
&lcd_ili9881c_truly_mipi_wxga { &lcd_jd9365_mipi_wxga {
sprd,sr-width = <800>; sprd,sr-width = <800>;
sprd,sr-height = <1280>; sprd,sr-height = <1280>;
}; };
@@ -7,6 +7,39 @@
#include "sprd_dsi_hal.h" #include "sprd_dsi_hal.h"
static bool use_jd9365_rounded_timing(struct dsi_context *ctx)
{
return ctx->lcd_name &&
!strcmp(ctx->lcd_name, "lcd_jd9365_mipi_wxga");
}
static u16 calc_dpi_byte_cycles(struct dsi_context *ctx,
struct videomode *vm, u32 pixels)
{
u32 pixel_clk = vm->pixelclock / 1000;
u32 ratio_x1000;
if (use_jd9365_rounded_timing(ctx))
return DIV_ROUND_CLOSEST_ULL((u64)pixels * ctx->byte_clk,
pixel_clk);
/* Preserve the original calculation for every other DSI panel. */
ratio_x1000 = ctx->byte_clk * 1000 / pixel_clk;
return pixels * ratio_x1000 / 1000;
}
static u16 calc_dpi_sig_delay(struct dsi_context *ctx,
struct videomode *vm, u32 pixels)
{
u32 ratio_x1000;
if (use_jd9365_rounded_timing(ctx))
return 95 * calc_dpi_byte_cycles(ctx, vm, pixels) / 100;
ratio_x1000 = ctx->byte_clk * 1000 / (vm->pixelclock / 1000);
return 95 * pixels * ratio_x1000 / 100000;
}
static int dsi_wait_tx_payload_fifo_empty(struct sprd_dsi *dsi) static int dsi_wait_tx_payload_fifo_empty(struct sprd_dsi *dsi)
{ {
int timeout; int timeout;
@@ -219,8 +252,8 @@ void sprd_dsi_fini(struct sprd_dsi *dsi)
int sprd_dsi_vrr_timing(struct sprd_dsi *dsi) int sprd_dsi_vrr_timing(struct sprd_dsi *dsi)
{ {
u16 Bpp_x100; u16 Bpp_x100;
u32 ratio_x1000;
u16 hline; u16 hline;
u16 hline_time;
u8 coding; u8 coding;
struct dsi_context *ctx = &dsi->ctx; struct dsi_context *ctx = &dsi->ctx;
struct videomode *vm = &dsi->ctx.vm; struct videomode *vm = &dsi->ctx.vm;
@@ -232,13 +265,15 @@ int sprd_dsi_vrr_timing(struct sprd_dsi *dsi)
coding = fmt_to_coding(ctx->format); coding = fmt_to_coding(ctx->format);
Bpp_x100 = calc_bytes_per_pixel_x100(coding); Bpp_x100 = calc_bytes_per_pixel_x100(coding);
ratio_x1000 = ctx->byte_clk * 1000 / (vm->pixelclock / 1000);
hline = vm->hactive + vm->hsync_len + vm->hfront_porch + hline = vm->hactive + vm->hsync_len + vm->hfront_porch +
vm->hback_porch; vm->hback_porch;
dsi_hal_dpi_sig_delay(dsi, 95 * hline * ratio_x1000 / 100000); hline_time = calc_dpi_byte_cycles(ctx, vm, hline);
dsi_hal_dpi_hline_time(dsi, hline * ratio_x1000 / 1000); dsi_hal_dpi_sig_delay(dsi, calc_dpi_sig_delay(ctx, vm, hline));
dsi_hal_dpi_hsync_time(dsi, vm->hsync_len * ratio_x1000 / 1000); dsi_hal_dpi_hline_time(dsi, hline_time);
dsi_hal_dpi_hbp_time(dsi, vm->hback_porch * ratio_x1000 / 1000); dsi_hal_dpi_hsync_time(dsi,
calc_dpi_byte_cycles(ctx, vm, vm->hsync_len));
dsi_hal_dpi_hbp_time(dsi,
calc_dpi_byte_cycles(ctx, vm, vm->hback_porch));
dsi_hal_dpi_vact(dsi, vm->vactive); dsi_hal_dpi_vact(dsi, vm->vactive);
dsi_hal_dpi_vfp(dsi, vm->vfront_porch); dsi_hal_dpi_vfp(dsi, vm->vfront_porch);
dsi_hal_dpi_vbp(dsi, vm->vback_porch); dsi_hal_dpi_vbp(dsi, vm->vback_porch);
@@ -274,6 +309,7 @@ int sprd_dsi_dpi_video(struct sprd_dsi *dsi)
u8 coding; u8 coding;
int div; int div;
u16 hline; u16 hline;
u16 hline_time;
struct dsi_context *ctx = &dsi->ctx; struct dsi_context *ctx = &dsi->ctx;
struct videomode *vm = &dsi->ctx.vm; struct videomode *vm = &dsi->ctx.vm;
@@ -284,15 +320,18 @@ int sprd_dsi_dpi_video(struct sprd_dsi *dsi)
ratio_x1000 = ctx->byte_clk * 1000 / (vm->pixelclock / 1000); ratio_x1000 = ctx->byte_clk * 1000 / (vm->pixelclock / 1000);
hline = vm->hactive + vm->hsync_len + vm->hfront_porch + hline = vm->hactive + vm->hsync_len + vm->hfront_porch +
vm->hback_porch; vm->hback_porch;
hline_time = calc_dpi_byte_cycles(ctx, vm, hline);
dsi_hal_power_en(dsi, 0); dsi_hal_power_en(dsi, 0);
dsi_hal_dpi_frame_ack_en(dsi, ctx->frame_ack_en); dsi_hal_dpi_frame_ack_en(dsi, ctx->frame_ack_en);
dsi_hal_dpi_color_coding(dsi, coding); dsi_hal_dpi_color_coding(dsi, coding);
dsi_hal_dpi_video_burst_mode(dsi, ctx->burst_mode); dsi_hal_dpi_video_burst_mode(dsi, ctx->burst_mode);
dsi_hal_dpi_sig_delay(dsi, 95 * hline * ratio_x1000 / 100000); dsi_hal_dpi_sig_delay(dsi, calc_dpi_sig_delay(ctx, vm, hline));
dsi_hal_dpi_hline_time(dsi, hline * ratio_x1000 / 1000); dsi_hal_dpi_hline_time(dsi, hline_time);
dsi_hal_dpi_hsync_time(dsi, vm->hsync_len * ratio_x1000 / 1000); dsi_hal_dpi_hsync_time(dsi,
dsi_hal_dpi_hbp_time(dsi, vm->hback_porch * ratio_x1000 / 1000); calc_dpi_byte_cycles(ctx, vm, vm->hsync_len));
dsi_hal_dpi_hbp_time(dsi,
calc_dpi_byte_cycles(ctx, vm, vm->hback_porch));
dsi_hal_dpi_vact(dsi, vm->vactive); dsi_hal_dpi_vact(dsi, vm->vactive);
dsi_hal_dpi_vfp(dsi, vm->vfront_porch); dsi_hal_dpi_vfp(dsi, vm->vfront_porch);
dsi_hal_dpi_vbp(dsi, vm->vback_porch); dsi_hal_dpi_vbp(dsi, vm->vback_porch);
@@ -8,19 +8,9 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/mfd/syscon.h> #include <linux/mfd/syscon.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#include <linux/io.h>
#include <linux/of_address.h>
#include "sprd_dpu.h" #include "sprd_dpu.h"
/* DPU_VSP clock-controller (ums9620 dpu_vsp_clk) register block @ 0x30110000. */
#define DPU_VSP_CLK_BASE 0x30110000UL
#define DPU_VSP_CLK_SIZE 0x3000
/* dispc0_dpi pixel-clock divider: offset 0x78, bits[3:0] (value 3 = div-by-4). */
#define REG_DISPC0_DPI_DIV 0x78
#define REG_DISPC0_DPI_DIV_MASK 0xf
static void __iomem *dpu_vsp_clk_base;
static struct clk *clk_dpuvsp_eb; static struct clk *clk_dpuvsp_eb;
static struct clk *clk_dpuvsp_disp_eb; static struct clk *clk_dpuvsp_disp_eb;
static struct clk *clk_master_div6_eb; static struct clk *clk_master_div6_eb;
@@ -163,20 +153,6 @@ static int dpu_clk_parse_dt(struct dpu_context *ctx,
clk_ctx->clk_dpu_dpi = NULL; clk_ctx->clk_dpu_dpi = NULL;
} }
/* Map the DPU_VSP clock-controller MMIO so the DPI-divider workaround
* can write register 0x30110078 directly. pr_err on failure - the ioremap
* must succeed or the workaround cannot fire at all.
*/
if (!dpu_vsp_clk_base) {
dpu_vsp_clk_base = ioremap_nocache(DPU_VSP_CLK_BASE,
DPU_VSP_CLK_SIZE);
if (!dpu_vsp_clk_base)
pr_err("ioremap dpu_vsp_clk (0x%lx) failed\n",
DPU_VSP_CLK_BASE);
else
pr_info("dpu_vsp_clk base mapped for dpi-div workaround\n");
}
return 0; return 0;
} }
@@ -211,40 +187,6 @@ static struct clk *div_to_clk(struct dpu_clk_context *clk_ctx, u32 clk_div)
} }
} }
/*
* Most direct path to force the dispc0_dpi pixel-clock divider to 3
* (divide-by-4): write bits[3:0] of register 0x30110078 (= DPU_VSP clock
* controller base 0x30110000 + offset 0x78). This bypasses the CCF and writes
* the MMIO register directly; the value is read back to confirm it latched.
* Returns the final divider value (should be 3 on success) or a negative errno.
*/
static int dpu_force_dpi_div3(void)
{
void __iomem *reg;
u32 val;
if (!dpu_vsp_clk_base) {
pr_err("force dpi div=3: clk mmio not mapped\n");
return -ENXIO;
}
reg = dpu_vsp_clk_base + REG_DISPC0_DPI_DIV;
val = readl_relaxed(reg);
val = (val & ~REG_DISPC0_DPI_DIV_MASK) | 3;
writel_relaxed(val, reg);
/* read-back flush, then re-read to confirm */
val = readl_relaxed(reg);
if ((val & REG_DISPC0_DPI_DIV_MASK) != 3) {
pr_err("force dpi div=3 (0x30110078) failed, readback=0x%x\n", val);
return -EIO;
}
pr_info("force dpi div=3 (0x30110078) ok, reg=0x%x\n", val);
return 0;
}
static int dpu_clk_init(struct dpu_context *ctx) static int dpu_clk_init(struct dpu_context *ctx)
{ {
int ret; int ret;
@@ -287,16 +229,6 @@ static int dpu_clk_init(struct dpu_context *ctx)
if (ret) if (ret)
pr_err("dpu update dpi clk rate failed\n"); pr_err("dpu update dpi clk rate failed\n");
/* Workaround: on resume (suspend->on), the DPI pixel-clock divider
* at 0x30110078 (dispc0_dpi div, bits[3:0]) is not re-applied and
* the panel lights up black. Force divider value 3 (div-by-4) by
* writing the MMIO register directly (most-direct path). Only acted
* upon when flagged from the resume path.
*/
if (ctx->dpi_div_force3) {
ctx->dpi_div_force3 = false;
dpu_force_dpi_div3();
}
} }
return ret; return ret;
@@ -378,18 +378,6 @@ static void sprd_dpu_enable(struct sprd_dpu *dpu)
void sprd_dpu_resume(struct sprd_dpu *dpu) void sprd_dpu_resume(struct sprd_dpu *dpu)
{ {
struct dpu_context *ctx = &dpu->ctx;
u32 mipi_port = 0;
/* Flag the DPI-divider workaround: force value 3 at 0x30110078 on the
* next dpu_clk_init() to avoid black screen on wake.
*/
if (dpu->dsi && dpu->dsi->panel) {
struct sprd_panel *panel = (struct sprd_panel *)container_of(dpu->dsi->panel, struct sprd_panel, base);
mipi_port = panel->info.mipi_port;
}
if(mipi_port == 1){
ctx->dpi_div_force3 = true;
}
sprd_dpu_enable(dpu); sprd_dpu_enable(dpu);
enable_irq(dpu->ctx.irq); enable_irq(dpu->ctx.irq);
sprd_iommu_restore(&dpu->dev); sprd_iommu_restore(&dpu->dev);
@@ -220,12 +220,6 @@ struct dpu_context {
/* spi frame refresh parameters */ /* spi frame refresh parameters */
unsigned int flag_mask_refresh; unsigned int flag_mask_refresh;
/* DPI pixel-clock divider force workaround.
* Set true from the resume path so dpu_clk_init() re-applies divider
* value 3 to register 0x30110078 (dispc0_dpi div, bits[3:0]) which is
* lost/missing on resume and causes a black screen on wake.
*/
bool dpi_div_force3;
}; };
struct sprd_dpu_ops { struct sprd_dpu_ops {
@@ -278,7 +278,15 @@ static int sprd_panel_get_modes(struct drm_panel *p)
/* parse and create sr mode config */ /* parse and create sr mode config */
of_property_read_u32(panel->info.of_node, "sprd,sr-width", &sr_width); of_property_read_u32(panel->info.of_node, "sprd,sr-width", &sr_width);
of_property_read_u32(panel->info.of_node, "sprd,sr-height", &sr_height); of_property_read_u32(panel->info.of_node, "sprd,sr-height", &sr_height);
if (sr_width && sr_height) { /*
* Do not advertise an SR mode when it is identical to the native
* panel mode. drm_display_mode_from_videomode() would otherwise
* create a duplicate with a synthetic pixel clock and zero porches,
* which userspace may select instead of the valid native timing.
*/
if (sr_width && sr_height &&
(sr_width != panel->info.mode.hdisplay ||
sr_height != panel->info.mode.vdisplay)) {
for (i = 0; i < panel->info.num_buildin_modes; i++) { for (i = 0; i < panel->info.num_buildin_modes; i++) {
struct videomode vm = {}; struct videomode vm = {};
vm.hactive = sr_width; vm.hactive = sr_width;
@@ -488,27 +496,35 @@ static int sprd_panel_gpio_request(struct device *dev,
{ {
panel->info.iovdd_gpio = devm_gpiod_get_optional(dev, panel->info.iovdd_gpio = devm_gpiod_get_optional(dev,
"iovdd", GPIOD_ASIS); "iovdd", GPIOD_ASIS);
if (IS_ERR_OR_NULL(panel->info.iovdd_gpio)) if (IS_ERR(panel->info.iovdd_gpio)) {
DRM_WARN("can't get panel iovdd gpio: %ld\n", DRM_WARN("can't get panel iovdd gpio: %ld\n",
PTR_ERR(panel->info.iovdd_gpio)); PTR_ERR(panel->info.iovdd_gpio));
panel->info.iovdd_gpio = NULL;
}
panel->info.avdd_gpio = devm_gpiod_get_optional(dev, panel->info.avdd_gpio = devm_gpiod_get_optional(dev,
"avdd", GPIOD_ASIS); "avdd", GPIOD_ASIS);
if (IS_ERR_OR_NULL(panel->info.avdd_gpio)) if (IS_ERR(panel->info.avdd_gpio)) {
DRM_WARN("can't get panel avdd gpio: %ld\n", DRM_WARN("can't get panel avdd gpio: %ld\n",
PTR_ERR(panel->info.avdd_gpio)); PTR_ERR(panel->info.avdd_gpio));
panel->info.avdd_gpio = NULL;
}
panel->info.avee_gpio = devm_gpiod_get_optional(dev, panel->info.avee_gpio = devm_gpiod_get_optional(dev,
"avee", GPIOD_ASIS); "avee", GPIOD_ASIS);
if (IS_ERR_OR_NULL(panel->info.avee_gpio)) if (IS_ERR(panel->info.avee_gpio)) {
DRM_WARN("can't get panel avee gpio: %ld\n", DRM_WARN("can't get panel avee gpio: %ld\n",
PTR_ERR(panel->info.avee_gpio)); PTR_ERR(panel->info.avee_gpio));
panel->info.avee_gpio = NULL;
}
panel->info.reset_gpio = devm_gpiod_get_optional(dev, panel->info.reset_gpio = devm_gpiod_get_optional(dev,
"reset", GPIOD_ASIS); "reset", GPIOD_ASIS);
if (IS_ERR_OR_NULL(panel->info.reset_gpio)) if (IS_ERR(panel->info.reset_gpio)) {
DRM_WARN("can't get panel reset gpio: %ld\n", DRM_WARN("can't get panel reset gpio: %ld\n",
PTR_ERR(panel->info.reset_gpio)); PTR_ERR(panel->info.reset_gpio));
panel->info.reset_gpio = NULL;
}
return 0; return 0;
} }