The GMA500 driver redefines many constants already found in the generic header. Replace uses of the custom defines by the standard ones and get rid of the duplicate defininitions. Acked-by: Alan Cox <alan@linux.intel.com> Signed-off-by: Thierry Reding <treding@nvidia.com>
		
			
				
	
	
		
			675 lines
		
	
	
	
		
			16 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			675 lines
		
	
	
	
		
			16 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * 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 <video/mipi_display.h>
 | 
						|
 | 
						|
#include "mdfld_dsi_output.h"
 | 
						|
#include "mdfld_dsi_pkg_sender.h"
 | 
						|
#include "mdfld_dsi_dpi.h"
 | 
						|
 | 
						|
#define MDFLD_DSI_READ_MAX_COUNT		5000
 | 
						|
 | 
						|
enum {
 | 
						|
	MDFLD_DSI_PANEL_MODE_SLEEP = 0x1,
 | 
						|
};
 | 
						|
 | 
						|
enum {
 | 
						|
	MDFLD_DSI_PKG_SENDER_FREE = 0x0,
 | 
						|
	MDFLD_DSI_PKG_SENDER_BUSY = 0x1,
 | 
						|
};
 | 
						|
 | 
						|
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 inline 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);
 | 
						|
	}
 | 
						|
	DRM_ERROR("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, (BIT(2) | BIT(10) | BIT(18) |
 | 
						|
						BIT(26) | BIT(27) | BIT(28)));
 | 
						|
}
 | 
						|
 | 
						|
static int wait_for_lp_fifos_empty(struct mdfld_dsi_pkg_sender *sender)
 | 
						|
{
 | 
						|
	return wait_for_gen_fifo_empty(sender, (BIT(10) | BIT(26)));
 | 
						|
}
 | 
						|
 | 
						|
static int wait_for_hs_fifos_empty(struct mdfld_dsi_pkg_sender *sender)
 | 
						|
{
 | 
						|
	return wait_for_gen_fifo_empty(sender, (BIT(2) | BIT(18)));
 | 
						|
}
 | 
						|
 | 
						|
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;
 | 
						|
 | 
						|
	dev_dbg(sender->dev->dev, "Handling error 0x%08x\n", mask);
 | 
						|
 | 
						|
	switch (mask) {
 | 
						|
	case BIT(0):
 | 
						|
	case BIT(1):
 | 
						|
	case BIT(2):
 | 
						|
	case BIT(3):
 | 
						|
	case BIT(4):
 | 
						|
	case BIT(5):
 | 
						|
	case BIT(6):
 | 
						|
	case BIT(7):
 | 
						|
	case BIT(8):
 | 
						|
	case BIT(9):
 | 
						|
	case BIT(10):
 | 
						|
	case BIT(11):
 | 
						|
	case BIT(12):
 | 
						|
	case BIT(13):
 | 
						|
		dev_dbg(sender->dev->dev, "No Action required\n");
 | 
						|
		break;
 | 
						|
	case BIT(14):
 | 
						|
		/*wait for all fifo empty*/
 | 
						|
		/*wait_for_all_fifos_empty(sender)*/
 | 
						|
		break;
 | 
						|
	case BIT(15):
 | 
						|
		dev_dbg(sender->dev->dev, "No Action required\n");
 | 
						|
		break;
 | 
						|
	case BIT(16):
 | 
						|
		break;
 | 
						|
	case BIT(17):
 | 
						|
		break;
 | 
						|
	case BIT(18):
 | 
						|
	case BIT(19):
 | 
						|
		dev_dbg(sender->dev->dev, "High/Low contention detected\n");
 | 
						|
		/*wait for contention recovery time*/
 | 
						|
		/*mdelay(10);*/
 | 
						|
		/*wait for all fifo empty*/
 | 
						|
		if (0)
 | 
						|
			wait_for_all_fifos_empty(sender);
 | 
						|
		break;
 | 
						|
	case BIT(20):
 | 
						|
		dev_dbg(sender->dev->dev, "No Action required\n");
 | 
						|
		break;
 | 
						|
	case BIT(21):
 | 
						|
		/*wait for all fifo empty*/
 | 
						|
		/*wait_for_all_fifos_empty(sender);*/
 | 
						|
		break;
 | 
						|
	case BIT(22):
 | 
						|
		break;
 | 
						|
	case BIT(23):
 | 
						|
	case BIT(24):
 | 
						|
	case BIT(25):
 | 
						|
	case BIT(26):
 | 
						|
	case BIT(27):
 | 
						|
		dev_dbg(sender->dev->dev, "HS Gen fifo full\n");
 | 
						|
		REG_WRITE(intr_stat_reg, mask);
 | 
						|
		wait_for_hs_fifos_empty(sender);
 | 
						|
		break;
 | 
						|
	case BIT(28):
 | 
						|
		dev_dbg(sender->dev->dev, "LP Gen fifo full\n");
 | 
						|
		REG_WRITE(intr_stat_reg, mask);
 | 
						|
		wait_for_lp_fifos_empty(sender);
 | 
						|
		break;
 | 
						|
	case BIT(29):
 | 
						|
	case BIT(30):
 | 
						|
	case BIT(31):
 | 
						|
		dev_dbg(sender->dev->dev, "No Action required\n");
 | 
						|
		break;
 | 
						|
	}
 | 
						|
 | 
						|
	if (mask & REG_READ(intr_stat_reg))
 | 
						|
		dev_dbg(sender->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(sender->dev->dev, "[DSI]: %s\n", dsi_errors[i]);
 | 
						|
			err = handle_dsi_error(sender, mask);
 | 
						|
			if (err)
 | 
						|
				DRM_ERROR("Cannot handle error\n");
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return err;
 | 
						|
}
 | 
						|
 | 
						|
static int send_short_pkg(struct mdfld_dsi_pkg_sender *sender, u8 data_type,
 | 
						|
			u8 cmd, u8 param, bool hs)
 | 
						|
{
 | 
						|
	struct drm_device *dev = sender->dev;
 | 
						|
	u32 ctrl_reg;
 | 
						|
	u32 val;
 | 
						|
	u8 virtual_channel = 0;
 | 
						|
 | 
						|
	if (hs) {
 | 
						|
		ctrl_reg = sender->mipi_hs_gen_ctrl_reg;
 | 
						|
 | 
						|
		/* FIXME: wait_for_hs_fifos_empty(sender); */
 | 
						|
	} else {
 | 
						|
		ctrl_reg = sender->mipi_lp_gen_ctrl_reg;
 | 
						|
 | 
						|
		/* FIXME: wait_for_lp_fifos_empty(sender); */
 | 
						|
	}
 | 
						|
 | 
						|
	val = FLD_VAL(param, 23, 16) | FLD_VAL(cmd, 15, 8) |
 | 
						|
		FLD_VAL(virtual_channel, 7, 6) | FLD_VAL(data_type, 5, 0);
 | 
						|
 | 
						|
	REG_WRITE(ctrl_reg, val);
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int send_long_pkg(struct mdfld_dsi_pkg_sender *sender, u8 data_type,
 | 
						|
			u8 *data, int len, bool hs)
 | 
						|
{
 | 
						|
	struct drm_device *dev = sender->dev;
 | 
						|
	u32 ctrl_reg;
 | 
						|
	u32 data_reg;
 | 
						|
	u32 val;
 | 
						|
	u8 *p;
 | 
						|
	u8 b1, b2, b3, b4;
 | 
						|
	u8 virtual_channel = 0;
 | 
						|
	int i;
 | 
						|
 | 
						|
	if (hs) {
 | 
						|
		ctrl_reg = sender->mipi_hs_gen_ctrl_reg;
 | 
						|
		data_reg = sender->mipi_hs_gen_data_reg;
 | 
						|
 | 
						|
		/* FIXME: wait_for_hs_fifos_empty(sender); */
 | 
						|
	} else {
 | 
						|
		ctrl_reg = sender->mipi_lp_gen_ctrl_reg;
 | 
						|
		data_reg = sender->mipi_lp_gen_data_reg;
 | 
						|
 | 
						|
		/* FIXME: wait_for_lp_fifos_empty(sender); */
 | 
						|
	}
 | 
						|
 | 
						|
	p = data;
 | 
						|
	for (i = 0; i < len / 4; i++) {
 | 
						|
		b1 = *p++;
 | 
						|
		b2 = *p++;
 | 
						|
		b3 = *p++;
 | 
						|
		b4 = *p++;
 | 
						|
 | 
						|
		REG_WRITE(data_reg, b4 << 24 | b3 << 16 | b2 << 8 | b1);
 | 
						|
	}
 | 
						|
 | 
						|
	i = len % 4;
 | 
						|
	if (i) {
 | 
						|
		b1 = 0; b2 = 0; b3 = 0;
 | 
						|
 | 
						|
		switch (i) {
 | 
						|
		case 3:
 | 
						|
			b1 = *p++;
 | 
						|
			b2 = *p++;
 | 
						|
			b3 = *p++;
 | 
						|
			break;
 | 
						|
		case 2:
 | 
						|
			b1 = *p++;
 | 
						|
			b2 = *p++;
 | 
						|
			break;
 | 
						|
		case 1:
 | 
						|
			b1 = *p++;
 | 
						|
			break;
 | 
						|
		}
 | 
						|
 | 
						|
		REG_WRITE(data_reg, b3 << 16 | b2 << 8 | b1);
 | 
						|
	}
 | 
						|
 | 
						|
	val = FLD_VAL(len, 23, 8) | FLD_VAL(virtual_channel, 7, 6) |
 | 
						|
		FLD_VAL(data_type, 5, 0);
 | 
						|
 | 
						|
	REG_WRITE(ctrl_reg, val);
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int send_pkg_prepare(struct mdfld_dsi_pkg_sender *sender, u8 data_type,
 | 
						|
			u8 *data, u16 len)
 | 
						|
{
 | 
						|
	u8 cmd;
 | 
						|
 | 
						|
	switch (data_type) {
 | 
						|
	case MIPI_DSI_DCS_SHORT_WRITE:
 | 
						|
	case MIPI_DSI_DCS_SHORT_WRITE_PARAM:
 | 
						|
	case MIPI_DSI_DCS_LONG_WRITE:
 | 
						|
		cmd = *data;
 | 
						|
		break;
 | 
						|
	default:
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
 | 
						|
	/*this prevents other package sending while doing msleep*/
 | 
						|
	sender->status = MDFLD_DSI_PKG_SENDER_BUSY;
 | 
						|
 | 
						|
	/*wait for 120 milliseconds in case exit_sleep_mode just be sent*/
 | 
						|
	if (unlikely(cmd == MIPI_DCS_ENTER_SLEEP_MODE)) {
 | 
						|
		/*TODO: replace it with msleep later*/
 | 
						|
		mdelay(120);
 | 
						|
	}
 | 
						|
 | 
						|
	if (unlikely(cmd == MIPI_DCS_EXIT_SLEEP_MODE)) {
 | 
						|
		/*TODO: replace it with msleep later*/
 | 
						|
		mdelay(120);
 | 
						|
	}
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int send_pkg_done(struct mdfld_dsi_pkg_sender *sender, u8 data_type,
 | 
						|
			u8 *data, u16 len)
 | 
						|
{
 | 
						|
	u8 cmd;
 | 
						|
 | 
						|
	switch (data_type) {
 | 
						|
	case MIPI_DSI_DCS_SHORT_WRITE:
 | 
						|
	case MIPI_DSI_DCS_SHORT_WRITE_PARAM:
 | 
						|
	case MIPI_DSI_DCS_LONG_WRITE:
 | 
						|
		cmd = *data;
 | 
						|
		break;
 | 
						|
	default:
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
 | 
						|
	/*update panel status*/
 | 
						|
	if (unlikely(cmd == MIPI_DCS_ENTER_SLEEP_MODE)) {
 | 
						|
		sender->panel_mode |= MDFLD_DSI_PANEL_MODE_SLEEP;
 | 
						|
		/*TODO: replace it with msleep later*/
 | 
						|
		mdelay(120);
 | 
						|
	} else if (unlikely(cmd == MIPI_DCS_EXIT_SLEEP_MODE)) {
 | 
						|
		sender->panel_mode &= ~MDFLD_DSI_PANEL_MODE_SLEEP;
 | 
						|
		/*TODO: replace it with msleep later*/
 | 
						|
		mdelay(120);
 | 
						|
	} else if (unlikely(cmd == MIPI_DCS_SOFT_RESET)) {
 | 
						|
		/*TODO: replace it with msleep later*/
 | 
						|
		mdelay(5);
 | 
						|
	}
 | 
						|
 | 
						|
	sender->status = MDFLD_DSI_PKG_SENDER_FREE;
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int send_pkg(struct mdfld_dsi_pkg_sender *sender, u8 data_type,
 | 
						|
		u8 *data, u16 len, bool hs)
 | 
						|
{
 | 
						|
	int ret;
 | 
						|
 | 
						|
	/*handle DSI error*/
 | 
						|
	ret = dsi_error_handler(sender);
 | 
						|
	if (ret) {
 | 
						|
		DRM_ERROR("Error handling failed\n");
 | 
						|
		return -EAGAIN;
 | 
						|
	}
 | 
						|
 | 
						|
	/* send pkg */
 | 
						|
	if (sender->status == MDFLD_DSI_PKG_SENDER_BUSY) {
 | 
						|
		DRM_ERROR("sender is busy\n");
 | 
						|
		return -EAGAIN;
 | 
						|
	}
 | 
						|
 | 
						|
	ret = send_pkg_prepare(sender, data_type, data, len);
 | 
						|
	if (ret) {
 | 
						|
		DRM_ERROR("send_pkg_prepare error\n");
 | 
						|
		return ret;
 | 
						|
	}
 | 
						|
 | 
						|
	switch (data_type) {
 | 
						|
	case MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM:
 | 
						|
	case MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM:
 | 
						|
	case MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM:
 | 
						|
	case MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM:
 | 
						|
	case MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM:
 | 
						|
	case MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM:
 | 
						|
	case MIPI_DSI_DCS_SHORT_WRITE:
 | 
						|
	case MIPI_DSI_DCS_SHORT_WRITE_PARAM:
 | 
						|
	case MIPI_DSI_DCS_READ:
 | 
						|
		ret = send_short_pkg(sender, data_type, data[0], data[1], hs);
 | 
						|
		break;
 | 
						|
	case MIPI_DSI_GENERIC_LONG_WRITE:
 | 
						|
	case MIPI_DSI_DCS_LONG_WRITE:
 | 
						|
		ret = send_long_pkg(sender, data_type, data, len, hs);
 | 
						|
		break;
 | 
						|
	}
 | 
						|
 | 
						|
	send_pkg_done(sender, data_type, data, len);
 | 
						|
 | 
						|
	/*FIXME: should I query complete and fifo empty here?*/
 | 
						|
 | 
						|
	return ret;
 | 
						|
}
 | 
						|
 | 
						|
int mdfld_dsi_send_mcs_long(struct mdfld_dsi_pkg_sender *sender, u8 *data,
 | 
						|
			u32 len, bool hs)
 | 
						|
{
 | 
						|
	unsigned long flags;
 | 
						|
 | 
						|
	if (!sender || !data || !len) {
 | 
						|
		DRM_ERROR("Invalid parameters\n");
 | 
						|
		return -EINVAL;
 | 
						|
	}
 | 
						|
 | 
						|
	spin_lock_irqsave(&sender->lock, flags);
 | 
						|
	send_pkg(sender, MIPI_DSI_DCS_LONG_WRITE, data, len, hs);
 | 
						|
	spin_unlock_irqrestore(&sender->lock, flags);
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
int mdfld_dsi_send_mcs_short(struct mdfld_dsi_pkg_sender *sender, u8 cmd,
 | 
						|
			u8 param, u8 param_num, bool hs)
 | 
						|
{
 | 
						|
	u8 data[2];
 | 
						|
	unsigned long flags;
 | 
						|
	u8 data_type;
 | 
						|
 | 
						|
	if (!sender) {
 | 
						|
		DRM_ERROR("Invalid parameter\n");
 | 
						|
		return -EINVAL;
 | 
						|
	}
 | 
						|
 | 
						|
	data[0] = cmd;
 | 
						|
 | 
						|
	if (param_num) {
 | 
						|
		data_type = MIPI_DSI_DCS_SHORT_WRITE_PARAM;
 | 
						|
		data[1] = param;
 | 
						|
	} else {
 | 
						|
		data_type = MIPI_DSI_DCS_SHORT_WRITE;
 | 
						|
		data[1] = 0;
 | 
						|
	}
 | 
						|
 | 
						|
	spin_lock_irqsave(&sender->lock, flags);
 | 
						|
	send_pkg(sender, data_type, data, sizeof(data), hs);
 | 
						|
	spin_unlock_irqrestore(&sender->lock, flags);
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
int mdfld_dsi_send_gen_short(struct mdfld_dsi_pkg_sender *sender, u8 param0,
 | 
						|
			u8 param1, u8 param_num, bool hs)
 | 
						|
{
 | 
						|
	u8 data[2];
 | 
						|
	unsigned long flags;
 | 
						|
	u8 data_type;
 | 
						|
 | 
						|
	if (!sender || param_num > 2) {
 | 
						|
		DRM_ERROR("Invalid parameter\n");
 | 
						|
		return -EINVAL;
 | 
						|
	}
 | 
						|
 | 
						|
	switch (param_num) {
 | 
						|
	case 0:
 | 
						|
		data_type = MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM;
 | 
						|
		data[0] = 0;
 | 
						|
		data[1] = 0;
 | 
						|
		break;
 | 
						|
	case 1:
 | 
						|
		data_type = MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM;
 | 
						|
		data[0] = param0;
 | 
						|
		data[1] = 0;
 | 
						|
		break;
 | 
						|
	case 2:
 | 
						|
		data_type = MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM;
 | 
						|
		data[0] = param0;
 | 
						|
		data[1] = param1;
 | 
						|
		break;
 | 
						|
	}
 | 
						|
 | 
						|
	spin_lock_irqsave(&sender->lock, flags);
 | 
						|
	send_pkg(sender, data_type, data, sizeof(data), hs);
 | 
						|
	spin_unlock_irqrestore(&sender->lock, flags);
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
int mdfld_dsi_send_gen_long(struct mdfld_dsi_pkg_sender *sender, u8 *data,
 | 
						|
			u32 len, bool hs)
 | 
						|
{
 | 
						|
	unsigned long flags;
 | 
						|
 | 
						|
	if (!sender || !data || !len) {
 | 
						|
		DRM_ERROR("Invalid parameters\n");
 | 
						|
		return -EINVAL;
 | 
						|
	}
 | 
						|
 | 
						|
	spin_lock_irqsave(&sender->lock, flags);
 | 
						|
	send_pkg(sender, MIPI_DSI_GENERIC_LONG_WRITE, data, len, hs);
 | 
						|
	spin_unlock_irqrestore(&sender->lock, flags);
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int __read_panel_data(struct mdfld_dsi_pkg_sender *sender, u8 data_type,
 | 
						|
			u8 *data, u16 len, u32 *data_out, u16 len_out, bool hs)
 | 
						|
{
 | 
						|
	unsigned long flags;
 | 
						|
	struct drm_device *dev = sender->dev;
 | 
						|
	int i;
 | 
						|
	u32 gen_data_reg;
 | 
						|
	int retry = MDFLD_DSI_READ_MAX_COUNT;
 | 
						|
 | 
						|
	if (!sender || !data_out || !len_out) {
 | 
						|
		DRM_ERROR("Invalid parameters\n");
 | 
						|
		return -EINVAL;
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
	 * 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, BIT(29));
 | 
						|
 | 
						|
	if ((REG_READ(sender->mipi_intr_stat_reg) & BIT(29)))
 | 
						|
		DRM_ERROR("Can NOT clean read data valid interrupt\n");
 | 
						|
 | 
						|
	/*send out read request*/
 | 
						|
	send_pkg(sender, data_type, data, len, hs);
 | 
						|
 | 
						|
	/*polling read data avail interrupt*/
 | 
						|
	while (retry && !(REG_READ(sender->mipi_intr_stat_reg) & BIT(29))) {
 | 
						|
		udelay(100);
 | 
						|
		retry--;
 | 
						|
	}
 | 
						|
 | 
						|
	if (!retry) {
 | 
						|
		spin_unlock_irqrestore(&sender->lock, flags);
 | 
						|
		return -ETIMEDOUT;
 | 
						|
	}
 | 
						|
 | 
						|
	REG_WRITE(sender->mipi_intr_stat_reg, BIT(29));
 | 
						|
 | 
						|
	/*read data*/
 | 
						|
	if (hs)
 | 
						|
		gen_data_reg = sender->mipi_hs_gen_data_reg;
 | 
						|
	else
 | 
						|
		gen_data_reg = sender->mipi_lp_gen_data_reg;
 | 
						|
 | 
						|
	for (i = 0; i < len_out; i++)
 | 
						|
		*(data_out + i) = REG_READ(gen_data_reg);
 | 
						|
 | 
						|
	spin_unlock_irqrestore(&sender->lock, flags);
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
int mdfld_dsi_read_mcs(struct mdfld_dsi_pkg_sender *sender, u8 cmd,
 | 
						|
		u32 *data, u16 len, bool hs)
 | 
						|
{
 | 
						|
	if (!sender || !data || !len) {
 | 
						|
		DRM_ERROR("Invalid parameters\n");
 | 
						|
		return -EINVAL;
 | 
						|
	}
 | 
						|
 | 
						|
	return __read_panel_data(sender, MIPI_DSI_DCS_READ, &cmd, 1,
 | 
						|
				data, len, hs);
 | 
						|
}
 | 
						|
 | 
						|
int mdfld_dsi_pkg_sender_init(struct mdfld_dsi_connector *dsi_connector,
 | 
						|
								int pipe)
 | 
						|
{
 | 
						|
	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;
 | 
						|
	const struct psb_offset *map = &dev_priv->regmap[pipe];
 | 
						|
	u32 mipi_val = 0;
 | 
						|
 | 
						|
	if (!dsi_connector) {
 | 
						|
		DRM_ERROR("Invalid parameter\n");
 | 
						|
		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) {
 | 
						|
			DRM_ERROR("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 regs*/
 | 
						|
	/* FIXME: should just copy the regmap ptr ? */
 | 
						|
	pkg_sender->dpll_reg = map->dpll;
 | 
						|
	pkg_sender->dspcntr_reg = map->cntr;
 | 
						|
	pkg_sender->pipeconf_reg = map->conf;
 | 
						|
	pkg_sender->dsplinoff_reg = map->linoff;
 | 
						|
	pkg_sender->dspsurf_reg = map->surf;
 | 
						|
	pkg_sender->pipestat_reg = map->status;
 | 
						|
 | 
						|
	pkg_sender->mipi_intr_stat_reg = MIPI_INTR_STAT_REG(pipe);
 | 
						|
	pkg_sender->mipi_lp_gen_data_reg = MIPI_LP_GEN_DATA_REG(pipe);
 | 
						|
	pkg_sender->mipi_hs_gen_data_reg = MIPI_HS_GEN_DATA_REG(pipe);
 | 
						|
	pkg_sender->mipi_lp_gen_ctrl_reg = MIPI_LP_GEN_CTRL_REG(pipe);
 | 
						|
	pkg_sender->mipi_hs_gen_ctrl_reg = MIPI_HS_GEN_CTRL_REG(pipe);
 | 
						|
	pkg_sender->mipi_gen_fifo_stat_reg = MIPI_GEN_FIFO_STAT_REG(pipe);
 | 
						|
	pkg_sender->mipi_data_addr_reg = MIPI_DATA_ADD_REG(pipe);
 | 
						|
	pkg_sender->mipi_data_len_reg = MIPI_DATA_LEN_REG(pipe);
 | 
						|
	pkg_sender->mipi_cmd_addr_reg = MIPI_CMD_ADD_REG(pipe);
 | 
						|
	pkg_sender->mipi_cmd_len_reg = MIPI_CMD_LEN_REG(pipe);
 | 
						|
 | 
						|
	/*init lock*/
 | 
						|
	spin_lock_init(&pkg_sender->lock);
 | 
						|
 | 
						|
	if (mdfld_get_panel_type(dev, pipe) != TC35876X) {
 | 
						|
		/**
 | 
						|
		 * For video mode, don't enable DPI timing output here,
 | 
						|
		 * will init the DPI timing output during mode setting.
 | 
						|
		 */
 | 
						|
		mipi_val = PASS_FROM_SPHY_TO_AFE | SEL_FLOPPED_HSTX;
 | 
						|
 | 
						|
		if (pipe == 0)
 | 
						|
			mipi_val |= 0x2;
 | 
						|
 | 
						|
		REG_WRITE(MIPI_PORT_CONTROL(pipe), mipi_val);
 | 
						|
		REG_READ(MIPI_PORT_CONTROL(pipe));
 | 
						|
 | 
						|
		/* do dsi controller init */
 | 
						|
		mdfld_dsi_controller_init(dsi_config, pipe);
 | 
						|
	}
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
void mdfld_dsi_pkg_sender_destroy(struct mdfld_dsi_pkg_sender *sender)
 | 
						|
{
 | 
						|
	if (!sender || IS_ERR(sender))
 | 
						|
		return;
 | 
						|
 | 
						|
	/*free*/
 | 
						|
	kfree(sender);
 | 
						|
}
 | 
						|
 | 
						|
 |