kernel_samsung_a53x/drivers/gpu/drm/samsung/dpu/panel/panel-samsung-s6e8fc1.c
2024-06-15 16:02:09 -03:00

225 lines
5.8 KiB
C
Executable file

// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2019 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
* Samsung S6E8DC1 Panel driver.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/of_platform.h>
#include <linux/module.h>
#include "panel-samsung-drv.h"
static const unsigned char SEQ_ERR_FG[] = {
0xED, 0x00, 0x01, 0x00, /* ERR_FG VLIN Monitor ON */
0x40, 0x04, 0x08, 0xA8, /* Line Copy On */
0x84, 0x4A, 0x73, 0x02, 0x0A, 0x00
};
static int s6e8fc1_disable(struct drm_panel *panel)
{
struct exynos_panel *ctx;
ctx = container_of(panel, struct exynos_panel, panel);
if (!ctx->enabled)
return 0;
EXYNOS_DCS_WRITE_SEQ(ctx, 0x28, 0x00, 0x00);
mdelay(20);
EXYNOS_DCS_WRITE_SEQ(ctx, 0x10, 0x00, 0x00);
ctx->enabled = false;
panel_debug(ctx, "+\n");
return 0;
}
static int s6e8fc1_unprepare(struct drm_panel *panel)
{
struct exynos_panel *ctx;
ctx = container_of(panel, struct exynos_panel, panel);
panel_debug(ctx, "+\n");
exynos_panel_set_power(ctx, false);
panel_debug(ctx, "-\n");
return 0;
}
static int s6e8fc1_prepare(struct drm_panel *panel)
{
struct exynos_panel *ctx;
ctx = container_of(panel, struct exynos_panel, panel);
panel_debug(ctx, "+\n");
exynos_panel_set_power(ctx, true);
usleep_range(10000, 11000);
exynos_panel_reset(ctx);
panel_debug(ctx, "-\n");
return 0;
}
static int s6e8fc1_set_brightness(struct exynos_panel *exynos_panel, u16 br)
{
u16 brightness;
brightness = (br & 0xff) << 8 | br >> 8;
return exynos_dcs_set_brightness(exynos_panel, brightness);
}
static void s6e8fc1_mode_set(struct exynos_panel *ctx,
const struct exynos_panel_mode *pmode, unsigned int flags)
{
panel_debug(ctx, "+\n");
if (!ctx->enabled)
return;
panel_debug(ctx, "-\n");
}
static void s6e8fc1_lp_mode_set(struct exynos_panel *ctx,
const struct exynos_panel_mode *pmode)
{
if (!ctx->enabled)
return;
panel_debug(ctxv, "enter %dhz LP mode\n", drm_mode_vrefresh(&pmode->mode));
}
static int s6e8fc1_enable(struct drm_panel *panel)
{
struct exynos_panel *ctx = container_of(panel, struct exynos_panel, panel);
const struct exynos_panel_mode *pmode = ctx->current_mode;
const struct drm_display_mode *mode;
if (!pmode) {
panel_err(ctx, "no current mode set\n");
return -EINVAL;
}
mode = &pmode->mode;
panel_info(ctx, "+\n");
EXYNOS_DCS_WRITE_SEQ_DELAY(ctx, 20, 0x11);
EXYNOS_DCS_WRITE_SEQ(ctx, 0xf0, 0x5a, 0x5a);
EXYNOS_DCS_WRITE_SEQ(ctx, 0xfc, 0x5a, 0x5a);
EXYNOS_DCS_WRITE_TABLE(ctx, SEQ_ERR_FG); // fail safe1 disable
EXYNOS_DCS_WRITE_SEQ(ctx, 0xf1, 0xa5, 0xa5);
EXYNOS_DCS_WRITE_SEQ(ctx, 0x53, 0x20);
EXYNOS_DCS_WRITE_SEQ(ctx, 0xB3, 0x11, 0x50, 0xDD, 0x0D, 0xC0, 0x0A);
EXYNOS_DCS_WRITE_SEQ(ctx, 0x51, 0x03, 0xFF);
EXYNOS_DCS_WRITE_SEQ(ctx, 0xf9, 0x20); // fail safe2 disable
EXYNOS_DCS_WRITE_SEQ(ctx, 0xf0, 0xa5, 0xa5);
mdelay(100);
EXYNOS_DCS_WRITE_SEQ(ctx, 0x29); /* display on */
ctx->enabled = true;
if (pmode->exynos_mode.is_lp_mode)
s6e8fc1_lp_mode_set(ctx, pmode);
panel_info(ctx, "-\n");
return 0;
}
/* drm_display_mode
*
* @clock: vtotal * htotal * fps / 1000
* @hdisplay = horizon resolution
* @hsync_start = hdisplay + hfp
* @hsync_end = hdisplay + hfp + hsa
* @htotal = hdisplay + hfp + hsa + hbp
* @vdisplay = vertical resolution,
* @vsync_start = vdisplay + vfp
* @vsync_end = vdisplay + vfp + vsa
* @vtotal = vdisplay + vfp + vsa + + vbp
*/
static const struct exynos_panel_mode s6e8fc1_mode[] = {
{
.mode = { DRM_MODE("720x1600@60", DRM_MODE_TYPE_DRIVER, 77375,
720, 746, 750, 798, 0, 1600, 1605, 1607,
1616, 0, 0) },
.exynos_mode = { EXYNOS_MODE(MIPI_DSI_MODE_VIDEO, 8,
false, false, 0, 0, 0) },
},
{
.mode = { DRM_MODE("720x1600@40", DRM_MODE_TYPE_DRIVER, 77375,
720, 746, 750, 798, 0, 1600, 2410, 2412,
2421, 0, 0) },
.exynos_mode = { EXYNOS_MODE(MIPI_DSI_MODE_VIDEO, 8,
false, false, 0, 0, 0) },
},
};
static const struct exynos_panel_mode s6e8fc1_lp_mode[] = {
{
.mode = { DRM_MODE("720x1600@60", DRM_MODE_TYPE_DRIVER, 38688,
720, 746, 750, 798, 0, 1600, 1605, 1607,
1616, 0, 0) },
.exynos_mode = { EXYNOS_MODE(MIPI_DSI_MODE_VIDEO, 8, true,
false, 0, 0, 0) },
},
{
.mode = { DRM_MODE("720x1600@40", DRM_MODE_TYPE_DRIVER, 77375,
720, 746, 750, 798, 0, 1600, 2410, 2412,
2421, 0, 0) },
.exynos_mode = { EXYNOS_MODE(MIPI_DSI_MODE_VIDEO, 8,
false, false, 0, 0, 0) },
},
};
static const struct drm_panel_funcs s6e8fc1_drm_funcs = {
.disable = s6e8fc1_disable,
.unprepare = s6e8fc1_unprepare,
.prepare = s6e8fc1_prepare,
.enable = s6e8fc1_enable,
.get_modes = exynos_panel_get_modes,
};
static const struct exynos_panel_funcs s6e8fc1_exynos_funcs = {
.set_brightness = s6e8fc1_set_brightness,
.set_lp_mode = s6e8fc1_lp_mode_set,
.mode_set = s6e8fc1_mode_set,
};
const struct exynos_panel_desc samsung_s6e8fc1 = {
.data_lane_cnt = 4,
.max_brightness = 1023,
.dft_brightness = 511,
.modes = s6e8fc1_mode,
.num_modes = ARRAY_SIZE(s6e8fc1_mode),
.lp_modes = s6e8fc1_lp_mode,
.num_lp_modes = ARRAY_SIZE(s6e8fc1_lp_mode),
.panel_func = &s6e8fc1_drm_funcs,
.exynos_panel_func = &s6e8fc1_exynos_funcs,
};
static const struct of_device_id exynos_panel_of_match[] = {
{ .compatible = "samsung,s6e8fc1", .data = &samsung_s6e8fc1 },
{ }
};
MODULE_DEVICE_TABLE(of, exynos_panel_of_match);
static struct mipi_dsi_driver exynos_panel_driver = {
.probe = exynos_panel_probe,
.remove = exynos_panel_remove,
.driver = {
.name = "panel-samsung-s6e8fc1",
.of_match_table = exynos_panel_of_match,
},
};
module_mipi_dsi_driver(exynos_panel_driver);
MODULE_AUTHOR("Wonyoeng choi <won0.choi@samsung.com>");
MODULE_DESCRIPTION("MIPI-DSI based Samsung s6e8fc1 panel driver");
MODULE_LICENSE("GPL");