适配新七寸屏

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
@@ -7,6 +7,39 @@
#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)
{
int timeout;
@@ -219,8 +252,8 @@ void sprd_dsi_fini(struct sprd_dsi *dsi)
int sprd_dsi_vrr_timing(struct sprd_dsi *dsi)
{
u16 Bpp_x100;
u32 ratio_x1000;
u16 hline;
u16 hline_time;
u8 coding;
struct dsi_context *ctx = &dsi->ctx;
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);
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 +
vm->hback_porch;
dsi_hal_dpi_sig_delay(dsi, 95 * hline * ratio_x1000 / 100000);
dsi_hal_dpi_hline_time(dsi, hline * ratio_x1000 / 1000);
dsi_hal_dpi_hsync_time(dsi, vm->hsync_len * ratio_x1000 / 1000);
dsi_hal_dpi_hbp_time(dsi, vm->hback_porch * ratio_x1000 / 1000);
hline_time = calc_dpi_byte_cycles(ctx, vm, hline);
dsi_hal_dpi_sig_delay(dsi, calc_dpi_sig_delay(ctx, vm, hline));
dsi_hal_dpi_hline_time(dsi, hline_time);
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_vfp(dsi, vm->vfront_porch);
dsi_hal_dpi_vbp(dsi, vm->vback_porch);
@@ -274,6 +309,7 @@ int sprd_dsi_dpi_video(struct sprd_dsi *dsi)
u8 coding;
int div;
u16 hline;
u16 hline_time;
struct dsi_context *ctx = &dsi->ctx;
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);
hline = vm->hactive + vm->hsync_len + vm->hfront_porch +
vm->hback_porch;
hline_time = calc_dpi_byte_cycles(ctx, vm, hline);
dsi_hal_power_en(dsi, 0);
dsi_hal_dpi_frame_ack_en(dsi, ctx->frame_ack_en);
dsi_hal_dpi_color_coding(dsi, coding);
dsi_hal_dpi_video_burst_mode(dsi, ctx->burst_mode);
dsi_hal_dpi_sig_delay(dsi, 95 * hline * ratio_x1000 / 100000);
dsi_hal_dpi_hline_time(dsi, hline * ratio_x1000 / 1000);
dsi_hal_dpi_hsync_time(dsi, vm->hsync_len * ratio_x1000 / 1000);
dsi_hal_dpi_hbp_time(dsi, vm->hback_porch * ratio_x1000 / 1000);
dsi_hal_dpi_sig_delay(dsi, calc_dpi_sig_delay(ctx, vm, hline));
dsi_hal_dpi_hline_time(dsi, hline_time);
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_vfp(dsi, vm->vfront_porch);
dsi_hal_dpi_vbp(dsi, vm->vback_porch);
@@ -8,19 +8,9 @@
#include <linux/module.h>
#include <linux/mfd/syscon.h>
#include <linux/regmap.h>
#include <linux/io.h>
#include <linux/of_address.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_disp_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;
}
/* 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;
}
@@ -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)
{
int ret;
@@ -287,16 +229,6 @@ static int dpu_clk_init(struct dpu_context *ctx)
if (ret)
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;
@@ -378,18 +378,6 @@ static void sprd_dpu_enable(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);
enable_irq(dpu->ctx.irq);
sprd_iommu_restore(&dpu->dev);
@@ -220,12 +220,6 @@ struct dpu_context {
/* spi frame refresh parameters */
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 {
@@ -278,7 +278,15 @@ static int sprd_panel_get_modes(struct drm_panel *p)
/* 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-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++) {
struct videomode vm = {};
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,
"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",
PTR_ERR(panel->info.iovdd_gpio));
panel->info.iovdd_gpio = NULL;
}
panel->info.avdd_gpio = devm_gpiod_get_optional(dev,
"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",
PTR_ERR(panel->info.avdd_gpio));
panel->info.avdd_gpio = NULL;
}
panel->info.avee_gpio = devm_gpiod_get_optional(dev,
"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",
PTR_ERR(panel->info.avee_gpio));
panel->info.avee_gpio = NULL;
}
panel->info.reset_gpio = devm_gpiod_get_optional(dev,
"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",
PTR_ERR(panel->info.reset_gpio));
panel->info.reset_gpio = NULL;
}
return 0;
}