예제 #1
0
파일: psb_irq.c 프로젝트: gregkh/psb-kmp
void psb_irq_postinstall(struct drm_device *dev)
{
	struct drm_psb_private *dev_priv =
	    (struct drm_psb_private *)dev->dev_private;
	unsigned long irqflags;

	spin_lock_irqsave(&dev_priv->irqmask_lock, irqflags);
	PSB_WVDC32(dev_priv->vdc_irq_mask, PSB_INT_ENABLE_R);
	PSB_WSGX32(dev_priv->sgx2_irq_mask, PSB_CR_EVENT_HOST_ENABLE2);
	PSB_WSGX32(dev_priv->sgx_irq_mask, PSB_CR_EVENT_HOST_ENABLE);
	(void)PSB_RSGX32(PSB_CR_EVENT_HOST_ENABLE);
	/****MSVDX IRQ Setup...*****/
	/* Enable Mtx Interupt to host */
	{
		unsigned long enables = 0;
		PSB_DEBUG_GENERAL("Setting up MSVDX IRQs.....\n");
		REGIO_WRITE_FIELD_LITE(enables, MSVDX_INTERRUPT_STATUS,
				       CR_MTX_IRQ, 1);
		PSB_WMSVDX32(enables, MSVDX_HOST_INTERRUPT_ENABLE);
	}
	dev_priv->irq_enabled = 1;
 
	uint32_t hotplug_stat = PSB_RVDC32(PORT_HOTPLUG_ENABLE_REG);
	PSB_WVDC32(hotplug_stat | SDVOB_HOTPLUG_DETECT_ENABLE, PORT_HOTPLUG_ENABLE_REG);

	spin_unlock_irqrestore(&dev_priv->irqmask_lock, irqflags);
}
static int ls04x_drv_ic_init(struct mdfld_dsi_config *dsi_config)
{
	int r = 0;
	u8 data[16];
	struct mdfld_dsi_pkg_sender *sender
				= mdfld_dsi_get_pkg_sender(dsi_config);

	PSB_DEBUG_ENTRY("\n");

	if (!sender)
		return -EINVAL;
	sender->status = MDFLD_DSI_PKG_SENDER_FREE;
	memset(data, 0, sizeof(data));
	mdfld_dsi_send_gen_short_hs(sender,
			ls04x_mcap[0],
			ls04x_mcap[1], 2,
			MDFLD_DSI_SEND_PACKAGE);

	r = mdfld_dsi_read_gen_hs(sender,
			ls04x_device_code_read[0], 0, 1, data, 5);
	PSB_DEBUG_GENERAL("device code read: %d %02x %02x %02x %02x %02x\n",
			  r, data[0], data[1], data[2], data[3], data[4]);

	if ((data[2] == 0x14) && (data[3] == 0x13))
		r = ls04x_igzo_drv_ic_init(dsi_config);
	else if ((data[2] == 0x34) && (data[3] == 0x15))
		r = ls04x_cgs_drv_ic_init(dsi_config);
	else if ((data[2] == 0x94) && (data[3] == 0x31))
		r = ls04x_igzo_g8_drv_ic_init(dsi_config);
	else
		DRM_INFO("unknown device code: %02x %02x\n", data[2], data[3]);

	return r;
}
예제 #3
0
파일: psb_irq.c 프로젝트: gregkh/psb-kmp
void psb_msvdx_irq_postinstall(struct drm_psb_private *dev_priv)
{
	/* Enable Mtx Interupt to host */
	unsigned long enables = 0;
	PSB_DEBUG_GENERAL("Setting up MSVDX IRQs.....\n");
	REGIO_WRITE_FIELD_LITE(enables, MSVDX_INTERRUPT_STATUS, CR_MTX_IRQ, 1);
	PSB_WMSVDX32(enables, MSVDX_HOST_INTERRUPT_ENABLE);
}
예제 #4
0
void gl3_disable(void)
{
	struct drm_psb_private *dev_priv =
		    (struct drm_psb_private *) gpDrmDevice->dev_private;

	PSB_DEBUG_ENTRY("gl3_disable called on platform %x\n",	dev_priv->platform_rev_id);
	if (!ospm_power_using_hw_begin(OSPM_GRAPHICS_ISLAND, true))
		return;
	MDFLD_GL3_WRITE(MDFLD_GL3_DISABLE_CACHE, MDFLD_GL3_CONTROL);
	PSB_DEBUG_GENERAL("gl3 cache disabled with mask %x\n",
			MDFLD_GL3_DISABLE_CACHE);
	ospm_power_using_hw_end(OSPM_GRAPHICS_ISLAND);
}
예제 #5
0
void gl3_reset(void)
{
	struct drm_psb_private *dev_priv =
		    (struct drm_psb_private *) gpDrmDevice->dev_private;

	PSB_DEBUG_ENTRY("gl3_reset called on platform %x\n",	dev_priv->platform_rev_id);
	if (!ospm_power_using_hw_begin(OSPM_GRAPHICS_ISLAND, true))
		return;
	// Reset the cache
	MDFLD_GL3_WRITE(MDFLD_GL3_SOFT_RESET_ENABLE, MDFLD_GL3_G_CONTROL);
	PSB_DEBUG_GENERAL("gl3 cache soft reset with mas %x\n",
			MDFLD_GL3_SOFT_RESET_ENABLE);
	ospm_power_using_hw_end(OSPM_GRAPHICS_ISLAND);
}
예제 #6
0
int
psb_poll_mtx_irq (struct drm_psb_private *dev_priv)
{
  int ret = 0;
  uint32_t MtxInt = 0;
  REGIO_WRITE_FIELD_LITE (MtxInt, MSVDX_INTERRUPT_STATUS, CR_MTX_IRQ, 1);

  ret = psb_wait_for_register (dev_priv, MSVDX_INTERRUPT_STATUS, MtxInt,	/* Required value */
			       MtxInt /* Enabled bits */ );
  if (ret)
    {
      PSB_DEBUG_GENERAL
	("MSVDX: Error Mtx did not return int within a resonable time\n");

      return ret;
    }

  PSB_DEBUG_GENERAL ("MSVDX: Got MTX Int\n");

  /* Got it so clear the bit */
  PSB_WMSVDX32 (MtxInt, MSVDX_INTERRUPT_CLEAR);

  return ret;
}
예제 #7
0
파일: psb_irq.c 프로젝트: gregkh/psb-kmp
/*
 * MSVDX interrupt.
 */
static void psb_msvdx_interrupt(struct drm_device *dev, uint32_t msvdx_stat)
{
	struct drm_psb_private *dev_priv =
	    (struct drm_psb_private *)dev->dev_private;

	if (msvdx_stat & MSVDX_INTERRUPT_STATUS_CR_MMU_FAULT_IRQ_MASK) {
		/*Ideally we should we should never get to this */
		PSB_DEBUG_GENERAL
		    ("******MSVDX: msvdx_stat: 0x%x fence2_irq_on=%d ***** (MMU FAULT)\n",
		     msvdx_stat, dev_priv->fence2_irq_on);

		/* Pause MMU */
		PSB_WMSVDX32(MSVDX_MMU_CONTROL0_CR_MMU_PAUSE_MASK,
			     MSVDX_MMU_CONTROL0);
		DRM_WRITEMEMORYBARRIER();

		/* Clear this interupt bit only */
		PSB_WMSVDX32(MSVDX_INTERRUPT_STATUS_CR_MMU_FAULT_IRQ_MASK,
			     MSVDX_INTERRUPT_CLEAR);
		PSB_RMSVDX32(MSVDX_INTERRUPT_CLEAR);
		DRM_READMEMORYBARRIER();

		dev_priv->msvdx_needs_reset = 1;
	} else if (msvdx_stat & MSVDX_INTERRUPT_STATUS_CR_MTX_IRQ_MASK) {
		PSB_DEBUG_GENERAL
		    ("******MSVDX: msvdx_stat: 0x%x fence2_irq_on=%d ***** (MTX)\n",
		     msvdx_stat, dev_priv->fence2_irq_on);

		/* Clear all interupt bits */
		PSB_WMSVDX32(0xffff, MSVDX_INTERRUPT_CLEAR);
		PSB_RMSVDX32(MSVDX_INTERRUPT_CLEAR);
		DRM_READMEMORYBARRIER();

		psb_msvdx_mtx_interrupt(dev);
	}
}
static void msvdx_upload_fw(struct drm_psb_private *dev_priv,
			  const uint32_t data_mem, uint32_t ram_bank_size,
			  uint32_t address, const unsigned int words,
			  const uint32_t * const data)
{
	uint32_t loop, ctrl, ram_id, addr, cur_bank = (uint32_t) ~0;
	uint32_t access_ctrl;

	PSB_DEBUG_GENERAL("MSVDX: Upload firmware by register interface\n");
	/* Save the access control register... */
	access_ctrl = PSB_RMSVDX32(MTX_RAM_ACCESS_CONTROL_OFFSET);

	/* Wait for MCMSTAT to become be idle 1 */
	psb_wait_for_register(dev_priv, MTX_RAM_ACCESS_STATUS_OFFSET,
			      1,	/* Required Value */
			      0xffffffff, /* Enables */
			      2000000, 5);

	for (loop = 0; loop < words; loop++) {
		ram_id = data_mem + (address / ram_bank_size);
		if (ram_id != cur_bank) {
			addr = address >> 2;
			ctrl = 0;
			REGIO_WRITE_FIELD_LITE(ctrl,
					       MTX_RAM_ACCESS_CONTROL,
					       MTX_MCMID, ram_id);
			REGIO_WRITE_FIELD_LITE(ctrl,
					       MTX_RAM_ACCESS_CONTROL,
					       MTX_MCM_ADDR, addr);
			REGIO_WRITE_FIELD_LITE(ctrl,
					       MTX_RAM_ACCESS_CONTROL,
					       MTX_MCMAI, 1);
			PSB_WMSVDX32(ctrl, MTX_RAM_ACCESS_CONTROL_OFFSET);
			cur_bank = ram_id;
		}
		address += 4;

		PSB_WMSVDX32(data[loop],
			     MTX_RAM_ACCESS_DATA_TRANSFER_OFFSET);

		/* Wait for MCMSTAT to become be idle 1 */
		psb_wait_for_register(dev_priv, MTX_RAM_ACCESS_STATUS_OFFSET,
				      1,	/* Required Value */
				      0xffffffff, /* Enables */
				      2000000, 5);
	}
static void msvdx_get_mtx_control_from_dash(struct drm_psb_private *dev_priv)
{
	struct msvdx_private *msvdx_priv = dev_priv->msvdx_private;
	int count = 0;
	uint32_t reg_val = 0;

	REGIO_WRITE_FIELD(reg_val, MSVDX_MTX_DEBUG, MTX_DBG_IS_SLAVE, 1);
	REGIO_WRITE_FIELD(reg_val, MSVDX_MTX_DEBUG, MTX_DBG_GPIO_IN, 0x02);
	PSB_WMSVDX32(reg_val, MSVDX_MTX_DEBUG_OFFSET);

	do {
		reg_val = PSB_RMSVDX32(MSVDX_MTX_DEBUG_OFFSET);
		count++;
	} while (((reg_val & 0x18) != 0) && count < 50000);

	if (count >= 50000)
		PSB_DEBUG_GENERAL("MAVDX: timeout in get_mtx_control_from_dash\n");

	/* Save the access control register...*/
	msvdx_priv->psb_dash_access_ctrl = PSB_RMSVDX32(MTX_RAM_ACCESS_CONTROL_OFFSET);
}
예제 #10
0
int
psb_wait_for_register (struct drm_psb_private *dev_priv,
		       uint32_t ui32Offset,
		       uint32_t ui32Value, uint32_t ui32Enable)
{
  uint32_t ui32Temp;
  uint32_t ui32PollCount = 1000;
  while (ui32PollCount)
    {
      ui32Temp = PSB_RMSVDX32 (ui32Offset);
      if (ui32Value == (ui32Temp & ui32Enable))	/* All the bits are reset   */
	return 0;		/* So exit                      */

      /* Wait a bit */
      DRM_UDELAY (100);
      ui32PollCount--;
    }
  PSB_DEBUG_GENERAL
    ("MSVDX: Timeout while waiting for register %08x: expecting %08x (mask %08x), got %08x\n",
     ui32Offset, ui32Value, ui32Enable, ui32Temp);
  return 1;
}
static void msvdx_upload_fw(struct drm_psb_private *dev_priv,
			  uint32_t address, const unsigned int words, int fw_sel)
{
	uint32_t reg_val = 0;
	uint32_t cmd;
	uint32_t uCountReg, offset, mmu_ptd;
	uint32_t size = (words * 4); /* byte count */
	uint32_t dma_channel = 0; /* Setup a Simple DMA for Ch0 */
	struct msvdx_private *msvdx_priv = dev_priv->msvdx_private;

	PSB_DEBUG_GENERAL("MSVDX: Upload firmware by DMA\n");
	msvdx_get_mtx_control_from_dash(dev_priv);

	/* dma transfers to/from the mtx have to be 32-bit aligned and in multiples of 32 bits */
	PSB_WMSVDX32(address, MTX_SYSC_CDMAA_OFFSET);

	REGIO_WRITE_FIELD_LITE(reg_val, MTX_SYSC_CDMAC, BURSTSIZE,	4); /* burst size in multiples of 64 bits (allowed values are 2 or 4) */
	REGIO_WRITE_FIELD_LITE(reg_val, MTX_SYSC_CDMAC, RNW, 0);	/* false means write to mtx mem, true means read from mtx mem */
	REGIO_WRITE_FIELD_LITE(reg_val, MTX_SYSC_CDMAC, ENABLE,	1);				/* begin transfer */
	REGIO_WRITE_FIELD_LITE(reg_val, MTX_SYSC_CDMAC, LENGTH,	words);		/* This specifies the transfer size of the DMA operation in terms of 32-bit words */
	PSB_WMSVDX32(reg_val, MTX_SYSC_CDMAC_OFFSET);

	/* toggle channel 0 usage between mtx and other msvdx peripherals */
	{
		reg_val = PSB_RMSVDX32(MSVDX_CONTROL_OFFSET);
		REGIO_WRITE_FIELD(reg_val, MSVDX_CONTROL, DMAC_CH0_SELECT,  0);
		PSB_WMSVDX32(reg_val, MSVDX_CONTROL_OFFSET);
	}


	/* Clear the DMAC Stats */
	PSB_WMSVDX32(0 , DMAC_DMAC_IRQ_STAT_OFFSET + dma_channel);

	offset = msvdx_priv->fw->offset;

	if (fw_sel)
		offset += ((msvdx_priv->mtx_mem_size + 8192) & ~0xfff);

	/* use bank 0 */
	cmd = 0;
	PSB_WMSVDX32(cmd, MSVDX_MMU_BANK_INDEX_OFFSET);

	/* Write PTD to mmu base 0*/
	mmu_ptd = psb_get_default_pd_addr(dev_priv->mmu);
	PSB_WMSVDX32(mmu_ptd, MSVDX_MMU_DIR_LIST_BASE_OFFSET + 0);

	/* Invalidate */
	reg_val = PSB_RMSVDX32(MSVDX_MMU_CONTROL0_OFFSET);
	reg_val &= ~0xf;
	REGIO_WRITE_FIELD(reg_val, MSVDX_MMU_CONTROL0, MMU_INVALDC, 1);
	PSB_WMSVDX32(reg_val, MSVDX_MMU_CONTROL0_OFFSET);

	PSB_WMSVDX32(offset, DMAC_DMAC_SETUP_OFFSET + dma_channel);

	/* Only use a single dma - assert that this is valid */
	if ((size / 4) >= (1 << 15)) {
		DRM_ERROR("psb: DMA size beyond limited, aboart firmware uploading\n");
		return;
	}

	uCountReg = PSB_DMAC_VALUE_COUNT(PSB_DMAC_BSWAP_NO_SWAP,
					 0,  /* 32 bits */
					 PSB_DMAC_DIR_MEM_TO_PERIPH,
					 0,
					 (size / 4));
	/* Set the number of bytes to dma*/
	PSB_WMSVDX32(uCountReg, DMAC_DMAC_COUNT_OFFSET + dma_channel);

	cmd = PSB_DMAC_VALUE_PERIPH_PARAM(PSB_DMAC_ACC_DEL_0, PSB_DMAC_INCR_OFF, PSB_DMAC_BURST_2);
	PSB_WMSVDX32(cmd, DMAC_DMAC_PERIPH_OFFSET + dma_channel);

	/* Set destination port for dma */
	cmd = 0;
	REGIO_WRITE_FIELD(cmd, DMAC_DMAC_PERIPHERAL_ADDR, ADDR, MTX_SYSC_CDMAT_OFFSET);
	PSB_WMSVDX32(cmd, DMAC_DMAC_PERIPHERAL_ADDR_OFFSET + dma_channel);


	/* Finally, rewrite the count register with the enable bit set*/
	PSB_WMSVDX32(uCountReg | DMAC_DMAC_COUNT_EN_MASK, DMAC_DMAC_COUNT_OFFSET + dma_channel);

	/* Wait for all to be done */
	if (psb_wait_for_register(dev_priv,
				  DMAC_DMAC_IRQ_STAT_OFFSET + dma_channel,
				  DMAC_DMAC_IRQ_STAT_TRANSFER_FIN_MASK,
				  DMAC_DMAC_IRQ_STAT_TRANSFER_FIN_MASK,
				  2000000, 5)) {
		psb_setup_fw_dump(dev_priv, dma_channel);
		msvdx_release_mtx_control_from_dash(dev_priv);
		return;
	}

	/* Assert that the MTX DMA port is all done aswell */
	if (psb_wait_for_register(dev_priv,
			MTX_SYSC_CDMAS0_OFFSET,
			1, 1, 2000000, 5)) {
		msvdx_release_mtx_control_from_dash(dev_priv);
		return;
	}

	msvdx_release_mtx_control_from_dash(dev_priv);

	PSB_DEBUG_GENERAL("MSVDX: Upload done\n");
}
예제 #12
0
static
void mdfld_h8c7_dsi_controller_init(struct mdfld_dsi_config *dsi_config)
{

	struct mdfld_dsi_hw_context *hw_ctx = &dsi_config->dsi_hw_context;
	struct drm_device *dev = dsi_config->dev;

	struct csc_setting csc = {	.pipe = 0,
								.type = CSC_REG_SETTING,
								.enable_state = true,
								.data_len = CSC_REG_COUNT,
								.data.csc_reg_data = {
									0xFFB0424, 0xFDF, 0x4320FF1, 0xFDC, 0xFF50FF5, 0x415}
							 };
	struct gamma_setting gamma = {	.pipe = 0,
									.type = GAMMA_REG_SETTING,
									.enable_state = true,
									.data_len = GAMMA_10_BIT_TABLE_COUNT,
									.gamma_tableX100 = {
										0x000000, 0x030303, 0x050505, 0x070707,
										0x090909, 0x0C0C0C, 0x0E0E0E, 0x101010,
										0x121212, 0x141414, 0x171717, 0x191919,
										0x1B1B1B, 0x1D1D1D, 0x1F1F1F, 0x212121,
										0x232323, 0x252525, 0x282828, 0x2A2A2A,
										0x2C2C2C, 0x2E2E2E, 0x303030, 0x323232,
										0x343434, 0x363636, 0x383838, 0x3A3A3A,
										0x3C3C3C, 0x3E3E3E, 0x404040, 0x424242,
										0x444444, 0x464646, 0x484848, 0x4A4A4A,
										0x4C4C4C, 0x4E4E4E, 0x505050, 0x525252,
										0x545454, 0x565656, 0x585858, 0x5A5A5A,
										0x5C5C5C, 0x5E5E5E, 0x606060, 0x626262,
										0x646464, 0x666666, 0x686868, 0x6A6A6A,
										0x6C6C6C, 0x6E6E6E, 0x707070, 0x727272,
										0x747474, 0x767676, 0x787878, 0x7A7A7A,
										0x7C7C7C, 0x7E7E7E, 0x808080, 0x828282,
										0x848484, 0x868686, 0x888888, 0x8A8A8A,
										0x8C8C8C, 0x8E8E8E, 0x909090, 0x929292,
										0x949494, 0x969696, 0x989898, 0x999999,
										0x9B9B9B, 0x9D9D9D, 0x9F9F9F, 0xA1A1A1,
										0xA3A3A3, 0xA5A5A5, 0xA7A7A7, 0xA9A9A9,
										0xABABAB, 0xADADAD, 0xAFAFAF, 0xB1B1B1,
										0xB3B3B3, 0xB5B5B5, 0xB6B6B6, 0xB8B8B8,
										0xBABABA, 0xBCBCBC, 0xBEBEBE, 0xC0C0C0,
										0xC2C2C2, 0xC4C4C4, 0xC6C6C6, 0xC8C8C8,
										0xCACACA, 0xCCCCCC, 0xCECECE, 0xCFCFCF,
										0xD1D1D1, 0xD3D3D3, 0xD5D5D5, 0xD7D7D7,
										0xD9D9D9, 0xDBDBDB, 0xDDDDDD, 0xDFDFDF,
										0xE1E1E1, 0xE3E3E3, 0xE4E4E4, 0xE6E6E6,
										0xE8E8E8, 0xEAEAEA, 0xECECEC, 0xEEEEEE,
										0xF0F0F0, 0xF2F2F2, 0xF4F4F4, 0xF6F6F6,
										0xF7F7F7, 0xF9F9F9, 0xFBFBFB, 0xFDFDFD}
								 };


	PSB_DEBUG_ENTRY("\n");

	/*reconfig lane configuration*/
	dsi_config->lane_count = 3;
	dsi_config->lane_config = MDFLD_DSI_DATA_LANE_3_1;
	dsi_config->enable_gamma_csc = ENABLE_GAMMA | ENABLE_CSC;
	/* This is for 400 mhz.  Set it to 0 for 800mhz */
	hw_ctx->cck_div = 1;
	hw_ctx->pll_bypass_mode = 0;

	hw_ctx->mipi_control = 0x00;
	hw_ctx->intr_en = 0xffffffff;
	hw_ctx->hs_tx_timeout = 0xffffff;
	hw_ctx->lp_rx_timeout = 0xffffff;
	hw_ctx->turn_around_timeout = 0x1f;
	hw_ctx->device_reset_timer = 0xffff;
	hw_ctx->high_low_switch_count = 0x20;
	hw_ctx->init_count = 0xf0;
	hw_ctx->eot_disable = 0x3;
	hw_ctx->lp_byteclk = 0x4;
	hw_ctx->clk_lane_switch_time_cnt = 0x20000E;
	hw_ctx->hs_ls_dbi_enable = 0x0;
	/* HW team suggested 1390 for bandwidth setting */
	hw_ctx->dbi_bw_ctrl = 1390;
	hw_ctx->dphy_param = 0x20124E1A;
	hw_ctx->dsi_func_prg = (0xa000 | dsi_config->lane_count);
	hw_ctx->mipi = TE_TRIGGER_GPIO_PIN;
	hw_ctx->mipi |= dsi_config->lane_config;

	if (dsi_config->enable_gamma_csc & ENABLE_CSC) {
		/* setting the tuned csc setting */
		drm_psb_enable_color_conversion = 1;
		mdfld_intel_crtc_set_color_conversion(dev, &csc);
	}

	if (dsi_config->enable_gamma_csc & ENABLE_GAMMA) {
		/* setting the tuned gamma setting */
		drm_psb_enable_gamma = 1;
		mdfld_intel_crtc_set_gamma(dev, &gamma);
	}

}

static
struct drm_display_mode *h8c7_cmd_get_config_mode(void)
{
	struct drm_display_mode *mode;

	PSB_DEBUG_ENTRY("\n");

	mode = kzalloc(sizeof(*mode), GFP_KERNEL);
	if (!mode)
		return NULL;

	mode->htotal = 920;
	mode->hdisplay = 720;
	mode->hsync_start = 816;
	mode->hsync_end = 824;
	mode->vtotal = 1300;
	mode->vdisplay = 1280;
	mode->vsync_start = 1294;
	mode->vsync_end = 1296;
	mode->vrefresh = 60;
	mode->clock =  mode->vrefresh * mode->vtotal * mode->htotal / 1000;
	mode->type |= DRM_MODE_TYPE_PREFERRED;

	PSB_DEBUG_ENTRY("hdisplay is %d\n", mode->hdisplay);
	PSB_DEBUG_ENTRY("vdisplay is %d\n", mode->vdisplay);
	PSB_DEBUG_ENTRY("HSS is %d\n", mode->hsync_start);
	PSB_DEBUG_ENTRY("HSE is %d\n", mode->hsync_end);
	PSB_DEBUG_ENTRY("htotal is %d\n", mode->htotal);
	PSB_DEBUG_ENTRY("VSS is %d\n", mode->vsync_start);
	PSB_DEBUG_ENTRY("VSE is %d\n", mode->vsync_end);
	PSB_DEBUG_ENTRY("vtotal is %d\n", mode->vtotal);
	PSB_DEBUG_ENTRY("clock is %d\n", mode->clock);

	drm_mode_set_name(mode);
	drm_mode_set_crtcinfo(mode, 0);

	return mode;
}

static
int mdfld_dsi_h8c7_cmd_power_on(struct mdfld_dsi_config *dsi_config)
{

	struct mdfld_dsi_pkg_sender *sender =
		mdfld_dsi_get_pkg_sender(dsi_config);
	int err = 0;
	int enable_err, enabled = 0;

	PSB_DEBUG_ENTRY("\n");

	if (!sender) {
		DRM_ERROR("Failed to get DSI packet sender\n");
		return -EINVAL;
	}

	if (!IS_ERR(h8c7_regulator_status.regulator)) {

		if (!h8c7_regulator_status.h8c7_mmc2_on) {
			PSB_DEBUG_ENTRY("Before power on, regulator is %d\n",
			regulator_is_enabled(h8c7_regulator_status.regulator));
			PSB_DEBUG_ENTRY("Begin to power on\n");
			h8c7_regulator_status.h8c7_mmc2_on = true;
		} else {
			DRM_ERROR("power on several times without off\n");
		}

		enabled = regulator_is_enabled(h8c7_regulator_status.regulator);
		enable_err = regulator_enable(h8c7_regulator_status.regulator);
		if (enable_err < 0) {
			regulator_put(h8c7_regulator_status.regulator);
			DRM_ERROR("FATAL:enable h8c7 regulator error\n");
		}

		/* vemmc2 need 50ms delay due to stability
		** If already enabled, no need to wait for this delay.
		** This code isn't race proof but since in addition to
		** this panel driver only touch driver is enabling this
		** regulator and does it after this function has been
		** finished, this code works well enough for now.
		*/
		if (!enabled)
			msleep(50);
		PSB_DEBUG_ENTRY("After power on, regulator is %d\n",
			regulator_is_enabled(h8c7_regulator_status.regulator));
	}

	/*exit sleep */
	err = mdfld_dsi_send_dcs(sender,
		 exit_sleep_mode,
		 NULL,
		 0,
		 CMD_DATA_SRC_SYSTEM_MEM,
		 MDFLD_DSI_SEND_PACKAGE);
	if (err) {
		DRM_ERROR("faild to exit_sleep mode\n");
		goto power_err;
	}

	msleep(120);

	/*set tear on*/
	err = mdfld_dsi_send_dcs(sender,
		 set_tear_on,
		 NULL,
		 0,
		 CMD_DATA_SRC_SYSTEM_MEM,
		 MDFLD_DSI_SEND_PACKAGE);
	if (err) {
		DRM_ERROR("faild to set_tear_on mode\n");
		goto power_err;
	}

	/*turn on display*/
	err = mdfld_dsi_send_dcs(sender,
		 set_display_on,
		 NULL,
		 0,
		 CMD_DATA_SRC_SYSTEM_MEM,
		 MDFLD_DSI_SEND_PACKAGE);
	if (err) {
		DRM_ERROR("faild to set_display_on mode\n");
		goto power_err;
	}
	if (drm_psb_enable_cabc) {
		/* turn on cabc */
		h8c7_disable_cabc[1] = 0x2;
		mdfld_dsi_send_mcs_long_hs(sender, h8c7_disable_cabc,
					   sizeof(h8c7_disable_cabc), 0);
		mdelay(5);
		mdfld_dsi_send_gen_long_hs(sender, h8c7_mcs_protect_off, 4, 0);
		mdfld_dsi_send_mcs_long_hs(sender, h8c7_set_cabc_gain, 10, 0);
		mdfld_dsi_send_gen_long_hs(sender, h8c7_mcs_protect_on, 4, 0);
		DRM_INFO("%s enable h8c7 cabc\n", __func__);
	}
power_err:
	return err;
}

static int mdfld_dsi_h8c7_cmd_power_off(struct mdfld_dsi_config *dsi_config)
{
	struct mdfld_dsi_pkg_sender *sender =
		mdfld_dsi_get_pkg_sender(dsi_config);
	int err = 0;

	PSB_DEBUG_ENTRY("\n");

	if (!sender) {
		DRM_ERROR("Failed to get DSI packet sender\n");
		return -EINVAL;
	}

	/* turn off cabc */
	h8c7_disable_cabc[1] = 0x0;
	mdfld_dsi_send_mcs_long_lp(sender, h8c7_disable_cabc,
				   sizeof(h8c7_disable_cabc), 0);

	/*turn off backlight*/
	err = mdfld_dsi_send_mcs_long_lp(sender, h8c7_turn_off_backlight,
					 sizeof(h8c7_turn_off_backlight), 0);
	if (err) {
		DRM_ERROR("%s: failed to turn off backlight\n", __func__);
		goto out;
	}
	mdelay(1);


	/*turn off display */
	err = mdfld_dsi_send_dcs(sender,
		 set_display_off,
		 NULL,
		 0,
		 CMD_DATA_SRC_SYSTEM_MEM,
		 MDFLD_DSI_SEND_PACKAGE);
	if (err) {
		DRM_ERROR("sent set_display_off faild\n");
		goto out;
	}

	/*set tear off */
	err = mdfld_dsi_send_dcs(sender,
		 set_tear_off,
		 NULL,
		 0,
		 CMD_DATA_SRC_SYSTEM_MEM,
		 MDFLD_DSI_SEND_PACKAGE);
	if (err) {
		DRM_ERROR("sent set_tear_off faild\n");
		goto out;
	}

	/*Enter sleep mode */
	err = mdfld_dsi_send_dcs(sender,
			enter_sleep_mode,
			NULL,
			0,
			CMD_DATA_SRC_SYSTEM_MEM,
			MDFLD_DSI_SEND_PACKAGE);

	if (err) {
		DRM_ERROR("DCS 0x%x sent failed\n", enter_sleep_mode);
		goto out;
	}

	/**
	 * MIPI spec shows it must wait 5ms
	 * before sneding next command
	 */
	mdelay(5);

	/*enter deep standby mode*/
	err = mdfld_dsi_send_mcs_long_lp(sender, h8c7_mcs_protect_off, 4, 0);
	if (err) {
		DRM_ERROR("Failed to turn off protection\n");
		goto out;
	}

	err = mdfld_dsi_send_mcs_long_lp(sender, h8c7_set_power_dstb, 14, 0);
	if (err)
		DRM_ERROR("Failed to enter DSTB\n");
	mdelay(5);
	mdfld_dsi_send_mcs_long_lp(sender, h8c7_mcs_protect_on, 4, 0);

out:
	if (!IS_ERR(h8c7_regulator_status.regulator)) {
		if (h8c7_regulator_status.h8c7_mmc2_on) {
			h8c7_regulator_status.h8c7_mmc2_on = false;
			PSB_DEBUG_GENERAL("Begin to power off\n");
		} else
			DRM_ERROR("power off several times without on\n");
		regulator_disable(h8c7_regulator_status.regulator);
		PSB_DEBUG_GENERAL("After power off, regulator is %d\n",
			regulator_is_enabled(h8c7_regulator_status.regulator));
	}

	return err;
}

static
void h8c7_cmd_get_panel_info(int pipe, struct panel_info *pi)
{
	PSB_DEBUG_ENTRY("\n");

	if (pipe == 0) {
		pi->width_mm = PANEL_4DOT3_WIDTH;
		pi->height_mm = PANEL_4DOT3_HEIGHT;
	}
}

static
int mdfld_dsi_h8c7_cmd_detect(struct mdfld_dsi_config *dsi_config)
{
	int status;
	struct drm_device *dev = dsi_config->dev;
	struct mdfld_dsi_hw_registers *regs = &dsi_config->regs;
	u32 dpll_val, device_ready_val;
	int pipe = dsi_config->pipe;
	struct mdfld_dsi_pkg_sender *sender =
		mdfld_dsi_get_pkg_sender(dsi_config);

	PSB_DEBUG_ENTRY("\n");

	if (pipe == 0) {
		/*
		 * FIXME: WA to detect the panel connection status, and need to
		 * implement detection feature with get_power_mode DSI command.
		 */
		if (!ospm_power_using_hw_begin(OSPM_DISPLAY_ISLAND,
					OSPM_UHB_FORCE_POWER_ON)) {
			DRM_ERROR("hw begin failed\n");
			return -EAGAIN;
		}

		dpll_val = REG_READ(regs->dpll_reg);
		device_ready_val = REG_READ(regs->device_ready_reg);
		if ((device_ready_val & DSI_DEVICE_READY) &&
		    (dpll_val & DPLL_VCO_ENABLE)) {
			dsi_config->dsi_hw_context.panel_on = true;
			mdfld_dsi_send_gen_long_hs(sender, h8c7_mcs_protect_off, 4, 0);
			mdfld_dsi_send_gen_long_hs(sender, h8c7_set_disp_reg, 13, 0);
			mdfld_dsi_send_gen_long_hs(sender, h8c7_mcs_protect_on, 4, 0);

		} else {
			dsi_config->dsi_hw_context.panel_on = false;
			DRM_INFO("%s: panel is not initialized!\n", __func__);
		}

		status = MDFLD_DSI_PANEL_CONNECTED;

		ospm_power_using_hw_end(OSPM_DISPLAY_ISLAND);
	} else {
		DRM_INFO("%s: do NOT support dual panel\n", __func__);
		status = MDFLD_DSI_PANEL_DISCONNECTED;
	}

	return status;
}
int vsp_init_fw(struct drm_device *dev)
{
	struct drm_psb_private *dev_priv = dev->dev_private;
	struct vsp_private *vsp_priv = dev_priv->vsp_private;
	int ret = 0;
	const struct firmware *raw;
	unsigned char *ptr, *ma_ptr;
	struct vsp_secure_boot_header *boot_header;
	struct vsp_multi_app_blob_data *ma_header;
	unsigned long imr_addr;
	int imr_size;
	unsigned char *imr_ptr;
	unsigned int vrl_header_size = 736;
	const unsigned long vsp_magic_num = 0x50535624;
	const int FW_NAME_LEN = 30;
	char fw_name[FW_NAME_LEN];
	int name_ret;

	PSB_DEBUG_GENERAL("read firmware into buffer\n");

	name_ret = snprintf(fw_name, FW_NAME_LEN, "vsp.bin.%04x.%04x",
		 (int)spid.platform_family_id, (int)spid.hardware_id);
	if (name_ret > FW_NAME_LEN) {
		DRM_ERROR("failed to get fw name, ret %d vs expect %d\n",
			  name_ret, FW_NAME_LEN);
		/* no way */
		return -1;
	}

	/* try load with spid first */
	ret = request_firmware(&raw, fw_name, &dev->pdev->dev);
	if (ret < 0 || raw == NULL) {
		VSP_DEBUG("failed to load fw: %s, try to load different fw\n",
			fw_name);

		/* read firmware img */
		VSP_DEBUG("load vsp fw\n");
		if (IS_ANN_A0(dev))
			ret = request_firmware(&raw, FW_NAME_ANN,
					       &dev->pdev->dev);
		else if (IS_TNG_B0(dev))
			ret = request_firmware(&raw, FW_NAME_B0,
					       &dev->pdev->dev);
		else {
			DRM_ERROR("VSP secure fw: bad platform\n");
			raw = NULL;
		}
	}

	if (ret < 0 || raw == NULL) {
		DRM_ERROR("VSP: request_firmware failed: reason %d\n", ret);
		return -1;
	}

	if (raw->size < sizeof(struct vsp_secure_boot_header)) {
		DRM_ERROR("VSP: %s is not a correct firmware (size %d)\n",
				FW_NAME, raw->size);
		ret = -1;
		goto out;
	}

	ptr = (void *)raw->data;
	ma_ptr = (void *) raw->data + vrl_header_size;
	boot_header = (struct vsp_secure_boot_header *)
		(ptr + vrl_header_size);
	ma_header = (struct vsp_multi_app_blob_data *)
		(ma_ptr + boot_header->ma_header_offset);

	/* get firmware header */
	memcpy(&vsp_priv->boot_header, boot_header, sizeof(vsp_priv->boot_header));

	if (vsp_priv->boot_header.magic_number != VSP_SECURE_BOOT_MAGIC_NR) {
		DRM_ERROR("VSP: failed to load correct vsp firmware\n"
			  "FW magic number is wrong %x (should be %x)\n",
			  vsp_priv->boot_header.magic_number,
			  VSP_SECURE_BOOT_MAGIC_NR);
		ret = -1;
		goto out;
	}

	/* read application firmware image data (for state-buffer size, etc) */
	/* load the multi-app blob header */
	memcpy(&vsp_priv->ma_header, ma_header, sizeof(vsp_priv->ma_header));
	if (vsp_priv->ma_header.magic_number != VSP_MULTI_APP_MAGIC_NR) {
		DRM_ERROR("VSP: failed to load correct vsp firmware\n"
			  "FW magic number is wrong %x (should be %x)\n",
			  vsp_priv->ma_header.magic_number,
			  VSP_MULTI_APP_MAGIC_NR);
		ret = -1;
		goto out;
	}

	VSP_DEBUG("firmware secure header:\n");
	VSP_DEBUG("boot_header magic number %x\n", boot_header->magic_number);
	VSP_DEBUG("boot_text_offset %x\n", boot_header->boot_text_offset);
	VSP_DEBUG("boot_text_reg %x\n", boot_header->boot_text_reg);
	VSP_DEBUG("boot_icache_value %x\n", boot_header->boot_icache_value);
	VSP_DEBUG("boot_icache_reg %x\n", boot_header->boot_icache_reg);
	VSP_DEBUG("boot_pc_value %x\n", boot_header->boot_pc_value);
	VSP_DEBUG("boot_pc_reg %x\n", boot_header->boot_pc_reg);
	VSP_DEBUG("ma_header_offset %x\n", boot_header->ma_header_offset);
	VSP_DEBUG("ma_header_reg %x\n", boot_header->ma_header_reg);
	VSP_DEBUG("boot_start_value %x\n", boot_header->boot_start_value);
	VSP_DEBUG("boot_start_reg %x\n", boot_header->boot_start_reg);
	VSP_DEBUG("firmware ma_blob header:\n");
	VSP_DEBUG("ma_header magic number %x\n", ma_header->magic_number);
	VSP_DEBUG("offset_from_start %x\n", ma_header->offset_from_start);
	VSP_DEBUG("imr_state_buffer_addr %x\n", ma_header->imr_state_buffer_addr);
	VSP_DEBUG("imr_state_buffer_size %x\n", ma_header->imr_state_buffer_size);
	VSP_DEBUG("apps_default_context_buffer_size %x\n",
			ma_header->apps_default_context_buffer_size);

	/* get imr 11 region start address and size */
	imr_addr = intel_mid_msgbus_read32(PNW_IMR_MSG_PORT,
					   TNG_IMR11L_MSG_REGADDR);
	imr_addr <<= 10;
	VSP_DEBUG("IMR11 base address %p\n", imr_addr);

	imr_size = raw->size;

	/* map imr 11 */
	/* check if raw size is smaller than */
	/* ioremap the region */
	imr_ptr = ioremap(imr_addr, imr_size);
	if (!imr_ptr) {
		DRM_ERROR("failed to map imr_addr\n");
		ret = -1;
		goto out;
	}

	/* copy the firmware to imr 11 */
	memcpy(imr_ptr, ptr, raw->size);

	/* unmap the region */
	iounmap(imr_ptr);
#ifdef CONFIG_DX_SEP54
	ret = sepapp_image_verify(imr_addr, imr_size, 15, vsp_magic_num);
	if (ret) {
		DRM_ERROR("failed to verify vsp firmware, ret %x\n", ret);
		ret = -1;
		goto out;
	}
#endif

	vsp_priv->fw_loaded = VSP_FW_LOADED;
	vsp_priv->vsp_state = VSP_STATE_DOWN;

	vsp_priv->ctrl = (struct vsp_ctrl_reg *) (dev_priv->vsp_reg +
						  VSP_CONFIG_REG_SDRAM_BASE +
						  VSP_CONFIG_REG_START);
out:
	release_firmware(raw);

	return ret;
}