blob: 4c5fd983433056397dbb68a613b307a73766536d [file] [log] [blame]
/* Copyright (c) 2017-2018, 2020, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include <spi_qup.h>
#include <msm_panel.h>
#include <target/display.h>
#include <platform/gpio.h>
#include <dev/gpio.h>
#include <platform/timer.h>
#include "mdss_spi.h"
#define SUCCESS 0
#define FAIL 1
static struct qup_spi_dev *dev = NULL;
#if QM215_MDSS_SPI
static struct gpio_pin spi_dc_gpio = {
"msmgpio", 64, 3, 1, 0, 1
};
#define SPI_BLSP_ID 1
#define SPI_QUP_ID 2
#endif
static int mdss_spi_write_cmd(const unsigned char *buf)
{
int ret = 0;
if (!dev) {
dprintf(CRITICAL, "SPI has not been initialized\n");
return -ENODEV;
}
dev->bytes_per_word = 1;
dev->bit_shift_en = 1;
gpio_set(spi_dc_gpio.pin_id, 0);
ret = spi_qup_write(dev, buf, 1);
gpio_set(spi_dc_gpio.pin_id, 2);
if (ret)
dprintf(CRITICAL, "Send SPI command to panel failed\n");
return ret;
}
static int mdss_spi_write_data(const unsigned char *buf, size_t len)
{
int ret = 0;
if (!dev) {
dprintf(CRITICAL, "SPI has not been initialized\n");
return -ENODEV;
}
dev->bytes_per_word = 1;
dev->bit_shift_en = 1;
gpio_set(spi_dc_gpio.pin_id, 2);
ret = spi_qup_write(dev, buf, len);
if (ret)
dprintf(CRITICAL, "Send SPI parameters to panel failed\n");
return ret;
}
static int mdss_spi_write_frame(const unsigned char *buf, size_t len)
{
int ret = 0;
if (!dev) {
dprintf(CRITICAL, "SPI has not been initialized\n");
return -ENODEV;
}
dev->bytes_per_word = 2;
dev->bit_shift_en = 1;
dev->unpack_en = 0;
gpio_set(spi_dc_gpio.pin_id, 2);
ret = spi_qup_write(dev, buf, len);
return ret;
}
void spi_read_panel_data(unsigned char *buf, int len)
{
int ret = 0;
if (!dev) {
dprintf(CRITICAL, "SPI has not been initialized\n");
return;
}
dev->bytes_per_word = 1;
dev->bit_shift_en = 1;
gpio_set(spi_dc_gpio.pin_id, 0);
ret = spi_qup_read(dev, buf, len);
gpio_set(spi_dc_gpio.pin_id, 2);
if (ret)
dprintf(CRITICAL, "Send SPI command to panel failed\n");
return;
}
int spi_check_panel_id(struct msm_panel_info *pinfo)
{
int i = 0;
int len;
int ret = SUCCESS;
unsigned char *buf;
if (!pinfo->spi.signature || !pinfo->spi.signature_len)
return ret;
len = pinfo->spi.signature_len;
buf = (unsigned char*) malloc(len + 1);
mdss_spi_write_cmd(pinfo->spi.signature_addr);
spi_read_panel_data(buf, len + 1);
for (i = 0; i < len; i++) {
/* left shift a bit to match SPI panel timming */
if(pinfo->spi.signature[i] !=
(((buf[i] << 1) | (buf[i + 1] >> 7)) & 0xFF)) {
ret = FAIL;
break;
}
}
free(buf);
return ret;
}
int mdss_spi_init(void)
{
if (!dev) {
dev = qup_blsp_spi_init(SPI_BLSP_ID, SPI_QUP_ID);
if (!dev) {
dprintf(CRITICAL, "Failed initializing SPI\n");
return -ENODEV;
}
}
gpio_tlmm_config(spi_dc_gpio.pin_id, 0, spi_dc_gpio.pin_direction,
spi_dc_gpio.pin_pull, spi_dc_gpio.pin_strength,
spi_dc_gpio.pin_state);
return SUCCESS;
}
int mdss_spi_panel_init(struct msm_panel_info *pinfo)
{
int cmd_count = 0;
while (cmd_count < pinfo->spi.num_of_panel_cmds) {
if (pinfo->spi.panel_cmds[cmd_count].cmds_post_tg){
cmd_count ++;
continue;
}
mdss_spi_write_cmd((unsigned char *) pinfo->spi.panel_cmds[cmd_count].payload);
if (pinfo->spi.panel_cmds[cmd_count].size > 1)
mdss_spi_write_data(
(unsigned char *) pinfo->spi.panel_cmds[cmd_count].payload + 1,
pinfo->spi.panel_cmds[cmd_count].size - 1);
if (pinfo->spi.panel_cmds[cmd_count].wait)
mdelay(pinfo->spi.panel_cmds[cmd_count].wait);
cmd_count ++;
}
return SUCCESS;
}
int mdss_spi_on(struct msm_panel_info *pinfo, struct fbcon_config *fb)
{
int buf_size = 0;
int ret = 0;
buf_size = fb->width * fb->height * (fb->bpp / 8);
ret = mdss_spi_write_frame(fb->base, buf_size);
if (ret)
dprintf(CRITICAL, "Send SPI frame data to panel failed\n");
return ret;
}
int mdss_spi_cmd_post_on(struct msm_panel_info *pinfo)
{
int cmd_count = 0;
char *payload;
if (!dev) {
dprintf(CRITICAL, "SPI has not been initialized\n");
return -ENODEV;
}
while (cmd_count < pinfo->spi.num_of_panel_cmds) {
if (pinfo->spi.panel_cmds[cmd_count].cmds_post_tg) {
payload = pinfo->spi.panel_cmds[cmd_count].payload;
mdss_spi_write_cmd((unsigned char *) payload);
if (pinfo->spi.panel_cmds[cmd_count].size > 1)
mdss_spi_write_data((unsigned char *) payload + 1,
pinfo->spi.panel_cmds[cmd_count].size
- 1);
if (pinfo->spi.panel_cmds[cmd_count].wait)
mdelay(pinfo->spi.panel_cmds[cmd_count].wait);
}
cmd_count ++;
}
return SUCCESS;
}