mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-03-15 19:55:32 +00:00
Switch Panel Driver over to boe driver and fix up for PineTabV
This commit is contained in:
parent
c7d5e25012
commit
4ef4d3ba8a
2 changed files with 145 additions and 56 deletions
|
@ -83,6 +83,8 @@ static int panel_bridge_attach(struct drm_bridge *bridge,
|
|||
drm_connector_attach_encoder(&panel_bridge->connector,
|
||||
bridge->encoder);
|
||||
|
||||
drm_panel_bridge_set_orientation(connector, bridge);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
#include <drm/drm_modes.h>
|
||||
#include <drm/drm_panel.h>
|
||||
|
||||
#include <video/display_timing.h>
|
||||
|
||||
struct boe {
|
||||
struct drm_panel panel;
|
||||
bool enabled;
|
||||
|
@ -38,37 +40,61 @@ static inline struct boe *panel_to_boe(struct drm_panel *panel)
|
|||
static int boe_disable(struct drm_panel *panel)
|
||||
{
|
||||
struct boe *ctx = panel_to_boe(panel);
|
||||
|
||||
int ret;
|
||||
if (!ctx->enabled)
|
||||
return 0;
|
||||
|
||||
mipi_dsi_dcs_set_display_off(ctx->dsi);
|
||||
ret = mipi_dsi_dcs_set_display_off(ctx->dsi);
|
||||
if (ret) {
|
||||
dev_err(&ctx->dsi->dev, "Failed to set display off: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
msleep(120);
|
||||
|
||||
ctx->enabled = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int boe_unprepare(struct drm_panel *panel)
|
||||
{
|
||||
struct boe *ctx = panel_to_boe(panel);
|
||||
int ret;
|
||||
|
||||
if (!ctx->prepared)
|
||||
return 0;
|
||||
|
||||
mipi_dsi_dcs_enter_sleep_mode(ctx->dsi);
|
||||
ret = mipi_dsi_dcs_enter_sleep_mode(ctx->dsi);
|
||||
if (ret) {
|
||||
dev_err(&ctx->dsi->dev, "Failed to enter sleep mode: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
msleep(220);
|
||||
|
||||
gpiod_set_value_cansleep(ctx->reset, 1);
|
||||
if (!IS_ERR(ctx->reset))
|
||||
gpiod_set_value_cansleep(ctx->reset, 1);
|
||||
|
||||
gpiod_set_value_cansleep(ctx->enable, 0);
|
||||
|
||||
regulator_disable(ctx->power);
|
||||
|
||||
ctx->prepared = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void boe_check_write(struct mipi_dsi_device *dsi,
|
||||
const void *data, size_t len)
|
||||
{
|
||||
ssize_t ret = mipi_dsi_dcs_write_buffer(dsi, data, len);
|
||||
if (ret < 0) {
|
||||
dev_warn(&dsi->dev, "Failed to write dsi buffer: %ld\n",
|
||||
ret);
|
||||
}
|
||||
}
|
||||
|
||||
static int boe_prepare(struct drm_panel *panel)
|
||||
{
|
||||
struct boe *ctx = panel_to_boe(panel);
|
||||
|
@ -80,69 +106,113 @@ static int boe_prepare(struct drm_panel *panel)
|
|||
|
||||
ret = regulator_enable(ctx->power);
|
||||
if (ret) {
|
||||
dev_err(&dsi->dev, "Failed to enable power supply: %d\n", ret);
|
||||
dev_err(panel->dev, "Failed to enable power supply: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
gpiod_set_value_cansleep(ctx->enable, 1);
|
||||
|
||||
msleep(120);
|
||||
if (!IS_ERR(ctx->reset)) {
|
||||
msleep(120);
|
||||
|
||||
gpiod_direction_output(ctx->reset, 1);
|
||||
ret = gpiod_direction_output(ctx->reset, 1);
|
||||
if (ret) {
|
||||
dev_err(panel->dev, "Failed to set reset gpio: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
msleep(120);
|
||||
msleep(120);
|
||||
|
||||
gpiod_direction_output(ctx->reset, 0);
|
||||
|
||||
msleep(120);
|
||||
|
||||
mipi_dsi_dcs_write_buffer(dsi, (u8[]){ 0xE0, 0xAB, 0xBA }, 3);
|
||||
mipi_dsi_dcs_write_buffer(dsi, (u8[]){ 0xE1, 0xBA, 0xAB }, 3);
|
||||
mipi_dsi_dcs_write_buffer(dsi, (u8[]){ 0xB1, 0x10, 0x01, 0x47, 0xFF }, 5);
|
||||
mipi_dsi_dcs_write_buffer(dsi, (u8[]){ 0xB2, 0x0C, 0x14, 0x04, 0x50, 0x50, 0x14 }, 7);
|
||||
mipi_dsi_dcs_write_buffer(dsi, (u8[]){ 0xB3, 0x56, 0x53, 0x00 }, 4);
|
||||
mipi_dsi_dcs_write_buffer(dsi, (u8[]){ 0xB4, 0x33, 0x30, 0x04 }, 4);
|
||||
mipi_dsi_dcs_write_buffer(dsi, (u8[]){ 0xB6, 0xB0, 0x00, 0x00, 0x10, 0x00, 0x10, 0x00 }, 8);
|
||||
mipi_dsi_dcs_write_buffer(dsi, (u8[]){ 0xB8, 0x05, 0x12, 0x29, 0x49, 0x48, 0x00, 0x00 }, 8);
|
||||
mipi_dsi_dcs_write_buffer(dsi, (u8[]){ 0xB9, 0x7C, 0x65, 0x55, 0x49, 0x46, 0x36, 0x3B, 0x24, 0x3D, 0x3C, 0x3D, 0x5C, 0x4C, 0x55, 0x47, 0x46, 0x39, 0x26, 0x06, 0x7C, 0x65, 0x55, 0x49, 0x46, 0x36, 0x3B, 0x24, 0x3D, 0x3C, 0x3D, 0x5C, 0x4C, 0x55, 0x47, 0x46, 0x39, 0x26, 0x06 }, 39);
|
||||
mipi_dsi_dcs_write_buffer(dsi, (u8[]){ 0xC0, 0xFF, 0x87, 0x12, 0x34, 0x44, 0x44, 0x44, 0x44, 0x98, 0x04, 0x98, 0x04, 0x0F, 0x00, 0x00, 0xC1 }, 17);
|
||||
mipi_dsi_dcs_write_buffer(dsi, (u8[]){ 0xC1, 0x54, 0x94, 0x02, 0x85, 0x9F, 0x00, 0x7F, 0x00, 0x54, 0x00 }, 11);
|
||||
mipi_dsi_dcs_write_buffer(dsi, (u8[]){ 0xC2, 0x17, 0x09, 0x08, 0x89, 0x08, 0x11, 0x22, 0x20, 0x44, 0xFF, 0x18, 0x00 }, 13);
|
||||
mipi_dsi_dcs_write_buffer(dsi, (u8[]){ 0xC3, 0x86, 0x46, 0x05, 0x05, 0x1C, 0x1C, 0x1D, 0x1D, 0x02, 0x1F, 0x1F, 0x1E, 0x1E, 0x0F, 0x0F, 0x0D, 0x0D, 0x13, 0x13, 0x11, 0x11, 0x00 }, 23);
|
||||
mipi_dsi_dcs_write_buffer(dsi, (u8[]){ 0xC4, 0x07, 0x07, 0x04, 0x04, 0x1C, 0x1C, 0x1D, 0x1D, 0x02, 0x1F, 0x1F, 0x1E, 0x1E, 0x0E, 0x0E, 0x0C, 0x0C, 0x12, 0x12, 0x10, 0x10, 0x00 }, 23);
|
||||
mipi_dsi_dcs_write_buffer(dsi, (u8[]){ 0xC6, 0x2A, 0x2A }, 3);
|
||||
mipi_dsi_dcs_write_buffer(dsi, (u8[]){ 0xC8, 0x21, 0x00, 0x31, 0x42, 0x34, 0x16 }, 7);
|
||||
mipi_dsi_dcs_write_buffer(dsi, (u8[]){ 0xCA, 0xCB, 0x43 }, 3);
|
||||
mipi_dsi_dcs_write_buffer(dsi, (u8[]){ 0xCD, 0x0E, 0x4B, 0x4B, 0x20, 0x19, 0x6B, 0x06, 0xB3 }, 9);
|
||||
mipi_dsi_dcs_write_buffer(dsi, (u8[]){ 0xD2, 0xE3, 0x2B, 0x38, 0x00 }, 5);
|
||||
mipi_dsi_dcs_write_buffer(dsi, (u8[]){ 0xD4, 0x00, 0x01, 0x00, 0x0E, 0x04, 0x44, 0x08, 0x10, 0x00, 0x00, 0x00 }, 12);
|
||||
mipi_dsi_dcs_write_buffer(dsi, (u8[]){ 0xE6, 0x80, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, 9);
|
||||
mipi_dsi_dcs_write_buffer(dsi, (u8[]){ 0xF0, 0x12, 0x03, 0x20, 0x00, 0xFF }, 6);
|
||||
mipi_dsi_dcs_write_buffer(dsi, (u8[]){ 0xF3, 0x00 }, 2);
|
||||
|
||||
mipi_dsi_dcs_exit_sleep_mode(dsi);
|
||||
ret = gpiod_direction_output(ctx->reset, 0);
|
||||
if (ret) {
|
||||
dev_err(panel->dev, "Failed to reset reset gpio: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
msleep(120);
|
||||
|
||||
ctx->prepared = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int boe_enable(struct drm_panel *panel)
|
||||
{
|
||||
struct boe *ctx = panel_to_boe(panel);
|
||||
struct mipi_dsi_device *dsi = ctx->dsi;
|
||||
int ret;
|
||||
|
||||
if (ctx->enabled)
|
||||
return 0;
|
||||
|
||||
mipi_dsi_dcs_set_display_on(ctx->dsi);
|
||||
boe_check_write(dsi, (u8[]){ 0xE0, 0xAB, 0xBA }, 3);
|
||||
boe_check_write(dsi, (u8[]){ 0xE1, 0xBA, 0xAB }, 3);
|
||||
boe_check_write(dsi, (u8[]){ 0xB1, 0x10, 0x01, 0x47, 0xFF }, 5);
|
||||
boe_check_write(dsi, (u8[]){ 0xB2, 0x0C, 0x14, 0x04, 0x50, 0x50, 0x14 }, 7);
|
||||
boe_check_write(dsi, (u8[]){ 0xB3, 0x56, 0x53, 0x00 }, 4);
|
||||
boe_check_write(dsi, (u8[]){ 0xB4, 0x33, 0x30, 0x04 }, 4);
|
||||
boe_check_write(dsi, (u8[]){ 0xB6, 0xB0, 0x00, 0x00, 0x10, 0x00, 0x10, 0x00 }, 8);
|
||||
boe_check_write(dsi, (u8[]){ 0xB8, 0x05, 0x12, 0x29, 0x49, 0x48, 0x00, 0x00 }, 8);
|
||||
boe_check_write(dsi, (u8[]){ 0xB9, 0x7C, 0x65, 0x55, 0x49, 0x46, 0x36, 0x3B, 0x24, 0x3D, 0x3C, 0x3D, 0x5C, 0x4C, 0x55, 0x47, 0x46, 0x39, 0x26, 0x06, 0x7C, 0x65, 0x55, 0x49, 0x46, 0x36, 0x3B, 0x24, 0x3D, 0x3C, 0x3D, 0x5C, 0x4C, 0x55, 0x47, 0x46, 0x39, 0x26, 0x06 }, 39);
|
||||
boe_check_write(dsi, (u8[]){ 0xC0, 0xFF, 0x87, 0x12, 0x34, 0x44, 0x44, 0x44, 0x44, 0x98, 0x04, 0x98, 0x04, 0x0F, 0x00, 0x00, 0xC1 }, 17);
|
||||
boe_check_write(dsi, (u8[]){ 0xC1, 0x54, 0x94, 0x02, 0x85, 0x9F, 0x00, 0x7F, 0x00, 0x54, 0x00 }, 11);
|
||||
boe_check_write(dsi, (u8[]){ 0xC2, 0x17, 0x09, 0x08, 0x89, 0x08, 0x11, 0x22, 0x20, 0x44, 0xFF, 0x18, 0x00 }, 13);
|
||||
boe_check_write(dsi, (u8[]){ 0xC3, 0x86, 0x46, 0x05, 0x05, 0x1C, 0x1C, 0x1D, 0x1D, 0x02, 0x1F, 0x1F, 0x1E, 0x1E, 0x0F, 0x0F, 0x0D, 0x0D, 0x13, 0x13, 0x11, 0x11, 0x00 }, 23);
|
||||
boe_check_write(dsi, (u8[]){ 0xC4, 0x07, 0x07, 0x04, 0x04, 0x1C, 0x1C, 0x1D, 0x1D, 0x02, 0x1F, 0x1F, 0x1E, 0x1E, 0x0E, 0x0E, 0x0C, 0x0C, 0x12, 0x12, 0x10, 0x10, 0x00 }, 23);
|
||||
boe_check_write(dsi, (u8[]){ 0xC6, 0x2A, 0x2A }, 3);
|
||||
boe_check_write(dsi, (u8[]){ 0xC8, 0x21, 0x00, 0x31, 0x42, 0x34, 0x16 }, 7);
|
||||
boe_check_write(dsi, (u8[]){ 0xCA, 0xCB, 0x43 }, 3);
|
||||
boe_check_write(dsi, (u8[]){ 0xCD, 0x0E, 0x4B, 0x4B, 0x20, 0x19, 0x6B, 0x06, 0xB3 }, 9);
|
||||
boe_check_write(dsi, (u8[]){ 0xD2, 0xE3, 0x2B, 0x38, 0x00 }, 5);
|
||||
boe_check_write(dsi, (u8[]){ 0xD4, 0x00, 0x01, 0x00, 0x0E, 0x04, 0x44, 0x08, 0x10, 0x00, 0x00, 0x00 }, 12);
|
||||
boe_check_write(dsi, (u8[]){ 0xE6, 0x80, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, 9);
|
||||
boe_check_write(dsi, (u8[]){ 0xF0, 0x12, 0x03, 0x20, 0x00, 0xFF }, 6);
|
||||
boe_check_write(dsi, (u8[]){ 0xF3, 0x00 }, 2);
|
||||
|
||||
msleep(120);
|
||||
|
||||
ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
|
||||
if (ret) {
|
||||
dev_err(panel->dev, "Failed to exit sleep mode: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
msleep(120);
|
||||
|
||||
ret = mipi_dsi_dcs_set_display_on(dsi);
|
||||
if (ret) {
|
||||
dev_err(panel->dev, "Failed to set display on: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
msleep(120);
|
||||
|
||||
ctx->enabled = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_STARFIVE_DSI
|
||||
static const struct drm_display_mode boe_default_mode = {
|
||||
.clock = 66000,
|
||||
|
||||
.hdisplay = 800,
|
||||
.hsync_start = 800 + 44,
|
||||
.hsync_end = 800 + 44 + 5,
|
||||
.htotal = 800 + 44 + 5 + 5,
|
||||
|
||||
.vdisplay = 1280,
|
||||
.vsync_start = 1280 + 5,
|
||||
.vsync_end = 1280 + 5 + 5,
|
||||
.vtotal = 1280 + 5 + 5 + 5,
|
||||
|
||||
.type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
|
||||
|
||||
.width_mm = 136,
|
||||
.height_mm = 216,
|
||||
};
|
||||
#else
|
||||
static const struct drm_display_mode boe_default_mode = {
|
||||
.clock = 73500,
|
||||
|
||||
|
@ -157,13 +227,18 @@ static const struct drm_display_mode boe_default_mode = {
|
|||
.vtotal = 1280 + 2 + 4 + 12,
|
||||
|
||||
.type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
|
||||
|
||||
.width_mm = 136,
|
||||
.height_mm = 216,
|
||||
};
|
||||
#endif
|
||||
|
||||
static int boe_get_modes(struct drm_panel *panel,
|
||||
struct drm_connector *connector)
|
||||
{
|
||||
struct boe *ctx = panel_to_boe(panel);
|
||||
struct drm_display_mode *mode;
|
||||
int ret;
|
||||
|
||||
mode = drm_mode_duplicate(connector->dev, &boe_default_mode);
|
||||
if (!mode) {
|
||||
|
@ -175,29 +250,31 @@ static int boe_get_modes(struct drm_panel *panel,
|
|||
}
|
||||
|
||||
drm_mode_set_name(mode);
|
||||
drm_mode_probed_add(connector, mode);
|
||||
|
||||
connector->display_info.bpc = 8;
|
||||
connector->display_info.width_mm = 216;
|
||||
connector->display_info.height_mm = 135;
|
||||
connector->display_info.width_mm = mode->width_mm;
|
||||
connector->display_info.height_mm = mode->height_mm;
|
||||
|
||||
drm_mode_probed_add(connector, mode);
|
||||
|
||||
/*
|
||||
* TODO: Remove once all drm drivers call
|
||||
* drm_connector_set_orientation_from_panel()
|
||||
*/
|
||||
drm_connector_set_panel_orientation(connector, ctx->orientation);
|
||||
ret = drm_connector_set_panel_orientation(connector, ctx->orientation);
|
||||
if (ret) {
|
||||
dev_err(panel->dev, "Failed to set panel orientation: %d\n", ret);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0))
|
||||
static enum drm_panel_orientation boe_get_orientation(struct drm_panel *panel)
|
||||
{
|
||||
struct boe *ctx = panel_to_boe(panel);
|
||||
|
||||
dev_info(panel->dev, "get orientation %d\n", ctx->orientation);
|
||||
return ctx->orientation;
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct drm_panel_funcs boe_funcs = {
|
||||
.disable = boe_disable,
|
||||
|
@ -205,9 +282,7 @@ static const struct drm_panel_funcs boe_funcs = {
|
|||
.prepare = boe_prepare,
|
||||
.enable = boe_enable,
|
||||
.get_modes = boe_get_modes,
|
||||
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0))
|
||||
.get_orientation = boe_get_orientation,
|
||||
#endif
|
||||
};
|
||||
|
||||
static int boe_dsi_probe(struct mipi_dsi_device *dsi)
|
||||
|
@ -238,32 +313,43 @@ static int boe_dsi_probe(struct mipi_dsi_device *dsi)
|
|||
return dev_err_probe(&dsi->dev, PTR_ERR(ctx->enable),
|
||||
"Failed to get enable GPIO\n");
|
||||
|
||||
/* PineTabV doesn't have the reset signal hooked up, so ignore errors */
|
||||
ctx->reset = devm_gpiod_get(&dsi->dev, "reset", GPIOD_OUT_HIGH);
|
||||
if (IS_ERR(ctx->reset))
|
||||
return dev_err_probe(&dsi->dev, PTR_ERR(ctx->reset),
|
||||
"Failed to get reset GPIO\n");
|
||||
|
||||
ret = of_drm_get_panel_orientation(dsi->dev.of_node, &ctx->orientation);
|
||||
if (ret)
|
||||
return dev_err_probe(&dsi->dev, ret,
|
||||
"Failed to get orientation\n");
|
||||
|
||||
|
||||
ret = drm_panel_of_backlight(&ctx->panel);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (ret)
|
||||
return dev_err_probe(&dsi->dev, ret,
|
||||
"Failed to get backlight\n");
|
||||
|
||||
drm_panel_add(&ctx->panel);
|
||||
|
||||
dsi->lanes = 4;
|
||||
dsi->format = MIPI_DSI_FMT_RGB888;
|
||||
dsi->mode_flags = MIPI_DSI_MODE_VIDEO_BURST |
|
||||
MIPI_DSI_MODE_NO_EOT_PACKET |
|
||||
MIPI_DSI_MODE_LPM;
|
||||
|
||||
#ifdef CONFIG_STARFIVE_DSI
|
||||
dsi->mode_flags = MIPI_DSI_MODE_LPM
|
||||
| MIPI_DSI_MODE_VIDEO |
|
||||
MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
|
||||
MIPI_DSI_CLOCK_NON_CONTINUOUS;
|
||||
dsi->channel = 3;
|
||||
dsi->hs_rate = 400000000;
|
||||
#else
|
||||
dsi->mode_flags = MIPI_DSI_MODE_NO_EOT_PACKET |
|
||||
MIPI_DSI_MODE_LPM |
|
||||
MIPI_DSI_MODE_VIDEO_BURST;
|
||||
#endif
|
||||
|
||||
ret = mipi_dsi_attach(dsi);
|
||||
if (ret < 0) {
|
||||
drm_panel_remove(&ctx->panel);
|
||||
return ret;
|
||||
return dev_err_probe(&dsi->dev, ret,
|
||||
"Failed to attach DSI\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -299,6 +385,7 @@ static struct mipi_dsi_driver boe_driver = {
|
|||
};
|
||||
module_mipi_dsi_driver(boe_driver);
|
||||
|
||||
|
||||
MODULE_AUTHOR("Alexander Warnecke <awarnecke002@hotmail.com>");
|
||||
MODULE_DESCRIPTION("BOE TH101MB31IG002-28A MIPI-DSI LCD panel");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
Loading…
Add table
Reference in a new issue