123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675 |
- /*
- * 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);
- }
|