blob: 9b96a5c9abcdf77816f76ce6aac58b3c0967a697 [file] [log] [blame]
/*
* Copyright © 2010 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
* Authors:
* Jackie Li<yaodong.li@intel.com>
*/
#include <linux/freezer.h>
#include "mdfld_dsi_output.h"
#include "mdfld_dsi_pkg_sender.h"
#include "mdfld_dsi_dbi.h"
#include "mdfld_dsi_dpi.h"
#define MDFLD_DSI_DBI_FIFO_TIMEOUT 100
#define MDFLD_DSI_MAX_RETURN_PACKET_SIZE 512
#define MDFLD_DSI_READ_MAX_COUNT 5000
static const char * const dsi_errors[] = {
"RX SOT Error",
"RX SOT Sync Error",
"RX EOT Sync Error",
"RX Escape Mode Entry Error",
"RX LP TX Sync Error",
"RX HS Receive Timeout Error",
"RX False Control Error",
"RX ECC Single Bit Error",
"RX ECC Multibit Error",
"RX Checksum Error",
"RX DSI Data Type Not Recognised",
"RX DSI VC ID Invalid",
"TX False Control Error",
"TX ECC Single Bit Error",
"TX ECC Multibit Error",
"TX Checksum Error",
"TX DSI Data Type Not Recognised",
"TX DSI VC ID invalid",
"High Contention",
"Low contention",
"DPI FIFO Under run",
"HS TX Timeout",
"LP RX Timeout",
"Turn Around ACK Timeout",
"ACK With No Error",
"RX Invalid TX Length",
"RX Prot Violation",
"HS Generic Write FIFO Full",
"LP Generic Write FIFO Full",
"Generic Read Data Avail",
"Special Packet Sent",
"Tearing Effect",
};
static int wait_for_gen_fifo_empty(struct mdfld_dsi_pkg_sender *sender,
u32 mask)
{
struct drm_device *dev = sender->dev;
u32 gen_fifo_stat_reg = sender->mipi_gen_fifo_stat_reg;
int retry = 0xffff;
while (retry--) {
if ((mask & REG_READ(gen_fifo_stat_reg)) == mask)
return 0;
udelay(100);
}
dev_err(dev->dev, "fifo is NOT empty 0x%08x\n",
REG_READ(gen_fifo_stat_reg));
return -EIO;
}
static int wait_for_all_fifos_empty(struct mdfld_dsi_pkg_sender *sender)
{
return wait_for_gen_fifo_empty(sender, (1 << 2) | (1 << 10) | (1 << 18)
| (1 << 26) | (1 << 27) | (1 << 28));
}
static int wait_for_lp_fifos_empty(struct mdfld_dsi_pkg_sender *sender)
{
return wait_for_gen_fifo_empty(sender, (1 << 10) | (1 << 26));
}
static int wait_for_hs_fifos_empty(struct mdfld_dsi_pkg_sender *sender)
{
return wait_for_gen_fifo_empty(sender, (1 << 2) | (1 << 18));
}
static int wait_for_dbi_fifo_empty(struct mdfld_dsi_pkg_sender *sender)
{
return wait_for_gen_fifo_empty(sender, (1 << 27));
}
static int handle_dsi_error(struct mdfld_dsi_pkg_sender *sender, u32 mask)
{
u32 intr_stat_reg = sender->mipi_intr_stat_reg;
struct drm_device *dev = sender->dev;
switch (mask) {
case (1 << 0):
case (1 << 1):
case (1 << 2):
case (1 << 3):
case (1 << 4):
case (1 << 5):
case (1 << 6):
case (1 << 7):
case (1 << 8):
case (1 << 9):
case (1 << 10):
case (1 << 11):
case (1 << 12):
case (1 << 13):
break;
case (1 << 14):
/*wait for all fifo empty*/
/*wait_for_all_fifos_empty(sender)*/;
break;
case (1 << 15):
break;
case (1 << 16):
break;
case (1 << 17):
break;
case (1 << 18):
case (1 << 19):
/*wait for contention recovery time*/
/*mdelay(10);*/
/*wait for all fifo empty*/
if (0)
wait_for_all_fifos_empty(sender);
break;
case (1 << 20):
break;
case (1 << 21):
/*wait for all fifo empty*/
/*wait_for_all_fifos_empty(sender);*/
break;
case (1 << 22):
break;
case (1 << 23):
case (1 << 24):
case (1 << 25):
case (1 << 26):
case (1 << 27):
/* HS Gen fifo full */
REG_WRITE(intr_stat_reg, mask);
wait_for_hs_fifos_empty(sender);
break;
case (1 << 28):
/* LP Gen fifo full\n */
REG_WRITE(intr_stat_reg, mask);
wait_for_lp_fifos_empty(sender);
break;
case (1 << 29):
case (1 << 30):
case (1 << 31):
break;
}
if (mask & REG_READ(intr_stat_reg))
dev_warn(dev->dev, "Cannot clean interrupt 0x%08x\n", mask);
return 0;
}
static int dsi_error_handler(struct mdfld_dsi_pkg_sender *sender)
{
struct drm_device *dev = sender->dev;
u32 intr_stat_reg = sender->mipi_intr_stat_reg;
u32 mask;
u32 intr_stat;
int i;
int err = 0;
intr_stat = REG_READ(intr_stat_reg);
for (i = 0; i < 32; i++) {
mask = (0x00000001UL) << i;
if (intr_stat & mask) {
dev_dbg(dev->dev, "[DSI]: %s\n", dsi_errors[i]);
err = handle_dsi_error(sender, mask);
if (err)
dev_err(dev->dev, "Cannot handle error\n");
}
}
return err;
}
static inline int dbi_cmd_sent(struct mdfld_dsi_pkg_sender *sender)
{
struct drm_device *dev = sender->dev;
u32 retry = 0xffff;
u32 dbi_cmd_addr_reg = sender->mipi_cmd_addr_reg;
/* Query the command execution status */
while (retry--) {
if (!(REG_READ(dbi_cmd_addr_reg) & (1 << 0)))
break;
}
if (!retry) {
dev_err(dev->dev, "Timeout waiting for DBI Command status\n");
return -EAGAIN;
}
return 0;
}
/*
* NOTE: this interface is abandoned expect for write_mem_start DCS
* other DCS are sent via generic pkg interfaces
*/
static int send_dcs_pkg(struct mdfld_dsi_pkg_sender *sender,
struct mdfld_dsi_pkg *pkg)
{
struct drm_device *dev = sender->dev;
struct mdfld_dsi_dcs_pkg *dcs_pkg = &pkg->pkg.dcs_pkg;
u32 dbi_cmd_len_reg = sender->mipi_cmd_len_reg;
u32 dbi_cmd_addr_reg = sender->mipi_cmd_addr_reg;
u32 cb_phy = sender->dbi_cb_phy;
u32 index = 0;
u8 *cb = (u8 *)sender->dbi_cb_addr;
int i;
int ret;
if (!sender->dbi_pkg_support) {
dev_err(dev->dev, "Trying to send DCS on a non DBI output, abort!\n");
return -ENOTSUPP;
}
/*wait for DBI fifo empty*/
wait_for_dbi_fifo_empty(sender);
*(cb + (index++)) = dcs_pkg->cmd;
if (dcs_pkg->param_num) {
for (i = 0; i < dcs_pkg->param_num; i++)
*(cb + (index++)) = *(dcs_pkg->param + i);
}
REG_WRITE(dbi_cmd_len_reg, (1 + dcs_pkg->param_num));
REG_WRITE(dbi_cmd_addr_reg,
(cb_phy << CMD_MEM_ADDR_OFFSET)
| (1 << 0)
| ((dcs_pkg->data_src == CMD_DATA_SRC_PIPE) ? (1 << 1) : 0));
ret = dbi_cmd_sent(sender);
if (ret) {
dev_err(dev->dev, "command 0x%x not complete\n", dcs_pkg->cmd);
return -EAGAIN;
}
return 0;
}
static int __send_short_pkg(struct mdfld_dsi_pkg_sender *sender,
struct mdfld_dsi_pkg *pkg)
{
struct drm_device *dev = sender->dev;
u32 hs_gen_ctrl_reg = sender->mipi_hs_gen_ctrl_reg;
u32 lp_gen_ctrl_reg = sender->mipi_lp_gen_ctrl_reg;
u32 gen_ctrl_val = 0;
struct mdfld_dsi_gen_short_pkg *short_pkg = &pkg->pkg.short_pkg;
gen_ctrl_val |= short_pkg->cmd << MCS_COMMANDS_POS;
gen_ctrl_val |= 0 << DCS_CHANNEL_NUMBER_POS;
gen_ctrl_val |= pkg->pkg_type;
gen_ctrl_val |= short_pkg->param << MCS_PARAMETER_POS;
if (pkg->transmission_type == MDFLD_DSI_HS_TRANSMISSION) {
/* wait for hs fifo empty */
/* wait_for_hs_fifos_empty(sender); */
/* Send pkg */
REG_WRITE(hs_gen_ctrl_reg, gen_ctrl_val);
} else if (pkg->transmission_type == MDFLD_DSI_LP_TRANSMISSION) {
/* wait_for_lp_fifos_empty(sender); */
/* Send pkg*/
REG_WRITE(lp_gen_ctrl_reg, gen_ctrl_val);
} else {
dev_err(dev->dev, "Unknown transmission type %d\n",
pkg->transmission_type);
return -EINVAL;
}
return 0;
}
static int __send_long_pkg(struct mdfld_dsi_pkg_sender *sender,
struct mdfld_dsi_pkg *pkg)
{
struct drm_device *dev = sender->dev;
u32 hs_gen_ctrl_reg = sender->mipi_hs_gen_ctrl_reg;
u32 hs_gen_data_reg = sender->mipi_hs_gen_data_reg;
u32 lp_gen_ctrl_reg = sender->mipi_lp_gen_ctrl_reg;
u32 lp_gen_data_reg = sender->mipi_lp_gen_data_reg;
u32 gen_ctrl_val = 0;
u32 *dp;
int i;
struct mdfld_dsi_gen_long_pkg *long_pkg = &pkg->pkg.long_pkg;
dp = long_pkg->data;
/*
* Set up word count for long pkg
* FIXME: double check word count field.
* currently, using the byte counts of the payload as the word count.
* ------------------------------------------------------------
* | DI | WC | ECC| PAYLOAD |CHECKSUM|
* ------------------------------------------------------------
*/
gen_ctrl_val |= (long_pkg->len << 2) << WORD_COUNTS_POS;
gen_ctrl_val |= 0 << DCS_CHANNEL_NUMBER_POS;
gen_ctrl_val |= pkg->pkg_type;
if (pkg->transmission_type == MDFLD_DSI_HS_TRANSMISSION) {
/* Wait for hs ctrl and data fifos to be empty */
/* wait_for_hs_fifos_empty(sender); */
for (i = 0; i < long_pkg->len; i++)
REG_WRITE(hs_gen_data_reg, *(dp + i));
REG_WRITE(hs_gen_ctrl_reg, gen_ctrl_val);
} else if (pkg->transmission_type == MDFLD_DSI_LP_TRANSMISSION) {
/* wait_for_lp_fifos_empty(sender); */
for (i = 0; i < long_pkg->len; i++)
REG_WRITE(lp_gen_data_reg, *(dp + i));
REG_WRITE(lp_gen_ctrl_reg, gen_ctrl_val);
} else {
dev_err(dev->dev, "Unknown transmission type %d\n",
pkg->transmission_type);
return -EINVAL;
}
return 0;
}
static int send_mcs_short_pkg(struct mdfld_dsi_pkg_sender *sender,
struct mdfld_dsi_pkg *pkg)
{
return __send_short_pkg(sender, pkg);
}
static int send_mcs_long_pkg(struct mdfld_dsi_pkg_sender *sender,
struct mdfld_dsi_pkg *pkg)
{
return __send_long_pkg(sender, pkg);
}
static int send_gen_short_pkg(struct mdfld_dsi_pkg_sender *sender,
struct mdfld_dsi_pkg *pkg)
{
return __send_short_pkg(sender, pkg);
}
static int send_gen_long_pkg(struct mdfld_dsi_pkg_sender *sender,
struct mdfld_dsi_pkg *pkg)
{
return __send_long_pkg(sender, pkg);
}
static int send_pkg_prepare(struct mdfld_dsi_pkg_sender *sender,
struct mdfld_dsi_pkg *pkg)
{
u8 cmd;
u8 *data;
switch (pkg->pkg_type) {
case MDFLD_DSI_PKG_DCS:
cmd = pkg->pkg.dcs_pkg.cmd;
break;
case MDFLD_DSI_PKG_MCS_SHORT_WRITE_0:
case MDFLD_DSI_PKG_MCS_SHORT_WRITE_1:
cmd = pkg->pkg.short_pkg.cmd;
break;
case MDFLD_DSI_PKG_MCS_LONG_WRITE:
data = (u8 *)pkg->pkg.long_pkg.data;
cmd = *data;
break;
default:
return 0;
}
/* This prevents other package sending while doing msleep */
sender->status = MDFLD_DSI_PKG_SENDER_BUSY;
/* Check panel mode v.s. sending command */
if ((sender->panel_mode & MDFLD_DSI_PANEL_MODE_SLEEP) &&
cmd != exit_sleep_mode) {
dev_err(sender->dev->dev,
"sending 0x%x when panel sleep in\n", cmd);
sender->status = MDFLD_DSI_PKG_SENDER_FREE;
return -EINVAL;
}
/* Wait for 120 milliseconds in case exit_sleep_mode just be sent */
if (cmd == DCS_ENTER_SLEEP_MODE) {
/*TODO: replace it with msleep later*/
mdelay(120);
}
return 0;
}
static int send_pkg_done(struct mdfld_dsi_pkg_sender *sender,
struct mdfld_dsi_pkg *pkg)
{
u8 cmd;
u8 *data;
switch (pkg->pkg_type) {
case MDFLD_DSI_PKG_DCS:
cmd = pkg->pkg.dcs_pkg.cmd;
break;
case MDFLD_DSI_PKG_MCS_SHORT_WRITE_0:
case MDFLD_DSI_PKG_MCS_SHORT_WRITE_1:
cmd = pkg->pkg.short_pkg.cmd;
break;
case MDFLD_DSI_PKG_MCS_LONG_WRITE:
data = (u8 *)pkg->pkg.long_pkg.data;
cmd = *data;
break;
default:
return 0;
}
/* Update panel status */
if (cmd == DCS_ENTER_SLEEP_MODE) {
sender->panel_mode |= MDFLD_DSI_PANEL_MODE_SLEEP;
/*TODO: replace it with msleep later*/
mdelay(120);
} else if (cmd == DCS_EXIT_SLEEP_MODE) {
sender->panel_mode &= ~MDFLD_DSI_PANEL_MODE_SLEEP;
/*TODO: replace it with msleep later*/
mdelay(120);
} else if (unlikely(cmd == DCS_SOFT_RESET)) {
/*TODO: replace it with msleep later*/
mdelay(5);
}
sender->status = MDFLD_DSI_PKG_SENDER_FREE;
return 0;
}
static int do_send_pkg(struct mdfld_dsi_pkg_sender *sender,
struct mdfld_dsi_pkg *pkg)
{
int ret;
if (sender->status == MDFLD_DSI_PKG_SENDER_BUSY) {
dev_err(sender->dev->dev, "sender is busy\n");
return -EAGAIN;
}
ret = send_pkg_prepare(sender, pkg);
if (ret) {
dev_err(sender->dev->dev, "send_pkg_prepare error\n");
return ret;
}
switch (pkg->pkg_type) {
case MDFLD_DSI_PKG_DCS:
ret = send_dcs_pkg(sender, pkg);
break;
case MDFLD_DSI_PKG_GEN_SHORT_WRITE_0:
case MDFLD_DSI_PKG_GEN_SHORT_WRITE_1:
case MDFLD_DSI_PKG_GEN_SHORT_WRITE_2:
case MDFLD_DSI_PKG_GEN_READ_0:
case MDFLD_DSI_PKG_GEN_READ_1:
case MDFLD_DSI_PKG_GEN_READ_2:
ret = send_gen_short_pkg(sender, pkg);
break;
case MDFLD_DSI_PKG_GEN_LONG_WRITE:
ret = send_gen_long_pkg(sender, pkg);
break;
case MDFLD_DSI_PKG_MCS_SHORT_WRITE_0:
case MDFLD_DSI_PKG_MCS_SHORT_WRITE_1:
case MDFLD_DSI_PKG_MCS_READ:
ret = send_mcs_short_pkg(sender, pkg);
break;
case MDFLD_DSI_PKG_MCS_LONG_WRITE:
ret = send_mcs_long_pkg(sender, pkg);
break;
default:
dev_err(sender->dev->dev, "Invalid pkg type 0x%x\n",
pkg->pkg_type);
ret = -EINVAL;
}
send_pkg_done(sender, pkg);
return ret;
}
static int send_pkg(struct mdfld_dsi_pkg_sender *sender,
struct mdfld_dsi_pkg *pkg)
{
int err ;
/* Handle DSI error */
err = dsi_error_handler(sender);
if (err) {
dev_err(sender->dev->dev, "Error handling failed\n");
err = -EAGAIN;
goto send_pkg_err;
}
/* Send pkg */
err = do_send_pkg(sender, pkg);
if (err) {
dev_err(sender->dev->dev, "sent pkg failed\n");
err = -EAGAIN;
goto send_pkg_err;
}
/* FIXME: should I query complete and fifo empty here? */
send_pkg_err:
return err;
}
static struct mdfld_dsi_pkg *pkg_sender_get_pkg_locked(
struct mdfld_dsi_pkg_sender *sender)
{
struct mdfld_dsi_pkg *pkg;
if (list_empty(&sender->free_list)) {
dev_err(sender->dev->dev, "No free pkg left\n");
return NULL;
}
pkg = list_first_entry(&sender->free_list, struct mdfld_dsi_pkg, entry);
/* Detach from free list */
list_del_init(&pkg->entry);
return pkg;
}
static void pkg_sender_put_pkg_locked(struct mdfld_dsi_pkg_sender *sender,
struct mdfld_dsi_pkg *pkg)
{
memset(pkg, 0, sizeof(struct mdfld_dsi_pkg));
INIT_LIST_HEAD(&pkg->entry);
list_add_tail(&pkg->entry, &sender->free_list);
}
static int mdfld_dbi_cb_init(struct mdfld_dsi_pkg_sender *sender,
struct psb_gtt *pg, int pipe)
{
unsigned long phys;
void *virt_addr = NULL;
switch (pipe) {
case 0:
/* FIXME: Doesn't this collide with stolen space ? */
phys = pg->gtt_phys_start - 0x1000;
break;
case 2:
phys = pg->gtt_phys_start - 0x800;
break;
default:
dev_err(sender->dev->dev, "Unsupported channel %d\n", pipe);
return -EINVAL;
}
virt_addr = ioremap_nocache(phys, 0x800);
if (!virt_addr) {
dev_err(sender->dev->dev, "Map DBI command buffer error\n");
return -ENOMEM;
}
sender->dbi_cb_phy = phys;
sender->dbi_cb_addr = virt_addr;
return 0;
}
static void mdfld_dbi_cb_destroy(struct mdfld_dsi_pkg_sender *sender)
{
if (sender && sender->dbi_cb_addr)
iounmap(sender->dbi_cb_addr);
}
static void pkg_sender_queue_pkg(struct mdfld_dsi_pkg_sender *sender,
struct mdfld_dsi_pkg *pkg,
int delay)
{
unsigned long flags;
spin_lock_irqsave(&sender->lock, flags);
if (!delay) {
send_pkg(sender, pkg);
pkg_sender_put_pkg_locked(sender, pkg);
} else {
/* Queue it */
list_add_tail(&pkg->entry, &sender->pkg_list);
}
spin_unlock_irqrestore(&sender->lock, flags);
}
static void process_pkg_list(struct mdfld_dsi_pkg_sender *sender)
{
struct mdfld_dsi_pkg *pkg;
unsigned long flags;
spin_lock_irqsave(&sender->lock, flags);
while (!list_empty(&sender->pkg_list)) {
pkg = list_first_entry(&sender->pkg_list,
struct mdfld_dsi_pkg, entry);
send_pkg(sender, pkg);
list_del_init(&pkg->entry);
pkg_sender_put_pkg_locked(sender, pkg);
}
spin_unlock_irqrestore(&sender->lock, flags);
}
static int mdfld_dsi_send_mcs_long(struct mdfld_dsi_pkg_sender *sender,
u32 *data, u32 len, u8 transmission, int delay)
{
struct mdfld_dsi_pkg *pkg;
unsigned long flags;
spin_lock_irqsave(&sender->lock, flags);
pkg = pkg_sender_get_pkg_locked(sender);
spin_unlock_irqrestore(&sender->lock, flags);
if (!pkg) {
dev_err(sender->dev->dev, "No memory\n");
return -ENOMEM;
}
pkg->pkg_type = MDFLD_DSI_PKG_MCS_LONG_WRITE;
pkg->transmission_type = transmission;
pkg->pkg.long_pkg.data = data;
pkg->pkg.long_pkg.len = len;
INIT_LIST_HEAD(&pkg->entry);
pkg_sender_queue_pkg(sender, pkg, delay);
return 0;
}
static int mdfld_dsi_send_mcs_short(struct mdfld_dsi_pkg_sender *sender,
u8 cmd, u8 param, u8 param_num,
u8 transmission,
int delay)
{
struct mdfld_dsi_pkg *pkg;
unsigned long flags;
spin_lock_irqsave(&sender->lock, flags);
pkg = pkg_sender_get_pkg_locked(sender);
spin_unlock_irqrestore(&sender->lock, flags);
if (!pkg) {
dev_err(sender->dev->dev, "No memory\n");
return -ENOMEM;
}
if (param_num) {
pkg->pkg_type = MDFLD_DSI_PKG_MCS_SHORT_WRITE_1;
pkg->pkg.short_pkg.param = param;
} else {
pkg->pkg_type = MDFLD_DSI_PKG_MCS_SHORT_WRITE_0;
pkg->pkg.short_pkg.param = 0;
}
pkg->transmission_type = transmission;
pkg->pkg.short_pkg.cmd = cmd;
INIT_LIST_HEAD(&pkg->entry);
pkg_sender_queue_pkg(sender, pkg, delay);
return 0;
}
static int mdfld_dsi_send_gen_short(struct mdfld_dsi_pkg_sender *sender,
u8 param0, u8 param1, u8 param_num,
u8 transmission,
int delay)
{
struct mdfld_dsi_pkg *pkg;
unsigned long flags;
spin_lock_irqsave(&sender->lock, flags);
pkg = pkg_sender_get_pkg_locked(sender);
spin_unlock_irqrestore(&sender->lock, flags);
if (!pkg) {
dev_err(sender->dev->dev, "No pkg memory\n");
return -ENOMEM;
}
switch (param_num) {
case 0:
pkg->pkg_type = MDFLD_DSI_PKG_GEN_SHORT_WRITE_0;
pkg->pkg.short_pkg.cmd = 0;
pkg->pkg.short_pkg.param = 0;
break;
case 1:
pkg->pkg_type = MDFLD_DSI_PKG_GEN_SHORT_WRITE_1;
pkg->pkg.short_pkg.cmd = param0;
pkg->pkg.short_pkg.param = 0;
break;
case 2:
pkg->pkg_type = MDFLD_DSI_PKG_GEN_SHORT_WRITE_2;
pkg->pkg.short_pkg.cmd = param0;
pkg->pkg.short_pkg.param = param1;
break;
}
pkg->transmission_type = transmission;
INIT_LIST_HEAD(&pkg->entry);
pkg_sender_queue_pkg(sender, pkg, delay);
return 0;
}
static int mdfld_dsi_send_gen_long(struct mdfld_dsi_pkg_sender *sender,
u32 *data, u32 len, u8 transmission, int delay)
{
struct mdfld_dsi_pkg *pkg;
unsigned long flags;
spin_lock_irqsave(&sender->lock, flags);
pkg = pkg_sender_get_pkg_locked(sender);
spin_unlock_irqrestore(&sender->lock, flags);
if (!pkg) {
dev_err(sender->dev->dev, "No pkg memory\n");
return -ENOMEM;
}
pkg->pkg_type = MDFLD_DSI_PKG_GEN_LONG_WRITE;
pkg->transmission_type = transmission;
pkg->pkg.long_pkg.data = data;
pkg->pkg.long_pkg.len = len;
INIT_LIST_HEAD(&pkg->entry);
pkg_sender_queue_pkg(sender, pkg, delay);
return 0;
}
static int __read_panel_data(struct mdfld_dsi_pkg_sender *sender,
struct mdfld_dsi_pkg *pkg,
u32 *data,
u16 len)
{
unsigned long flags;
struct drm_device *dev = sender->dev;
int i;
u32 gen_data_reg;
int retry = MDFLD_DSI_READ_MAX_COUNT;
u8 transmission = pkg->transmission_type;
/*
* do reading.
* 0) send out generic read request
* 1) polling read data avail interrupt
* 2) read data
*/
spin_lock_irqsave(&sender->lock, flags);
REG_WRITE(sender->mipi_intr_stat_reg, 1 << 29);
if ((REG_READ(sender->mipi_intr_stat_reg) & (1 << 29)))
DRM_ERROR("Can NOT clean read data valid interrupt\n");
/*send out read request*/
send_pkg(sender, pkg);
pkg_sender_put_pkg_locked(sender, pkg);
/*polling read data avail interrupt*/
while (retry && !(REG_READ(sender->mipi_intr_stat_reg) & (1 << 29))) {
udelay(100);
retry--;
}
if (!retry) {
spin_unlock_irqrestore(&sender->lock, flags);
return -ETIMEDOUT;
}
REG_WRITE(sender->mipi_intr_stat_reg, (1 << 29));
/*read data*/
if (transmission == MDFLD_DSI_HS_TRANSMISSION)
gen_data_reg = sender->mipi_hs_gen_data_reg;
else if (transmission == MDFLD_DSI_LP_TRANSMISSION)
gen_data_reg = sender->mipi_lp_gen_data_reg;
else {
DRM_ERROR("Unknown transmission");
spin_unlock_irqrestore(&sender->lock, flags);
return -EINVAL;
}
for (i=0; i<len; i++)
*(data + i) = REG_READ(gen_data_reg);
spin_unlock_irqrestore(&sender->lock, flags);
return 0;
}
static int mdfld_dsi_read_gen(struct mdfld_dsi_pkg_sender *sender,
u8 param0,
u8 param1,
u8 param_num,
u32 *data,
u16 len,
u8 transmission)
{
struct mdfld_dsi_pkg *pkg;
unsigned long flags;
spin_lock_irqsave(&sender->lock, flags);
pkg = pkg_sender_get_pkg_locked(sender);
spin_unlock_irqrestore(&sender->lock,flags);
if (!pkg) {
dev_err(sender->dev->dev, "No pkg memory\n");
return -ENOMEM;
}
switch (param_num) {
case 0:
pkg->pkg_type = MDFLD_DSI_PKG_GEN_READ_0;
pkg->pkg.short_pkg.cmd = 0;
pkg->pkg.short_pkg.param = 0;
break;
case 1:
pkg->pkg_type = MDFLD_DSI_PKG_GEN_READ_1;
pkg->pkg.short_pkg.cmd = param0;
pkg->pkg.short_pkg.param = 0;
break;
case 2:
pkg->pkg_type = MDFLD_DSI_PKG_GEN_READ_2;
pkg->pkg.short_pkg.cmd = param0;
pkg->pkg.short_pkg.param = param1;
break;
}
pkg->transmission_type = transmission;
INIT_LIST_HEAD(&pkg->entry);
return __read_panel_data(sender, pkg, data, len);
}
static int mdfld_dsi_read_mcs(struct mdfld_dsi_pkg_sender *sender,
u8 cmd,
u32 *data,
u16 len,
u8 transmission)
{
struct mdfld_dsi_pkg *pkg;
unsigned long flags;
spin_lock_irqsave(&sender->lock, flags);
pkg = pkg_sender_get_pkg_locked(sender);
spin_unlock_irqrestore(&sender->lock, flags);
if (!pkg) {
dev_err(sender->dev->dev, "No pkg memory\n");
return -ENOMEM;
}
pkg->pkg_type = MDFLD_DSI_PKG_MCS_READ;
pkg->pkg.short_pkg.cmd = cmd;
pkg->pkg.short_pkg.param = 0;
pkg->transmission_type = transmission;
INIT_LIST_HEAD(&pkg->entry);
return __read_panel_data(sender, pkg, data, len);
}
void dsi_controller_dbi_init(struct mdfld_dsi_config * dsi_config, int pipe)
{
struct drm_device * dev = dsi_config->dev;
u32 reg_offset = pipe ? MIPIC_REG_OFFSET : 0;
int lane_count = dsi_config->lane_count;
u32 val = 0;
/*un-ready device*/
REG_WRITE((MIPIA_DEVICE_READY_REG + reg_offset), 0x00000000);
/*init dsi adapter before kicking off*/
REG_WRITE((MIPIA_CONTROL_REG + reg_offset), 0x00000018);
/*TODO: figure out how to setup these registers*/
REG_WRITE((MIPIA_DPHY_PARAM_REG + reg_offset), 0x150c3408);
REG_WRITE((MIPIA_CLK_LANE_SWITCH_TIME_CNT_REG + reg_offset), 0x000a0014);
REG_WRITE((MIPIA_DBI_BW_CTRL_REG + reg_offset), 0x00000400);
REG_WRITE((MIPIA_DBI_FIFO_THROTTLE_REG + reg_offset), 0x00000001);
REG_WRITE((MIPIA_HS_LS_DBI_ENABLE_REG + reg_offset), 0x00000000);
/*enable all interrupts*/
REG_WRITE((MIPIA_INTR_EN_REG + reg_offset), 0xffffffff);
/*max value: 20 clock cycles of txclkesc*/
REG_WRITE((MIPIA_TURN_AROUND_TIMEOUT_REG + reg_offset), 0x0000001f);
/*min 21 txclkesc, max: ffffh*/
REG_WRITE((MIPIA_DEVICE_RESET_TIMER_REG + reg_offset), 0x0000ffff);
/*min: 7d0 max: 4e20*/
REG_WRITE((MIPIA_INIT_COUNT_REG + reg_offset), 0x00000fa0);
/*set up max return packet size*/
REG_WRITE((MIPIA_MAX_RETURN_PACK_SIZE_REG + reg_offset),
MDFLD_DSI_MAX_RETURN_PACKET_SIZE);
/*set up func_prg*/
val |= lane_count;
val |= (dsi_config->channel_num << DSI_DBI_VIRT_CHANNEL_OFFSET);
val |= DSI_DBI_COLOR_FORMAT_OPTION2;
REG_WRITE((MIPIA_DSI_FUNC_PRG_REG + reg_offset), val);
REG_WRITE((MIPIA_HS_TX_TIMEOUT_REG + reg_offset), 0x3fffff);
REG_WRITE((MIPIA_LP_RX_TIMEOUT_REG + reg_offset), 0xffff);
REG_WRITE((MIPIA_HIGH_LOW_SWITCH_COUNT_REG + reg_offset), 0x46);
REG_WRITE((MIPIA_EOT_DISABLE_REG + reg_offset), 0x00000000);
REG_WRITE((MIPIA_LP_BYTECLK_REG + reg_offset), 0x00000004);
REG_WRITE((MIPIA_DEVICE_READY_REG + reg_offset), 0x00000001);
}
void dsi_controller_dpi_init(struct mdfld_dsi_config * dsi_config, int pipe)
{
struct drm_device * dev = dsi_config->dev;
u32 reg_offset = pipe ? MIPIC_REG_OFFSET : 0;
int lane_count = dsi_config->lane_count;
struct mdfld_dsi_dpi_timing dpi_timing;
struct drm_display_mode * mode = dsi_config->mode;
u32 val = 0;
/*un-ready device*/
REG_WRITE((MIPIA_DEVICE_READY_REG + reg_offset), 0x00000000);
/*init dsi adapter before kicking off*/
REG_WRITE((MIPIA_CONTROL_REG + reg_offset), 0x00000018);
/*enable all interrupts*/
REG_WRITE((MIPIA_INTR_EN_REG + reg_offset), 0xffffffff);
/*set up func_prg*/
val |= lane_count;
val |= dsi_config->channel_num << DSI_DPI_VIRT_CHANNEL_OFFSET;
switch(dsi_config->bpp) {
case 16:
val |= DSI_DPI_COLOR_FORMAT_RGB565;
break;
case 18:
val |= DSI_DPI_COLOR_FORMAT_RGB666;
break;
case 24:
val |= DSI_DPI_COLOR_FORMAT_RGB888;
break;
default:
DRM_ERROR("unsupported color format, bpp = %d\n", dsi_config->bpp);
}
REG_WRITE((MIPIA_DSI_FUNC_PRG_REG + reg_offset), val);
REG_WRITE((MIPIA_HS_TX_TIMEOUT_REG + reg_offset),
(mode->vtotal * mode->htotal * dsi_config->bpp / (8 * lane_count)) & DSI_HS_TX_TIMEOUT_MASK);
REG_WRITE((MIPIA_LP_RX_TIMEOUT_REG + reg_offset), 0xffff & DSI_LP_RX_TIMEOUT_MASK);
/*max value: 20 clock cycles of txclkesc*/
REG_WRITE((MIPIA_TURN_AROUND_TIMEOUT_REG + reg_offset), 0x14 & DSI_TURN_AROUND_TIMEOUT_MASK);
/*min 21 txclkesc, max: ffffh*/
REG_WRITE((MIPIA_DEVICE_RESET_TIMER_REG + reg_offset), 0xffff & DSI_RESET_TIMER_MASK);
REG_WRITE((MIPIA_DPI_RESOLUTION_REG + reg_offset), mode->vdisplay << 16 | mode->hdisplay);
/*set DPI timing registers*/
mdfld_dsi_dpi_timing_calculation(mode, &dpi_timing, dsi_config->lane_count, dsi_config->bpp);
REG_WRITE((MIPIA_HSYNC_COUNT_REG + reg_offset), dpi_timing.hsync_count & DSI_DPI_TIMING_MASK);
REG_WRITE((MIPIA_HBP_COUNT_REG + reg_offset), dpi_timing.hbp_count & DSI_DPI_TIMING_MASK);
REG_WRITE((MIPIA_HFP_COUNT_REG + reg_offset), dpi_timing.hfp_count & DSI_DPI_TIMING_MASK);
REG_WRITE((MIPIA_HACTIVE_COUNT_REG + reg_offset), dpi_timing.hactive_count & DSI_DPI_TIMING_MASK);
REG_WRITE((MIPIA_VSYNC_COUNT_REG + reg_offset), dpi_timing.vsync_count & DSI_DPI_TIMING_MASK);
REG_WRITE((MIPIA_VBP_COUNT_REG + reg_offset), dpi_timing.vbp_count & DSI_DPI_TIMING_MASK);
REG_WRITE((MIPIA_VFP_COUNT_REG + reg_offset), dpi_timing.vfp_count & DSI_DPI_TIMING_MASK);
REG_WRITE((MIPIA_HIGH_LOW_SWITCH_COUNT_REG + reg_offset), 0x46);
/*min: 7d0 max: 4e20*/
REG_WRITE((MIPIA_INIT_COUNT_REG + reg_offset), 0x000007d0);
/*set up video mode*/
val = dsi_config->video_mode | DSI_DPI_COMPLETE_LAST_LINE;
REG_WRITE((MIPIA_VIDEO_MODE_FORMAT_REG + reg_offset), val);
REG_WRITE((MIPIA_EOT_DISABLE_REG + reg_offset), 0x00000000);
REG_WRITE((MIPIA_LP_BYTECLK_REG + reg_offset), 0x00000004);
/*TODO: figure out how to setup these registers*/
REG_WRITE((MIPIA_DPHY_PARAM_REG + reg_offset), 0x150c3408);
REG_WRITE((MIPIA_CLK_LANE_SWITCH_TIME_CNT_REG + reg_offset), (0xa << 16) | 0x14);
/*set device ready*/
REG_WRITE((MIPIA_DEVICE_READY_REG + reg_offset), 0x00000001);
}
static void dsi_controller_init(struct mdfld_dsi_config * dsi_config, int pipe)
{
if (!dsi_config || ((pipe != 0) && (pipe != 2))) {
DRM_ERROR("Invalid parameters\n");
return;
}
if (dsi_config->type == MDFLD_DSI_ENCODER_DPI)
dsi_controller_dpi_init(dsi_config, pipe);
else if (dsi_config->type == MDFLD_DSI_ENCODER_DBI)
dsi_controller_dbi_init(dsi_config, pipe);
else
DRM_ERROR("Bad DSI encoder type\n");
}
void mdfld_dsi_cmds_kick_out(struct mdfld_dsi_pkg_sender *sender)
{
process_pkg_list(sender);
}
int mdfld_dsi_send_dcs(struct mdfld_dsi_pkg_sender *sender,
u8 dcs, u8 *param, u32 param_num, u8 data_src,
int delay)
{
struct mdfld_dsi_pkg *pkg;
u32 cb_phy = sender->dbi_cb_phy;
struct drm_device *dev = sender->dev;
u32 index = 0;
u8 *cb = (u8 *)sender->dbi_cb_addr;
unsigned long flags;
int retry;
u8 *dst = NULL;
u32 len;
if (!sender) {
WARN_ON(1);
return -EINVAL;
}
if (!sender->dbi_pkg_support) {
dev_err(dev->dev, "No DBI pkg sending on this sender\n");
return -ENOTSUPP;
}
if (param_num > MDFLD_MAX_DCS_PARAM) {
dev_err(dev->dev, "Sender only supports up to %d DCS params\n",
MDFLD_MAX_DCS_PARAM);
return -EINVAL;
}
/*
* If dcs is write_mem_start, send it directly using DSI adapter
* interface
*/
if (dcs == DCS_WRITE_MEM_START) {
if (!spin_trylock(&sender->lock))
return -EAGAIN;
/*
* query whether DBI FIFO is empty,
* if not wait it becoming empty
*/
retry = MDFLD_DSI_DBI_FIFO_TIMEOUT;
while (retry &&
!(REG_READ(sender->mipi_gen_fifo_stat_reg) & (1 << 27))) {
udelay(500);
retry--;
}
/* If DBI FIFO timeout, drop this frame */
if (!retry) {
spin_unlock(&sender->lock);
return 0;
}
*(cb + (index++)) = write_mem_start;
REG_WRITE(sender->mipi_cmd_len_reg, 1);
REG_WRITE(sender->mipi_cmd_addr_reg,
cb_phy | (1 << 0) | (1 << 1));
retry = MDFLD_DSI_DBI_FIFO_TIMEOUT;
while (retry &&
(REG_READ(sender->mipi_cmd_addr_reg) & (1 << 0))) {
udelay(1);
retry--;
}
spin_unlock(&sender->lock);
return 0;
}
/* Get a free pkg */
spin_lock_irqsave(&sender->lock, flags);
pkg = pkg_sender_get_pkg_locked(sender);
spin_unlock_irqrestore(&sender->lock, flags);
if (!pkg) {
dev_err(dev->dev, "No packages memory\n");
return -ENOMEM;
}
dst = pkg->pkg.dcs_pkg.param;
memcpy(dst, param, param_num);
pkg->pkg_type = MDFLD_DSI_PKG_DCS;
pkg->transmission_type = MDFLD_DSI_DCS;
pkg->pkg.dcs_pkg.cmd = dcs;
pkg->pkg.dcs_pkg.param_num = param_num;
pkg->pkg.dcs_pkg.data_src = data_src;
INIT_LIST_HEAD(&pkg->entry);
if (param_num == 0)
return mdfld_dsi_send_mcs_short_hs(sender, dcs, 0, 0, delay);
else if (param_num == 1)
return mdfld_dsi_send_mcs_short_hs(sender, dcs,
param[0], 1, delay);
else if (param_num > 1) {
len = (param_num + 1) / 4;
if ((param_num + 1) % 4)
len++;
return mdfld_dsi_send_mcs_long_hs(sender,
(u32 *)&pkg->pkg.dcs_pkg, len, delay);
}
return 0;
}
int mdfld_dsi_send_mcs_short_hs(struct mdfld_dsi_pkg_sender *sender,
u8 cmd, u8 param, u8 param_num, int delay)
{
if (!sender) {
WARN_ON(1);
return -EINVAL;
}
return mdfld_dsi_send_mcs_short(sender, cmd, param, param_num,
MDFLD_DSI_HS_TRANSMISSION, delay);
}
int mdfld_dsi_send_mcs_short_lp(struct mdfld_dsi_pkg_sender *sender,
u8 cmd, u8 param, u8 param_num, int delay)
{
if (!sender) {
WARN_ON(1);
return -EINVAL;
}
return mdfld_dsi_send_mcs_short(sender, cmd, param, param_num,
MDFLD_DSI_LP_TRANSMISSION, delay);
}
int mdfld_dsi_send_mcs_long_hs(struct mdfld_dsi_pkg_sender *sender,
u32 *data,
u32 len,
int delay)
{
if (!sender || !data || !len) {
DRM_ERROR("Invalid parameters\n");
return -EINVAL;
}
return mdfld_dsi_send_mcs_long(sender, data, len,
MDFLD_DSI_HS_TRANSMISSION, delay);
}
int mdfld_dsi_send_mcs_long_lp(struct mdfld_dsi_pkg_sender *sender,
u32 *data,
u32 len,
int delay)
{
if (!sender || !data || !len) {
WARN_ON(1);
return -EINVAL;
}
return mdfld_dsi_send_mcs_long(sender, data, len,
MDFLD_DSI_LP_TRANSMISSION, delay);
}
int mdfld_dsi_send_gen_short_hs(struct mdfld_dsi_pkg_sender *sender,
u8 param0, u8 param1, u8 param_num, int delay)
{
if (!sender) {
WARN_ON(1);
return -EINVAL;
}
return mdfld_dsi_send_gen_short(sender, param0, param1, param_num,
MDFLD_DSI_HS_TRANSMISSION, delay);
}
int mdfld_dsi_send_gen_short_lp(struct mdfld_dsi_pkg_sender *sender,
u8 param0, u8 param1, u8 param_num, int delay)
{
if (!sender || param_num < 0 || param_num > 2) {
WARN_ON(1);
return -EINVAL;
}
return mdfld_dsi_send_gen_short(sender, param0, param1, param_num,
MDFLD_DSI_LP_TRANSMISSION, delay);
}
int mdfld_dsi_send_gen_long_hs(struct mdfld_dsi_pkg_sender *sender,
u32 *data,
u32 len,
int delay)
{
if (!sender || !data || !len) {
WARN_ON(1);
return -EINVAL;
}
return mdfld_dsi_send_gen_long(sender, data, len,
MDFLD_DSI_HS_TRANSMISSION, delay);
}
int mdfld_dsi_send_gen_long_lp(struct mdfld_dsi_pkg_sender *sender,
u32 *data,
u32 len,
int delay)
{
if (!sender || !data || !len) {
WARN_ON(1);
return -EINVAL;
}
return mdfld_dsi_send_gen_long(sender, data, len,
MDFLD_DSI_LP_TRANSMISSION, delay);
}
int mdfld_dsi_read_gen_hs(struct mdfld_dsi_pkg_sender *sender,
u8 param0,
u8 param1,
u8 param_num,
u32 *data,
u16 len)
{
if (!sender || !data || param_num < 0 || param_num > 2
|| !data || !len) {
DRM_ERROR("Invalid parameters\n");
return -EINVAL;
}
return mdfld_dsi_read_gen(sender, param0, param1, param_num,
data, len, MDFLD_DSI_HS_TRANSMISSION);
}
int mdfld_dsi_read_gen_lp(struct mdfld_dsi_pkg_sender *sender,
u8 param0,
u8 param1,
u8 param_num,
u32 *data,
u16 len)
{
if (!sender || !data || param_num < 0 || param_num > 2
|| !data || !len) {
DRM_ERROR("Invalid parameters\n");
return -EINVAL;
}
return mdfld_dsi_read_gen(sender, param0, param1, param_num,
data, len, MDFLD_DSI_LP_TRANSMISSION);
}
int mdfld_dsi_read_mcs_hs(struct mdfld_dsi_pkg_sender *sender,
u8 cmd,
u32 *data,
u16 len)
{
if (!sender || !data || !len) {
DRM_ERROR("Invalid parameters\n");
return -EINVAL;
}
return mdfld_dsi_read_mcs(sender, cmd, data, len,
MDFLD_DSI_HS_TRANSMISSION);
}
int mdfld_dsi_read_mcs_lp(struct mdfld_dsi_pkg_sender *sender,
u8 cmd,
u32 *data,
u16 len)
{
if (!sender || !data || !len) {
WARN_ON(1);
return -EINVAL;
}
return mdfld_dsi_read_mcs(sender, cmd, data, len,
MDFLD_DSI_LP_TRANSMISSION);
}
int mdfld_dsi_pkg_sender_init(struct mdfld_dsi_connector *dsi_connector,
int pipe)
{
int ret;
struct mdfld_dsi_pkg_sender *pkg_sender;
struct mdfld_dsi_config *dsi_config =
mdfld_dsi_get_config(dsi_connector);
struct drm_device *dev = dsi_config->dev;
struct drm_psb_private *dev_priv = dev->dev_private;
struct psb_gtt *pg = &dev_priv->gtt;
int i;
struct mdfld_dsi_pkg *pkg, *tmp;
u32 mipi_val = 0;
if (!dsi_connector) {
WARN_ON(1);
return -EINVAL;
}
pkg_sender = dsi_connector->pkg_sender;
if (!pkg_sender || IS_ERR(pkg_sender)) {
pkg_sender = kzalloc(sizeof(struct mdfld_dsi_pkg_sender),
GFP_KERNEL);
if (!pkg_sender) {
dev_err(dev->dev, "Create DSI pkg sender failed\n");
return -ENOMEM;
}
dsi_connector->pkg_sender = (void *)pkg_sender;
}
pkg_sender->dev = dev;
pkg_sender->dsi_connector = dsi_connector;
pkg_sender->pipe = pipe;
pkg_sender->pkg_num = 0;
pkg_sender->panel_mode = 0;
pkg_sender->status = MDFLD_DSI_PKG_SENDER_FREE;
/* Init dbi command buffer*/
if (dsi_config->type == MDFLD_DSI_ENCODER_DBI) {
pkg_sender->dbi_pkg_support = 1;
ret = mdfld_dbi_cb_init(pkg_sender, pg, pipe);
if (ret) {
dev_err(dev->dev, "DBI command buffer map failed\n");
goto mapping_err;
}
}
/* Init regs */
if (pipe == 0) {
pkg_sender->dpll_reg = MRST_DPLL_A;
pkg_sender->dspcntr_reg = DSPACNTR;
pkg_sender->pipeconf_reg = PIPEACONF;
pkg_sender->dsplinoff_reg = DSPALINOFF;
pkg_sender->dspsurf_reg = DSPASURF;
pkg_sender->pipestat_reg = PIPEASTAT;
pkg_sender->mipi_intr_stat_reg = MIPIA_INTR_STAT_REG;
pkg_sender->mipi_lp_gen_data_reg = MIPIA_LP_GEN_DATA_REG;
pkg_sender->mipi_hs_gen_data_reg = MIPIA_HS_GEN_DATA_REG;
pkg_sender->mipi_lp_gen_ctrl_reg = MIPIA_LP_GEN_CTRL_REG;
pkg_sender->mipi_hs_gen_ctrl_reg = MIPIA_HS_GEN_CTRL_REG;
pkg_sender->mipi_gen_fifo_stat_reg = MIPIA_GEN_FIFO_STAT_REG;
pkg_sender->mipi_data_addr_reg = MIPIA_DATA_ADD_REG;
pkg_sender->mipi_data_len_reg = MIPIA_DATA_LEN_REG;
pkg_sender->mipi_cmd_addr_reg = MIPIA_CMD_ADD_REG;
pkg_sender->mipi_cmd_len_reg = MIPIA_CMD_LEN_REG;
} else if (pipe == 2) {
pkg_sender->dpll_reg = MRST_DPLL_A;
pkg_sender->dspcntr_reg = DSPCCNTR;
pkg_sender->pipeconf_reg = PIPECCONF;
pkg_sender->dsplinoff_reg = DSPCLINOFF;
pkg_sender->dspsurf_reg = DSPCSURF;
pkg_sender->pipestat_reg = PIPECSTAT;
pkg_sender->mipi_intr_stat_reg =
MIPIA_INTR_STAT_REG + MIPIC_REG_OFFSET;
pkg_sender->mipi_lp_gen_data_reg =
MIPIA_LP_GEN_DATA_REG + MIPIC_REG_OFFSET;
pkg_sender->mipi_hs_gen_data_reg =
MIPIA_HS_GEN_DATA_REG + MIPIC_REG_OFFSET;
pkg_sender->mipi_lp_gen_ctrl_reg =
MIPIA_LP_GEN_CTRL_REG + MIPIC_REG_OFFSET;
pkg_sender->mipi_hs_gen_ctrl_reg =
MIPIA_HS_GEN_CTRL_REG + MIPIC_REG_OFFSET;
pkg_sender->mipi_gen_fifo_stat_reg =
MIPIA_GEN_FIFO_STAT_REG + MIPIC_REG_OFFSET;
pkg_sender->mipi_data_addr_reg =
MIPIA_DATA_ADD_REG + MIPIC_REG_OFFSET;
pkg_sender->mipi_data_len_reg =
MIPIA_DATA_LEN_REG + MIPIC_REG_OFFSET;
pkg_sender->mipi_cmd_addr_reg =
MIPIA_CMD_ADD_REG + MIPIC_REG_OFFSET;
pkg_sender->mipi_cmd_len_reg =
MIPIA_CMD_LEN_REG + MIPIC_REG_OFFSET;
}
/* Init pkg list */
INIT_LIST_HEAD(&pkg_sender->pkg_list);
INIT_LIST_HEAD(&pkg_sender->free_list);
spin_lock_init(&pkg_sender->lock);
/* Allocate free pkg pool */
for (i = 0; i < MDFLD_MAX_PKG_NUM; i++) {
pkg = kzalloc(sizeof(struct mdfld_dsi_pkg), GFP_KERNEL);
if (!pkg) {
dev_err(dev->dev, "Out of memory allocating pkg pool");
ret = -ENOMEM;
goto pkg_alloc_err;
}
INIT_LIST_HEAD(&pkg->entry);
list_add_tail(&pkg->entry, &pkg_sender->free_list);
}
/*
* For video mode, don't enable DPI timing output here,
* will init the DPI timing output during mode setting.
*/
if (dsi_config->type == MDFLD_DSI_ENCODER_DPI)
mipi_val = PASS_FROM_SPHY_TO_AFE | SEL_FLOPPED_HSTX;
else if (dsi_config->type == MDFLD_DSI_ENCODER_DBI)
mipi_val = PASS_FROM_SPHY_TO_AFE | SEL_FLOPPED_HSTX
| TE_TRIGGER_GPIO_PIN;
else
DRM_ERROR("Bad DSI encoder type\n");
if (pipe == 0) {
mipi_val |= 0x2;
REG_WRITE(MIPI, mipi_val);
REG_READ(MIPI);
} else if (pipe == 2) {
REG_WRITE(MIPI_C, mipi_val);
REG_READ(MIPI_C);
}
/*do dsi controller init*/
dsi_controller_init(dsi_config, pipe);
return 0;
pkg_alloc_err:
list_for_each_entry_safe(pkg, tmp, &pkg_sender->free_list, entry) {
list_del(&pkg->entry);
kfree(pkg);
}
/* Free mapped command buffer */
mdfld_dbi_cb_destroy(pkg_sender);
mapping_err:
kfree(pkg_sender);
dsi_connector->pkg_sender = NULL;
return ret;
}
void mdfld_dsi_pkg_sender_destroy(struct mdfld_dsi_pkg_sender *sender)
{
struct mdfld_dsi_pkg *pkg, *tmp;
if (!sender || IS_ERR(sender))
return;
/* Free pkg pool */
list_for_each_entry_safe(pkg, tmp, &sender->free_list, entry) {
list_del(&pkg->entry);
kfree(pkg);
}
/* Free pkg list */
list_for_each_entry_safe(pkg, tmp, &sender->pkg_list, entry) {
list_del(&pkg->entry);
kfree(pkg);
}
mdfld_dbi_cb_destroy(sender); /* free mapped command buffer */
kfree(sender);
}