blob: cef5846d7929429f910c7167a5b43ca5cf2276f9 [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "lcd.h"
#include <fuchsia/hardware/platform/device/c/banjo.h>
#include <lib/ddk/debug.h>
#include <lib/device-protocol/display-panel.h>
#include <lib/mipi-dsi/mipi-dsi.h>
#include <ddktl/device.h>
#include "common.h"
#define READ_DISPLAY_ID_CMD (0x04)
#define READ_DISPLAY_ID_LEN (0x03)
namespace amlogic_display {
namespace {
#include "initcodes-inl.h"
} // namespace
zx_status_t Lcd::GetDisplayId() {
uint8_t txcmd = READ_DISPLAY_ID_CMD;
uint8_t rsp[READ_DISPLAY_ID_LEN];
zx_status_t status = ZX_OK;
// Create the command using mipi-dsi library
mipi_dsi_cmd_t cmd;
status = mipi_dsi::MipiDsi::CreateCommand(&txcmd, 1, rsp, READ_DISPLAY_ID_LEN, COMMAND_GEN, &cmd);
if (status == ZX_OK) {
if ((status = dsiimpl_.SendCmd(&cmd, 1)) != ZX_OK) {
DISP_ERROR("Could not read out Display ID\n");
return status;
}
DISP_INFO("Display ID: 0x%x, 0x%x, 0x%x\n", rsp[0], rsp[1], rsp[2]);
} else {
DISP_ERROR("Invalid command (%d)\n", status);
}
return status;
}
// This function write DSI commands based on the input buffer.
zx_status_t Lcd::LoadInitTable(const uint8_t* buffer, size_t size) {
zx_status_t status = ZX_OK;
size_t i;
i = 0;
bool isDCS = false;
while (i < size) {
switch (buffer[i]) {
case DELAY_CMD:
zx_nanosleep(zx_deadline_after(ZX_MSEC(buffer[i + 1])));
i += 2;
break;
case DCS_CMD:
isDCS = true;
__FALLTHROUGH;
case GEN_CMD:
default:
// Create the command using mipi-dsi library
mipi_dsi_cmd_t cmd;
status =
mipi_dsi::MipiDsi::CreateCommand(&buffer[i + 2], buffer[i + 1], NULL, 0, isDCS, &cmd);
if (status == ZX_OK) {
if ((status = dsiimpl_.SendCmd(&cmd, 1)) != ZX_OK) {
DISP_ERROR("Error loading LCD init table. Aborting %d\n", status);
return status;
}
} else {
DISP_ERROR("Invalid command (%d). Skipping\n", status);
}
// increment by payload length
i += buffer[i + 1] + 2; // the 2 includes current plus size field
isDCS = false;
break;
}
}
return status;
}
zx_status_t Lcd::Disable() {
ZX_DEBUG_ASSERT(initialized_);
if (!enabled_) {
return ZX_OK;
}
// First send shutdown command to LCD
enabled_ = false;
return LoadInitTable(lcd_shutdown_sequence, sizeof(lcd_shutdown_sequence));
}
zx_status_t Lcd::Enable() {
ZX_DEBUG_ASSERT(initialized_);
if (enabled_) {
return ZX_OK;
}
// reset LCD panel via GPIO according to vendor doc
gpio_.ConfigOut(1);
gpio_.Write(1);
zx_nanosleep(zx_deadline_after(ZX_MSEC(30)));
gpio_.Write(0);
zx_nanosleep(zx_deadline_after(ZX_MSEC(100)));
gpio_.Write(1);
zx_nanosleep(zx_deadline_after(ZX_MSEC(50)));
// check status
if (GetDisplayId() != ZX_OK) {
DISP_ERROR("Cannot communicate with LCD Panel!\n");
return ZX_ERR_TIMED_OUT;
}
zx_nanosleep(zx_deadline_after(ZX_USEC(10)));
// load table
zx_status_t status;
if (panel_type_ == PANEL_TV070WSM_FT) {
status = LoadInitTable(lcd_init_sequence_TV070WSM_FT, sizeof(lcd_init_sequence_TV070WSM_FT));
} else if (panel_type_ == PANEL_P070ACB_FT) {
status = LoadInitTable(lcd_init_sequence_P070ACB_FT, sizeof(lcd_init_sequence_P070ACB_FT));
} else if (panel_type_ == PANEL_TV101WXM_FT) {
status = LoadInitTable(lcd_init_sequence_TV101WXM_FT, sizeof(lcd_init_sequence_TV101WXM_FT));
} else if (panel_type_ == PANEL_G101B158_FT) {
status = LoadInitTable(lcd_init_sequence_G101B158_FT, sizeof(lcd_init_sequence_G101B158_FT));
} else if (panel_type_ == PANEL_TV080WXM_FT) {
status = LoadInitTable(lcd_init_sequence_TV080WXM_FT, sizeof(lcd_init_sequence_TV080WXM_FT));
} else if (panel_type_ == PANEL_TV101WXM_FT_9365) {
status = LoadInitTable(lcd_init_sequence_TV101WXM_FT_9365,
sizeof(lcd_init_sequence_TV101WXM_FT_9365));
} else if (panel_type_ == PANEL_TV070WSM_FT_9365) {
status = LoadInitTable(lcd_init_sequence_TV070WSM_FT_9365,
sizeof(lcd_init_sequence_TV070WSM_FT_9365));
} else if (panel_type_ == PANEL_KD070D82_FT ||
panel_type_ == PANEL_KD070D82_FT_9365) {
status = LoadInitTable(lcd_init_sequence_KD070D82_FT_9365,
sizeof(lcd_init_sequence_KD070D82_FT_9365));
} else {
DISP_ERROR("Unsupported panel detected!\n");
status = ZX_ERR_NOT_SUPPORTED;
}
if (status == ZX_OK) {
// LCD is on now.
enabled_ = true;
}
return status;
}
zx_status_t Lcd::Init(ddk::DsiImplProtocolClient dsiimpl, ddk::GpioProtocolClient gpio) {
if (initialized_) {
return ZX_OK;
}
dsiimpl_ = dsiimpl;
if (!gpio.is_valid()) {
DISP_ERROR("Could not obtain GPIO protocol\n");
return ZX_ERR_NO_RESOURCES;
}
gpio_ = gpio;
initialized_ = true;
if (kBootloaderDisplayEnabled) {
DISP_INFO("LCD Enabled by Bootloader. Disabling before proceeding\n");
enabled_ = true;
Disable();
}
return ZX_OK;
}
} // namespace amlogic_display