/***************************************************************************
 * Copyright (c) 2005-2009, Broadcom Corporation.
 *
 *  Name: crystalhd_fleafuncs.c
 *
 *  Description:
 *		BCM70015 Linux driver HW layer.
 *
 *  HISTORY:
 *
 **********************************************************************
 * This file is part of the crystalhd device driver.
 *
 * This driver is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, version 2 of the License.
 *
 * This driver is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this driver.  If not, see <http://www.gnu.org/licenses/>.
 **********************************************************************/

#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <asm/tsc.h>
#include <asm/msr.h>
#include "crystalhd_hw.h"
#include "crystalhd_fleafuncs.h"
#include "crystalhd_lnx.h"
#include "FleaDefs.h"
#include "crystalhd_flea_ddr.h"

#define OFFSETOF(_s_, _m_) ((size_t)(unsigned long)&(((_s_ *)0)->_m_))

void crystalhd_flea_core_reset(struct crystalhd_hw *hw)
{
	unsigned int pollCnt=0,regVal=0;

	dev_dbg(&hw->adp->pdev->dev,"[crystalhd_flea_core_reset]: Starting core reset\n");

	hw->pfnWriteDevRegister(hw->adp, BCHP_MISC3_RESET_CTRL,	0x01);

	pollCnt=0;
	while (1)
	{
		pollCnt++;
		regVal=0;

		msleep_interruptible(1);

		regVal = hw->pfnReadDevRegister(hw->adp, BCHP_MISC3_RESET_CTRL);

		if(!(regVal & 0x01))
		{
			/*
			-- Bit is 0, Reset is completed. Which means that
			-- wait for sometime and then allow other accesses.
			*/
			msleep_interruptible(1);
			break;
		}

		if(pollCnt > MAX_VALID_POLL_CNT)
		{
			printk("!!FATAL ERROR!! Core Reset Failure\n");
			break;
		}
	}

	msleep_interruptible(5);

	return;
}

void crystalhd_flea_disable_interrupts(struct crystalhd_hw *hw)
{
	union FLEA_INTR_BITS_COMMON IntrMaskReg;
	/*
	-- Mask everything except the reserved bits.
	*/
	IntrMaskReg.WholeReg =0xffffffff;
	IntrMaskReg.Reserved1=0;
	IntrMaskReg.Reserved2=0;
	IntrMaskReg.Reserved3=0;
	IntrMaskReg.Reserved4=0;

	hw->pfnWriteDevRegister(hw->adp, BCHP_INTR_INTR_MSK_SET_REG, IntrMaskReg.WholeReg);

	return;
}

void crystalhd_flea_enable_interrupts(struct crystalhd_hw *hw)
{
	union FLEA_INTR_BITS_COMMON IntrMaskReg;
	/*
	-- Clear The Mask for everything except the reserved bits.
	*/
	IntrMaskReg.WholeReg =0xffffffff;
	IntrMaskReg.Reserved1=0;
	IntrMaskReg.Reserved2=0;
	IntrMaskReg.Reserved3=0;
	IntrMaskReg.Reserved4=0;

	hw->pfnWriteDevRegister(hw->adp, BCHP_INTR_INTR_MSK_CLR_REG, IntrMaskReg.WholeReg);

	return;
}

void crystalhd_flea_clear_interrupts(struct crystalhd_hw *hw)
{
	union FLEA_INTR_BITS_COMMON	IntrStsValue;

	IntrStsValue.WholeReg = hw->pfnReadDevRegister(hw->adp, BCHP_INTR_INTR_STATUS);

	if(IntrStsValue.WholeReg)
	{
		hw->pfnWriteDevRegister(hw->adp, BCHP_INTR_INTR_CLR_REG, IntrStsValue.WholeReg);
		hw->pfnWriteDevRegister(hw->adp, BCHP_INTR_EOI_CTRL, 1);
	}

	return;
}

bool crystalhd_flea_detect_ddr3(struct crystalhd_hw *hw)
{
	uint32_t regVal = 0;

	/*Set the Multiplexer to select the GPIO-6*/
	regVal = hw->pfnReadDevRegister(hw->adp, BCHP_SUN_TOP_CTRL_PIN_MUX_CTRL_0);

	/*Make sure that the bits-24:27 are reset*/
	if(regVal & 0x0f000000)
	{
		regVal = regVal & 0xf0ffffff; /*Clear bit 24-27 for selecting GPIO_06*/
		hw->pfnWriteDevRegister(hw->adp, BCHP_SUN_TOP_CTRL_PIN_MUX_CTRL_0, regVal);
	}

	regVal=0;
	/*Set the Direction of GPIO-6*/
	regVal = hw->pfnReadDevRegister(hw->adp, BCHP_GIO_IODIR_LO);

	if(!(regVal & BC_BIT(6)))
	{
		/*Set the Bit number 6 to make the GPIO6 as input*/
		regVal |= BC_BIT(6);
		hw->pfnWriteDevRegister(hw->adp, BCHP_GIO_IODIR_LO, regVal);
	}

	regVal=0;
	regVal = hw->pfnReadDevRegister(hw->adp,	BCHP_GIO_DATA_LO);

	/*If this bit is clear then have DDR-3 else we have DDR-2*/
	if(!(regVal & BC_BIT(6)))
	{
		dev_dbg(&hw->adp->pdev->dev,"DDR-3 Detected\n");
		return true;
	}
	dev_dbg(&hw->adp->pdev->dev,"DDR-2 Detected\n");
	return false;
}

void crystalhd_flea_init_dram(struct crystalhd_hw *hw)
{
	int32_t ddr2_speed_grade[2];
	uint32_t sd_0_col_size, sd_0_bank_size, sd_0_row_size;
	uint32_t sd_1_col_size, sd_1_bank_size, sd_1_row_size;
	uint32_t ddr3_mode[2];
	uint32_t regVal;
	bool bDDR3Detected=false; /*Should be filled in using the detection logic. Default to DDR2 */

	/* On all designs we are using DDR2 or DDR3 x16 and running at a max of 400Mhz */
	/* Only one bank of DDR supported. The other is a dummy */

	ddr2_speed_grade[0] = DDR2_400MHZ;
	ddr2_speed_grade[1] = DDR2_400MHZ;
	sd_0_col_size = COL_BITS_10;
	sd_0_bank_size = BANK_SIZE_8;
	sd_0_row_size = ROW_SIZE_8K; /* DDR2 */
	/*	sd_0_row_size = ROW_SIZE_16K; // DDR3 */
	sd_1_col_size = COL_BITS_10;
	sd_1_bank_size = BANK_SIZE_8;
	sd_1_row_size = ROW_SIZE_8K;
	ddr3_mode[0] = 0;
	ddr3_mode[1] = 0;

	bDDR3Detected = crystalhd_flea_detect_ddr3(hw);
	if(bDDR3Detected)
	{
		ddr3_mode[0] = 1;
		sd_0_row_size = ROW_SIZE_16K; /* DDR3 */
		sd_1_row_size = ROW_SIZE_16K; /* DDR3 */

	}

	/* Step 1. PLL Init */
	crystalhd_flea_ddr_pll_config(hw, ddr2_speed_grade, 1, 0); /* only need to configure PLLs in TM0 */

	/* Step 2. DDR CTRL Init */
	crystalhd_flea_ddr_ctrl_init(hw, 0, ddr3_mode[0], ddr2_speed_grade[0], sd_0_col_size, sd_0_bank_size, sd_0_row_size, 0);

	/* Step 3 RTS Init - Real time scheduling memory arbiter */
	crystalhd_flea_ddr_arb_rts_init(hw);

	/* NAREN turn off ODT. The REF1 and SV1 and most customer designs allow this. */
	/* IF SOMEONE COMPLAINS ABOUT MEMORY OR DATA CORRUPTION LOOK HERE FIRST */

	/*hw->pfnWriteDevRegister(hw->adp, BCHP_DDR23_CTL_REGS_0_LOAD_EMODE_CMD, 0x02, false); */

	/*regVal = hw->pfnReadDevRegister(hw->adp, BCHP_DDR23_CTL_REGS_0_PARAMS3);
	regVal &= ~(BCHP_DDR23_CTL_REGS_0_PARAMS3_wr_odt_en_MASK);
	hw->pfnWriteDevRegister(hw->adp, BCHP_DDR23_CTL_REGS_0_PARAMS3, regVal);*/

	/*regVal = hw->pfnReadDevRegister(hw->adp, BCHP_DDR23_PHY_BYTE_LANE_1_DRIVE_PAD_CTL);
	regVal |= BCHP_DDR23_PHY_BYTE_LANE_1_DRIVE_PAD_CTL_seltxdrv_ci_MASK;
	hw->pfnWriteDevRegister(hw->adp, BCHP_DDR23_PHY_BYTE_LANE_1_DRIVE_PAD_CTL, regVal);

	regVal = hw->pfnReadDevRegister(hw->adp, BCHP_DDR23_PHY_BYTE_LANE_0_DRIVE_PAD_CTL);
	regVal |= BCHP_DDR23_PHY_BYTE_LANE_0_DRIVE_PAD_CTL_seltxdrv_ci_MASK;
	hw->pfnWriteDevRegister(hw->adp, BCHP_DDR23_PHY_BYTE_LANE_0_DRIVE_PAD_CTL, regVal);*/

	regVal = hw->pfnReadDevRegister(hw->adp, BCHP_DDR23_PHY_BYTE_LANE_1_CLOCK_PAD_DISABLE);
	regVal |= BCHP_DDR23_PHY_BYTE_LANE_1_CLOCK_PAD_DISABLE_clk_pad_dis_MASK;
	hw->pfnWriteDevRegister(hw->adp, BCHP_DDR23_PHY_BYTE_LANE_1_CLOCK_PAD_DISABLE, regVal);

	regVal = hw->pfnReadDevRegister(hw->adp, BCHP_DDR23_PHY_BYTE_LANE_0_READ_CONTROL);
	regVal &= ~(BCHP_DDR23_PHY_BYTE_LANE_0_READ_CONTROL_dq_odt_enable_MASK);
	hw->pfnWriteDevRegister(hw->adp, BCHP_DDR23_PHY_BYTE_LANE_0_READ_CONTROL, regVal);

	regVal = hw->pfnReadDevRegister(hw->adp, BCHP_DDR23_PHY_BYTE_LANE_1_READ_CONTROL);
	regVal &= ~(BCHP_DDR23_PHY_BYTE_LANE_1_READ_CONTROL_dq_odt_enable_MASK);
	hw->pfnWriteDevRegister(hw->adp, BCHP_DDR23_PHY_BYTE_LANE_1_READ_CONTROL, regVal);

	return;
}

uint32_t crystalhd_flea_reg_rd(struct crystalhd_adp *adp, uint32_t reg_off)
{
	uint32_t baseAddr = reg_off >> 16;
	void	*regAddr;

	if (!adp) {
		printk(KERN_ERR "%s: Invalid args\n", __func__);
		return 0;
	}

	if(baseAddr == 0 || baseAddr == FLEA_GISB_DIRECT_BASE) /* Direct Mapped Region */
	{
		regAddr = adp->i2o_addr + (reg_off & 0x0000FFFF);
		if(regAddr > (adp->i2o_addr + adp->pci_i2o_len)) {
			dev_err(&adp->pdev->dev, "%s: reg_off out of range: 0x%08x\n",
					__func__, reg_off);
			return 0;
		}
		return readl(regAddr);
	}
	else /* non directly mapped region */
	{
		if(adp->pci_i2o_len < 0xFFFF) {
			printk("Un-expected mapped region size\n");
			return 0;
		}
		regAddr = adp->i2o_addr + FLEA_GISB_INDIRECT_ADDRESS;
		writel(reg_off | 0x10000000, regAddr);
		regAddr = adp->i2o_addr + FLEA_GISB_INDIRECT_DATA;
		return readl(regAddr);
	}
}

void crystalhd_flea_reg_wr(struct crystalhd_adp *adp, uint32_t reg_off, uint32_t val)
{
	uint32_t baseAddr = reg_off >> 16;
	void	*regAddr;

	if (!adp) {
		printk(KERN_ERR "%s: Invalid args\n", __func__);
		return;
	}

	if(baseAddr == 0 || baseAddr == FLEA_GISB_DIRECT_BASE) /* Direct Mapped Region */
	{
		regAddr = adp->i2o_addr + (reg_off & 0x0000FFFF);
		if(regAddr > (adp->i2o_addr + adp->pci_i2o_len)) {
			dev_err(&adp->pdev->dev, "%s: reg_off out of range: 0x%08x\n",
					__func__, reg_off);
					return ;
		}
		writel(val, regAddr);
	}
	else /* non directly mapped region */
	{
		if(adp->pci_i2o_len < 0xFFFF) {
			printk("Un-expected mapped region size\n");
			return;
		}
		regAddr = adp->i2o_addr + FLEA_GISB_INDIRECT_ADDRESS;
		writel(reg_off | 0x10000000, regAddr);
		regAddr = adp->i2o_addr + FLEA_GISB_INDIRECT_DATA;
		writel(val, regAddr);
	}
}

/**
* crystalhd_flea_mem_rd - Read data from DRAM area.
* @adp: Adapter instance
* @start_off: Start offset.
* @dw_cnt: Count in dwords.
* @rd_buff: Buffer to copy the data from dram.
*
* Return:
*	Status.
*
* Dram read routine.
*/
BC_STATUS crystalhd_flea_mem_rd(struct crystalhd_hw *hw, uint32_t start_off,
								uint32_t dw_cnt, uint32_t *rd_buff)
{
	uint32_t ix = 0;
	uint32_t addr = start_off, base;

	if (!hw || !rd_buff) {
		printk(KERN_ERR "%s: Invalid arg\n", __func__);
		return BC_STS_INV_ARG;
	}

	if( hw->FleaPowerState == FLEA_PS_LP_COMPLETE ) {
		/*printk(KERN_ERR "%s: Flea power down, cann't read memory.\n", __func__); */
		return BC_STS_BUSY;
	}

	if((start_off + dw_cnt * 4) > FLEA_TOTAL_DRAM_SIZE) {
		printk(KERN_ERR "Access beyond DRAM limit at Addr 0x%x and size 0x%x words\n", start_off, dw_cnt);
		return BC_STS_ERROR;
	}

	/* Set the base addr for the 512kb window */
	hw->pfnWriteDevRegister(hw->adp, BCHP_MISC2_DIRECT_WINDOW_CONTROL,
							(addr & BCHP_MISC2_DIRECT_WINDOW_CONTROL_DIRECT_WINDOW_BASE_ADDR_MASK) | BCHP_MISC2_DIRECT_WINDOW_CONTROL_DIRECT_WINDOW_ENABLE_MASK);

	for (ix = 0; ix < dw_cnt; ix++) {
		rd_buff[ix] = readl(hw->adp->mem_addr + (addr & ~BCHP_MISC2_DIRECT_WINDOW_CONTROL_DIRECT_WINDOW_BASE_ADDR_MASK));
		base = addr & BCHP_MISC2_DIRECT_WINDOW_CONTROL_DIRECT_WINDOW_BASE_ADDR_MASK;
		addr += 4; /* DWORD access at all times */
		if (base != (addr & BCHP_MISC2_DIRECT_WINDOW_CONTROL_DIRECT_WINDOW_BASE_ADDR_MASK)) {
			/* Set the base addr for next 512kb window */
			hw->pfnWriteDevRegister(hw->adp, BCHP_MISC2_DIRECT_WINDOW_CONTROL,
										(addr & BCHP_MISC2_DIRECT_WINDOW_CONTROL_DIRECT_WINDOW_BASE_ADDR_MASK) | BCHP_MISC2_DIRECT_WINDOW_CONTROL_DIRECT_WINDOW_ENABLE_MASK);
		}
	}
	return BC_STS_SUCCESS;
}

/**
* crystalhd_flea_mem_wr - Write data to DRAM area.
* @adp: Adapter instance
* @start_off: Start offset.
* @dw_cnt: Count in dwords.
* @wr_buff: Data Buffer to be written.
*
* Return:
*	Status.
*
* Dram write routine.
*/
BC_STATUS crystalhd_flea_mem_wr(struct crystalhd_hw *hw, uint32_t start_off,
								uint32_t dw_cnt, uint32_t *wr_buff)
{
	uint32_t ix = 0;
	uint32_t addr = start_off, base;
	uint32_t temp;

	if (!hw || !wr_buff) {
		printk(KERN_ERR "%s: Invalid arg\n", __func__);
		return BC_STS_INV_ARG;
	}

	if( hw->FleaPowerState == FLEA_PS_LP_COMPLETE ) {
		/*printk(KERN_ERR "%s: Flea power down, cann't write memory.\n", __func__); */
		return BC_STS_BUSY;
	}

	if((start_off + dw_cnt * 4) > FLEA_TOTAL_DRAM_SIZE) {
		printk("Access beyond DRAM limit at Addr 0x%x and size 0x%x words\n", start_off, dw_cnt);
		return BC_STS_ERROR;
	}

	/* Set the base addr for the 512kb window */
	hw->pfnWriteDevRegister(hw->adp, BCHP_MISC2_DIRECT_WINDOW_CONTROL,
							(addr & BCHP_MISC2_DIRECT_WINDOW_CONTROL_DIRECT_WINDOW_BASE_ADDR_MASK) | BCHP_MISC2_DIRECT_WINDOW_CONTROL_DIRECT_WINDOW_ENABLE_MASK);

	for (ix = 0; ix < dw_cnt; ix++) {
		writel(wr_buff[ix], hw->adp->mem_addr + (addr & ~BCHP_MISC2_DIRECT_WINDOW_CONTROL_DIRECT_WINDOW_BASE_ADDR_MASK));
		base = addr & BCHP_MISC2_DIRECT_WINDOW_CONTROL_DIRECT_WINDOW_BASE_ADDR_MASK;
		addr += 4; /* DWORD access at all times */
		if (base != (addr & BCHP_MISC2_DIRECT_WINDOW_CONTROL_DIRECT_WINDOW_BASE_ADDR_MASK)) {
			/* Set the base addr for next 512kb window */
			hw->pfnWriteDevRegister(hw->adp, BCHP_MISC2_DIRECT_WINDOW_CONTROL,
									(addr & BCHP_MISC2_DIRECT_WINDOW_CONTROL_DIRECT_WINDOW_BASE_ADDR_MASK) | BCHP_MISC2_DIRECT_WINDOW_CONTROL_DIRECT_WINDOW_ENABLE_MASK);
		}
	}

	/*Dummy Read To Flush Memory Arbitrator*/
	crystalhd_flea_mem_rd(hw, start_off, 1, &temp);
	return BC_STS_SUCCESS;
}


static
void crystalhd_flea_runtime_power_up(struct crystalhd_hw *hw)
{
	uint32_t regVal;
	uint64_t currTick;
	uint32_t totalTick_Hi;
	uint32_t TickSpentInPD_Hi;
	uint64_t temp_64;
	long totalTick_Hi_f;
	long TickSpentInPD_Hi_f;

	/*printk("RT PU \n"); */

	/* NAREN This function restores clocks and power to the DRAM and to the core to bring the decoder back up to full operation */
	/* Start the DRAM controller clocks first */
	regVal = hw->pfnReadDevRegister(hw->adp, BCHP_CLK_PM_CTRL);
	regVal &= ~(BCHP_CLK_PM_CTRL_DIS_DDR_108_CLK_MASK |	BCHP_CLK_PM_CTRL_DIS_DDR_216_CLK_MASK);
	hw->pfnWriteDevRegister(hw->adp, BCHP_CLK_PM_CTRL, regVal);

	/* Delay to allow the DRAM clock to stabilize */
	udelay(25);

	/* Power Up PHY and start clocks on DRAM device */
	regVal = hw->pfnReadDevRegister(hw->adp, BCHP_DDR23_PHY_CONTROL_REGS_CLOCK_REG_CONTROL);
	regVal &= ~(BCHP_DDR23_PHY_CONTROL_REGS_CLOCK_REG_CONTROL_pwrdn_MASK);
	hw->pfnWriteDevRegister(hw->adp, BCHP_DDR23_PHY_CONTROL_REGS_CLOCK_REG_CONTROL, regVal);

	regVal = hw->pfnReadDevRegister(hw->adp, BCHP_DDR23_PHY_CONTROL_REGS_PLL_CONFIG);
	regVal &= ~(BCHP_DDR23_PHY_CONTROL_REGS_PLL_CONFIG_PWRDN_MASK);
	hw->pfnWriteDevRegister(hw->adp, BCHP_DDR23_PHY_CONTROL_REGS_PLL_CONFIG, regVal);

	hw->pfnWriteDevRegister(hw->adp, BCHP_DDR23_PHY_CONTROL_REGS_CLK_PM_CTRL,
		~(BCHP_DDR23_PHY_CONTROL_REGS_CLK_PM_CTRL_DIS_DDR_CLK_MASK));

	/* Delay to allow the PLL to lock */
	udelay(25);

	regVal = hw->pfnReadDevRegister(hw->adp, BCHP_DDR23_PHY_CONTROL_REGS_IDLE_PAD_CONTROL);
	regVal &= ~(BCHP_DDR23_PHY_CONTROL_REGS_IDLE_PAD_CONTROL_idle_MASK );
	hw->pfnWriteDevRegister(hw->adp, BCHP_DDR23_PHY_CONTROL_REGS_IDLE_PAD_CONTROL, regVal);

	regVal = hw->pfnReadDevRegister(hw->adp, BCHP_DDR23_PHY_BYTE_LANE_0_CLOCK_REG_CONTROL);
	regVal &= ~(BCHP_DDR23_PHY_BYTE_LANE_0_CLOCK_REG_CONTROL_pwrdn_MASK);
	hw->pfnWriteDevRegister(hw->adp, BCHP_DDR23_PHY_BYTE_LANE_0_CLOCK_REG_CONTROL, regVal);

	regVal = hw->pfnReadDevRegister(hw->adp, BCHP_DDR23_PHY_BYTE_LANE_1_CLOCK_REG_CONTROL);
	regVal &= ~(BCHP_DDR23_PHY_BYTE_LANE_1_CLOCK_REG_CONTROL_pwrdn_MASK);
	hw->pfnWriteDevRegister(hw->adp, BCHP_DDR23_PHY_BYTE_LANE_1_CLOCK_REG_CONTROL, regVal);

	regVal = hw->pfnReadDevRegister(hw->adp, BCHP_DDR23_PHY_BYTE_LANE_0_IDLE_PAD_CONTROL);
	regVal &= ~(BCHP_DDR23_PHY_BYTE_LANE_0_IDLE_PAD_CONTROL_idle_MASK );
	hw->pfnWriteDevRegister(hw->adp, BCHP_DDR23_PHY_BYTE_LANE_0_IDLE_PAD_CONTROL, regVal);

	regVal = hw->pfnReadDevRegister(hw->adp, BCHP_DDR23_PHY_BYTE_LANE_1_IDLE_PAD_CONTROL);
	regVal &= ~(BCHP_DDR23_PHY_BYTE_LANE_1_IDLE_PAD_CONTROL_idle_MASK );
	hw->pfnWriteDevRegister(hw->adp, BCHP_DDR23_PHY_BYTE_LANE_1_IDLE_PAD_CONTROL, regVal);

	/* Start Refresh Cycles from controller */
	regVal = hw->pfnReadDevRegister(hw->adp, BCHP_PRI_ARB_CONTROL_REGS_REFRESH_CTL_0);
	regVal |= BCHP_PRI_ARB_CONTROL_REGS_REFRESH_CTL_0_enable_MASK;
	hw->pfnWriteDevRegister(hw->adp, BCHP_PRI_ARB_CONTROL_REGS_REFRESH_CTL_0, regVal);

	/* turn off self-refresh */
	regVal = hw->pfnReadDevRegister(hw->adp, BCHP_DDR23_CTL_REGS_0_PARAMS2);
	regVal &= ~(BCHP_DDR23_CTL_REGS_0_PARAMS2_clke_MASK);
	hw->pfnWriteDevRegister(hw->adp, BCHP_DDR23_CTL_REGS_0_PARAMS2, regVal);

	udelay(5);

	/* Issue refresh cycle */
	hw->pfnWriteDevRegister(hw->adp, BCHP_DDR23_CTL_REGS_0_REFRESH_CMD, 0x60);

	/* Enable the ARM AVD and BLINK clocks */
	regVal = hw->pfnReadDevRegister(hw->adp, BCHP_CLK_PM_CTRL);

	regVal &= ~(BCHP_CLK_PM_CTRL_DIS_ARM_CLK_MASK |
				BCHP_CLK_PM_CTRL_DIS_AVD_CLK_MASK |
				BCHP_CLK_PM_CTRL_DIS_BLINK_108_CLK_MASK |
				BCHP_CLK_PM_CTRL_DIS_AVD_108_CLK_MASK |
				BCHP_CLK_PM_CTRL_DIS_BLINK_216_CLK_MASK |
				BCHP_CLK_PM_CTRL_DIS_AVD_216_CLK_MASK);

	hw->pfnWriteDevRegister(hw->adp, BCHP_CLK_PM_CTRL, 0x03000000);

	/* Start arbiter */
	hw->pfnWriteDevRegister(hw->adp, BCHP_PRI_ARB_CONTROL_REGS_MASTER_CTL, BCHP_PRI_ARB_CONTROL_REGS_MASTER_CTL_arb_disable_Enable);

#ifdef _POWER_HANDLE_AVD_WATCHDOG_
	/* Restore Watchdog timers */
	/* Make sure the timeouts do not happen */
	/*Outer Loop Watchdog timer */
	hw->pfnWriteDevRegister(hw->adp, BCHP_DECODE_CPUREGS_0_REG_WATCHDOG_TMR, hw->OLWatchDogTimer);

	/*//Inner Loop Watchdog timer */
	hw->pfnWriteDevRegister(hw->adp, BCHP_DECODE_CPUREGS2_0_REG_WATCHDOG_TMR, hw->ILWatchDogTimer);

#endif

	/*printk("RT Power Up Flea Complete\n"); */

	rdtscll(currTick);

	hw->TickSpentInPD += (currTick - hw->TickStartInPD);

	temp_64 = (hw->TickSpentInPD)>>24;
	TickSpentInPD_Hi = (uint32_t)(temp_64);
	TickSpentInPD_Hi_f = (long)TickSpentInPD_Hi;

	temp_64 = (currTick - hw->TickCntDecodePU)>>24;
	totalTick_Hi = (uint32_t)(temp_64);
	totalTick_Hi_f = (long)totalTick_Hi;

	if( totalTick_Hi_f <= 0 )
	{
		temp_64 = (hw->TickSpentInPD);
		TickSpentInPD_Hi = (uint32_t)(temp_64);
		TickSpentInPD_Hi_f = (long)TickSpentInPD_Hi;

		temp_64 = (currTick - hw->TickCntDecodePU);
		totalTick_Hi = (uint32_t)(temp_64);
		totalTick_Hi_f = (long)totalTick_Hi;
	}

	if( totalTick_Hi_f <= 0 )
	{
		printk("totalTick_Hi_f <= 0, set hw->PDRatio = 60\n");
		hw->PDRatio = 60;
	}
	else
		hw->PDRatio = (TickSpentInPD_Hi_f * 100) / totalTick_Hi_f;

	/*printk("Ticks currently spent in PD: 0x%llx Total: 0x%llx Ratio %d,\n", */
	/*	hw->TickSpentInPD, (currTick - hw->TickCntDecodePU), hw->PDRatio); */

	/* NAREN check if the PD ratio is greater than 75. If so, try to increase the PauseThreshold to improve the ratio */
	/* never go higher than the default threshold */
	if((hw->PDRatio > 75) && (hw->PauseThreshold < hw->DefaultPauseThreshold))
	{
		/*printk("Current PDRatio:%u, PauseThreshold:%u, DefaultPauseThreshold:%u, incress PauseThreshold.\n", */
		/*		hw->PDRatio, hw->PauseThreshold, hw->DefaultPauseThreshold); */
		hw->PauseThreshold++;
	}
	else
	{
		/*printk("Current PDRatio:%u, PauseThreshold:%u, DefaultPauseThreshold:%u, don't incress PauseThreshold.\n", */
		/*		hw->PDRatio, hw->PauseThreshold, hw->DefaultPauseThreshold); */
	}

	return;
}

static
void crystalhd_flea_runtime_power_dn(struct crystalhd_hw *hw)
{
	uint32_t regVal;
	uint32_t pollCnt;

	/*printk("RT PD \n"); */

	hw->DrvPauseCnt++;

	/* NAREN This function stops the decoder clocks including the AVD, ARM and DRAM */
	/* It powers down the DRAM device and places the DRAM into self-refresh */

#ifdef _POWER_HANDLE_AVD_WATCHDOG_
	/* Make sure the timeouts do not happen */
	/* Because the AVD drops to a debug prompt and stops decoding if it hits any watchdogs */
	/*Outer Loop Watchdog timer */
	regVal = hw->pfnReadDevRegister(hw->adp,
		BCHP_DECODE_CPUREGS_0_REG_WATCHDOG_TMR);

	hw->OLWatchDogTimer = regVal;
	hw->pfnWriteDevRegister(hw->adp,
		BCHP_DECODE_CPUREGS_0_REG_WATCHDOG_TMR,
		0xffffffff);

	/*Inner Loop Watchdog timer */
	regVal = hw->pfnReadDevRegister(hw->adp,
		BCHP_DECODE_CPUREGS2_0_REG_WATCHDOG_TMR);

	hw->ILWatchDogTimer = regVal;
	hw->pfnWriteDevRegister(hw->adp,
		BCHP_DECODE_CPUREGS2_0_REG_WATCHDOG_TMR,
		0xffffffff);
#endif

	/* Stop memory arbiter first to freese memory access */
	hw->pfnWriteDevRegister(hw->adp, BCHP_PRI_ARB_CONTROL_REGS_MASTER_CTL, BCHP_PRI_ARB_CONTROL_REGS_MASTER_CTL_arb_disable_Disable);

	/* delay at least 15us for memory transactions to complete */
	/* udelay(15); */

	/* Wait for MEMC to become idle. Continue even if we are no since worst case this would just mean higher power consumption */
	pollCnt=0;
	while (pollCnt++ <= 400) /*200 */
	{
		regVal = hw->pfnReadDevRegister(hw->adp, BCHP_DDR23_CTL_REGS_0_CTL_STATUS);

		if(regVal & BCHP_DDR23_CTL_REGS_0_CTL_STATUS_idle_MASK)
		{
			/* udelay(10); */
			break;
		}
		udelay(10);
	}

	/*If we failed Start the arbiter and return*/
	if(!(regVal & BCHP_DDR23_CTL_REGS_0_CTL_STATUS_idle_MASK))
	{
		printk("RT PD : failed Start the arbiter and return.\n");
		hw->pfnWriteDevRegister(hw->adp,
			BCHP_PRI_ARB_CONTROL_REGS_MASTER_CTL,
			BCHP_PRI_ARB_CONTROL_REGS_MASTER_CTL_arb_disable_Enable);
		return;
	}

	/* Disable the AVD, ARM and BLINK clocks*/
	/*regVal = hw->pfnReadDevRegister(hw->adp, BCHP_CLK_PM_CTRL);

	regVal |=	BCHP_CLK_PM_CTRL_DIS_ARM_CLK_MASK |
				BCHP_CLK_PM_CTRL_DIS_AVD_CLK_MASK |
				BCHP_CLK_PM_CTRL_DIS_BLINK_108_CLK_MASK |
				BCHP_CLK_PM_CTRL_DIS_AVD_108_CLK_MASK |
				BCHP_CLK_PM_CTRL_DIS_BLINK_216_CLK_MASK |
				BCHP_CLK_PM_CTRL_DIS_AVD_216_CLK_MASK;

	hw->pfnWriteDevRegister(hw->adp, BCHP_CLK_PM_CTRL, regValE);*/

	/* turn on self-refresh */
	regVal = hw->pfnReadDevRegister(hw->adp, BCHP_DDR23_CTL_REGS_0_PARAMS2);
	regVal |= BCHP_DDR23_CTL_REGS_0_PARAMS2_clke_MASK;
	hw->pfnWriteDevRegister(hw->adp, BCHP_DDR23_CTL_REGS_0_PARAMS2, regVal);

	/* Issue refresh cycle */
	hw->pfnWriteDevRegister(hw->adp,	BCHP_DDR23_CTL_REGS_0_REFRESH_CMD, 0x60);

	/* Stop Refresh Cycles from controller */
	regVal = hw->pfnReadDevRegister(hw->adp, BCHP_PRI_ARB_CONTROL_REGS_REFRESH_CTL_0);
	regVal &= ~(BCHP_PRI_ARB_CONTROL_REGS_REFRESH_CTL_0_enable_MASK);
	hw->pfnWriteDevRegister(hw->adp, BCHP_PRI_ARB_CONTROL_REGS_REFRESH_CTL_0, regVal);

	/* Check if we are in self-refresh. Continue even if we are no since worst case this would just mean higher power consumption */
	pollCnt=0;
	while(pollCnt++ < 100)
	{
		regVal = hw->pfnReadDevRegister(hw->adp, BCHP_DDR23_CTL_REGS_0_CTL_STATUS);

		if(!(regVal & BCHP_DDR23_CTL_REGS_0_CTL_STATUS_clke_MASK))
			break;
	}

	regVal = hw->pfnReadDevRegister(hw->adp, BCHP_CLK_PM_CTRL);

	regVal |=	BCHP_CLK_PM_CTRL_DIS_ARM_CLK_MASK |
				BCHP_CLK_PM_CTRL_DIS_AVD_CLK_MASK |
				BCHP_CLK_PM_CTRL_DIS_BLINK_108_CLK_MASK |
				BCHP_CLK_PM_CTRL_DIS_AVD_108_CLK_MASK |
				BCHP_CLK_PM_CTRL_DIS_BLINK_216_CLK_MASK |
				BCHP_CLK_PM_CTRL_DIS_AVD_216_CLK_MASK;

	hw->pfnWriteDevRegister(hw->adp, BCHP_CLK_PM_CTRL, regVal);

	/* Power down PHY and stop clocks on DRAM */
	regVal = hw->pfnReadDevRegister(hw->adp, BCHP_DDR23_PHY_BYTE_LANE_0_IDLE_PAD_CONTROL);

	regVal |=	BCHP_DDR23_PHY_BYTE_LANE_0_IDLE_PAD_CONTROL_idle_MASK |
				BCHP_DDR23_PHY_BYTE_LANE_0_IDLE_PAD_CONTROL_dm_iddq_MASK |
				BCHP_DDR23_PHY_BYTE_LANE_0_IDLE_PAD_CONTROL_dq_iddq_MASK |
				BCHP_DDR23_PHY_BYTE_LANE_0_IDLE_PAD_CONTROL_read_enb_iddq_MASK |
				BCHP_DDR23_PHY_BYTE_LANE_0_IDLE_PAD_CONTROL_dqs_iddq_MASK |
				BCHP_DDR23_PHY_BYTE_LANE_0_IDLE_PAD_CONTROL_clk_iddq_MASK;

	hw->pfnWriteDevRegister(hw->adp, BCHP_DDR23_PHY_BYTE_LANE_0_IDLE_PAD_CONTROL, regVal);

	regVal = hw->pfnReadDevRegister(hw->adp, BCHP_DDR23_PHY_BYTE_LANE_1_IDLE_PAD_CONTROL);

	regVal |=	BCHP_DDR23_PHY_BYTE_LANE_1_IDLE_PAD_CONTROL_idle_MASK |
				BCHP_DDR23_PHY_BYTE_LANE_1_IDLE_PAD_CONTROL_dm_iddq_MASK |
				BCHP_DDR23_PHY_BYTE_LANE_1_IDLE_PAD_CONTROL_dq_iddq_MASK |
				BCHP_DDR23_PHY_BYTE_LANE_1_IDLE_PAD_CONTROL_read_enb_iddq_MASK |
				BCHP_DDR23_PHY_BYTE_LANE_1_IDLE_PAD_CONTROL_dqs_iddq_MASK |
				BCHP_DDR23_PHY_BYTE_LANE_1_IDLE_PAD_CONTROL_clk_iddq_MASK;

	hw->pfnWriteDevRegister(hw->adp, BCHP_DDR23_PHY_BYTE_LANE_1_IDLE_PAD_CONTROL, regVal);

	regVal = hw->pfnReadDevRegister(hw->adp, BCHP_DDR23_PHY_BYTE_LANE_0_CLOCK_REG_CONTROL);
	regVal |= BCHP_DDR23_PHY_BYTE_LANE_0_CLOCK_REG_CONTROL_pwrdn_MASK;
	hw->pfnWriteDevRegister(hw->adp, BCHP_DDR23_PHY_BYTE_LANE_0_CLOCK_REG_CONTROL, regVal);

	regVal = hw->pfnReadDevRegister(hw->adp, BCHP_DDR23_PHY_BYTE_LANE_1_CLOCK_REG_CONTROL);
	regVal |= BCHP_DDR23_PHY_BYTE_LANE_1_CLOCK_REG_CONTROL_pwrdn_MASK;
	hw->pfnWriteDevRegister(hw->adp, BCHP_DDR23_PHY_BYTE_LANE_1_CLOCK_REG_CONTROL, regVal);

	regVal = hw->pfnReadDevRegister(hw->adp, BCHP_DDR23_PHY_CONTROL_REGS_IDLE_PAD_CONTROL);
	regVal |=	BCHP_DDR23_PHY_CONTROL_REGS_IDLE_PAD_CONTROL_idle_MASK |
				BCHP_DDR23_PHY_CONTROL_REGS_IDLE_PAD_CONTROL_ctl_iddq_MASK |
				BCHP_DDR23_PHY_CONTROL_REGS_IDLE_PAD_CONTROL_rxenb_MASK |
				BCHP_DDR23_PHY_CONTROL_REGS_IDLE_PAD_CONTROL_cke_reb_MASK;
	hw->pfnWriteDevRegister(hw->adp, BCHP_DDR23_PHY_CONTROL_REGS_IDLE_PAD_CONTROL, regVal);

	hw->pfnWriteDevRegister(hw->adp, BCHP_DDR23_PHY_CONTROL_REGS_CLK_PM_CTRL, BCHP_DDR23_PHY_CONTROL_REGS_CLK_PM_CTRL_DIS_DDR_CLK_MASK);

	regVal = hw->pfnReadDevRegister(hw->adp, BCHP_DDR23_PHY_CONTROL_REGS_PLL_CONFIG);
	regVal |= BCHP_DDR23_PHY_CONTROL_REGS_PLL_CONFIG_PWRDN_MASK;
	hw->pfnWriteDevRegister(hw->adp, BCHP_DDR23_PHY_CONTROL_REGS_PLL_CONFIG, regVal);

	regVal = hw->pfnReadDevRegister(hw->adp, BCHP_DDR23_PHY_CONTROL_REGS_CLOCK_REG_CONTROL);
	regVal |= BCHP_DDR23_PHY_CONTROL_REGS_CLOCK_REG_CONTROL_pwrdn_MASK;
	hw->pfnWriteDevRegister(hw->adp, BCHP_DDR23_PHY_CONTROL_REGS_CLOCK_REG_CONTROL, regVal);

	/* Finally clock off the DRAM controller */
	regVal = hw->pfnReadDevRegister(hw->adp, BCHP_CLK_PM_CTRL);
	regVal |=	BCHP_CLK_PM_CTRL_DIS_DDR_108_CLK_MASK |	BCHP_CLK_PM_CTRL_DIS_DDR_216_CLK_MASK;
	hw->pfnWriteDevRegister(hw->adp, BCHP_CLK_PM_CTRL, regVal);

	/* udelay(20); */

	/*printk("RT Power Down Flea Complete\n"); */

	/* Measure how much time we spend in idle */
	rdtscll(hw->TickStartInPD);

	return;
}

bool crystalhd_flea_detect_fw_alive(struct crystalhd_hw *hw)
{
	uint32_t pollCnt		= 0;
	uint32_t hbCnt			= 0;
	uint32_t heartBeatReg1	= 0;
	uint32_t heartBeatReg2	= 0;
	bool	 bRetVal		= false;

	heartBeatReg1 = hw->pfnReadDevRegister(hw->adp, HEART_BEAT_REGISTER);
	while(1)
	{
		heartBeatReg2 = hw->pfnReadDevRegister(hw->adp, HEART_BEAT_REGISTER);
		if(heartBeatReg1 != heartBeatReg2) {
			hbCnt++;
			heartBeatReg1 = heartBeatReg2;
		}

		if(hbCnt >= HEART_BEAT_POLL_CNT) {
			bRetVal = true;
			break;
		}

		pollCnt++;
		if(pollCnt >= FLEA_MAX_POLL_CNT) {
			bRetVal = false;
			break;
		}

		msleep_interruptible(1);
	}

	return bRetVal;
}

void crystalhd_flea_handle_PicQSts_intr(struct crystalhd_hw *hw)
{
	uint32_t	newChBitmap=0;

	newChBitmap = hw->pfnReadDevRegister(hw->adp, RX_DMA_PIC_QSTS_MBOX);

	hw->PicQSts = newChBitmap;

	/* -- For link we were enabling the capture on format change
	   -- For Flea, we will get a PicQSts interrupt where we will
	   -- enable the capture. */

	if(hw->RxCaptureState != 1)
	{
		hw->RxCaptureState = 1;
	}
}

void crystalhd_flea_update_tx_buff_info(struct crystalhd_hw *hw)
{
	TX_INPUT_BUFFER_INFO	TxBuffInfo;
	uint32_t ReadSzInDWords=0;

	ReadSzInDWords = (sizeof(TxBuffInfo) - sizeof(TxBuffInfo.Reserved))/4;
	hw->pfnDevDRAMRead(hw, hw->TxBuffInfoAddr, ReadSzInDWords, (uint32_t*)&TxBuffInfo);

	if(TxBuffInfo.DramBuffAdd % 4)
	{
		printk("Tx Err:: DWORD UNAligned Tx Addr. Not Updating\n");
		return;
	}

	hw->TxFwInputBuffInfo.DramBuffAdd			= TxBuffInfo.DramBuffAdd;
	hw->TxFwInputBuffInfo.DramBuffSzInBytes		= TxBuffInfo.DramBuffSzInBytes;
	hw->TxFwInputBuffInfo.Flags					= TxBuffInfo.Flags;
	hw->TxFwInputBuffInfo.HostXferSzInBytes		= TxBuffInfo.HostXferSzInBytes;
	hw->TxFwInputBuffInfo.SeqNum				= TxBuffInfo.SeqNum;

	return;
}

/* was HWFleaNotifyFllChange */
void crystalhd_flea_notify_fll_change(struct crystalhd_hw *hw, bool bCleanupContext)
{
	unsigned long flags = 0;
	uint32_t freeListLen = 0;
	/*
	* When we are doing the cleanup we should update DRAM only if the
	* firmware is running. So Detect the heart beat.
	*/
	if(bCleanupContext && (!crystalhd_flea_detect_fw_alive(hw)))
		return;

	spin_lock_irqsave(&hw->lock, flags);
	freeListLen = crystalhd_dioq_count(hw->rx_freeq);
	hw->pfnDevDRAMWrite(hw, hw->FleaFLLUpdateAddr, 1, &freeListLen);
	spin_unlock_irqrestore(&hw->lock, flags);

	return;
}


static
void crystalhd_flea_init_power_state(struct crystalhd_hw *hw)
{
	hw->FleaEnablePWM = false;	/* enable by default */
	hw->FleaPowerState = FLEA_PS_NONE;
}

static
bool crystalhd_flea_set_power_state(struct crystalhd_hw *hw,
					enum FLEA_POWER_STATES	NewState)
{
	bool StChangeSuccess=false;
	uint32_t tempFLL = 0;
	uint32_t freeListLen = 0;
	BC_STATUS sts;
	struct crystalhd_rx_dma_pkt *rx_pkt = NULL;

	freeListLen = crystalhd_dioq_count(hw->rx_freeq);

	switch(NewState)
	{
		case FLEA_PS_ACTIVE:
		{
			/*Transition to Active State*/
			if(hw->FleaPowerState == FLEA_PS_LP_PENDING)
			{
				StChangeSuccess = true;
				hw->FleaPowerState = FLEA_PS_ACTIVE;
				/* Write the correct FLL to FW */
				hw->pfnDevDRAMWrite(hw,
									hw->FleaFLLUpdateAddr,
									1,
									&freeListLen);
				/* We need to check to post here because we may never get a context to post otherwise */
				if(hw->PicQSts != 0)
				{
					rx_pkt = crystalhd_dioq_fetch(hw->rx_freeq);
					if (rx_pkt)
						sts = hw->pfnPostRxSideBuff(hw, rx_pkt);
				}
				/*printk(" Success\n"); */

			}else if(hw->FleaPowerState == FLEA_PS_LP_COMPLETE){
				crystalhd_flea_runtime_power_up(hw);
				StChangeSuccess = true;
				hw->FleaPowerState = FLEA_PS_ACTIVE;
				/* Write the correct FLL to FW */
				hw->pfnDevDRAMWrite(hw,
										hw->FleaFLLUpdateAddr,
										1,
										&freeListLen);
				/* Now check if we missed processing PiQ and TXFIFO interrupts when we were in power down */
				if (hw->PwrDwnPiQIntr)
				{
					crystalhd_flea_handle_PicQSts_intr(hw);
					hw->PwrDwnPiQIntr = false;
				}
				/* We need to check to post here because we may never get a context to post otherwise */
				if(hw->PicQSts != 0)
				{
					rx_pkt = crystalhd_dioq_fetch(hw->rx_freeq);
					if (rx_pkt)
						sts = hw->pfnPostRxSideBuff(hw, rx_pkt);
				}
				if (hw->PwrDwnTxIntr)
				{
					crystalhd_flea_update_tx_buff_info(hw);
					hw->PwrDwnTxIntr = false;
				}

			}
			break;
		}

		case FLEA_PS_LP_PENDING:
		{
			if(hw->FleaPowerState != FLEA_PS_ACTIVE)
			{
				break;
			}

			/*printk(" Success\n"); */

			StChangeSuccess = true;
			/* Write 0 FLL to FW to prevent it from sending PQ*/
			hw->pfnDevDRAMWrite(hw,
									hw->FleaFLLUpdateAddr,
									1,
									&tempFLL);
			hw->FleaPowerState = FLEA_PS_LP_PENDING;
			break;
		}

		case FLEA_PS_LP_COMPLETE:
		{
			if( (hw->FleaPowerState == FLEA_PS_ACTIVE) ||
			    (hw->FleaPowerState == FLEA_PS_LP_PENDING)) {
				/* Write 0 FLL to FW to prevent it from sending PQ*/
				hw->pfnDevDRAMWrite(hw,
									hw->FleaFLLUpdateAddr,
									1,
									&tempFLL);
				crystalhd_flea_runtime_power_dn(hw);
				StChangeSuccess = true;
				hw->FleaPowerState = FLEA_PS_LP_COMPLETE;

			}
			break;
		}
		default:
			break;
	}

	return StChangeSuccess;
}

/*
* Look At Different States and List Status and decide on
* Next Logical State To Be In.
*/
static
void crystalhd_flea_set_next_power_state(struct crystalhd_hw *hw,
						enum FLEA_STATE_CH_EVENT		PowerEvt)
{
	enum FLEA_POWER_STATES NextPS;
	NextPS = hw->FleaPowerState;

	if( hw->FleaEnablePWM == false )
	{
		hw->FleaPowerState = FLEA_PS_ACTIVE;
		return;
	}

/*	printk("Trying Power State Transition from %x Because Of Event:%d \n", */
/*			hw->FleaPowerState, */
/*			PowerEvt); */

	if(PowerEvt == FLEA_EVT_STOP_DEVICE)
	{
		hw->FleaPowerState = FLEA_PS_STOPPED;
		return;
	}

	if(PowerEvt == FLEA_EVT_START_DEVICE)
	{
		hw->FleaPowerState = FLEA_PS_ACTIVE;
		return;
	}

	switch(hw->FleaPowerState)
	{
		case FLEA_PS_ACTIVE:
		{
			if(PowerEvt == FLEA_EVT_FLL_CHANGE)
			{
				/*Ready List Was Decremented. */
				/*printk("1:TxL0Sts:%x TxL1Sts:%x EmptyCnt:%x RxL0Sts:%x RxL1Sts:%x FwCmdCnt:%x\n", */
				/*	hw->TxList0Sts, */
				/*	hw->TxList1Sts, */
				/*	hw->EmptyCnt, */
				/*	hw->rx_list_sts[0], */
				/*	hw->rx_list_sts[1], */
				/*	hw->FwCmdCnt); */

				if( (hw->TxList0Sts == ListStsFree)	&&
					(hw->TxList1Sts == ListStsFree) &&
					(!hw->EmptyCnt) && /*We have Not Indicated Any Empty Fifo to Application*/
					(!hw->SingleThreadAppFIFOEmpty) && /*for single threaded apps*/
					(!(hw->rx_list_sts[0] && rx_waiting_y_intr)) &&
					(!(hw->rx_list_sts[1] && rx_waiting_y_intr)) &&
					(!hw->FwCmdCnt))
				{
					NextPS = FLEA_PS_LP_COMPLETE;
				}else{
					NextPS = FLEA_PS_LP_PENDING;
				}
			}

			break;
		}

		case FLEA_PS_LP_PENDING:
		{
			if( (PowerEvt == FLEA_EVT_FW_CMD_POST) ||
				(PowerEvt == FLEA_EVT_FLL_CHANGE))
			{
				NextPS = FLEA_PS_ACTIVE;
			}else if(PowerEvt == FLEA_EVT_CMD_COMP){

				/*printk("2:TxL0Sts:%x TxL1Sts:%x EmptyCnt:%x STAppFIFOEmpty:%x RxL0Sts:%x RxL1Sts:%x FwCmdCnt:%x\n", */
				/*	hw->TxList0Sts, */
				/*	hw->TxList1Sts, */
				/*	hw->EmptyCnt, */
				/*	hw->SingleThreadAppFIFOEmpty, */
				/*	hw->rx_list_sts[0], */
				/*	hw->rx_list_sts[1], */
				/*	hw->FwCmdCnt); */

				if( (hw->TxList0Sts == ListStsFree)	&&
					(hw->TxList1Sts == ListStsFree) &&
					(!hw->EmptyCnt) &&	/*We have Not Indicated Any Empty Fifo to Application*/
					(!hw->SingleThreadAppFIFOEmpty) && /*for single threaded apps*/
					(!(hw->rx_list_sts[0] && rx_waiting_y_intr)) &&
					(!(hw->rx_list_sts[1] && rx_waiting_y_intr)) &&
					(!hw->FwCmdCnt))
				{
					NextPS = FLEA_PS_LP_COMPLETE;
				}
			}
			break;
		}
		case FLEA_PS_LP_COMPLETE:
		{
			if( (PowerEvt == FLEA_EVT_FLL_CHANGE) ||
				(PowerEvt == FLEA_EVT_FW_CMD_POST))
			{
				NextPS = FLEA_PS_ACTIVE;
			}

			break;
		}
		default:
		{
			printk("Invalid Flea Power State %x\n",
				hw->FleaPowerState);

			break;
		}
	}

	if(hw->FleaPowerState != NextPS)
	{
		printk("%s:State Transition [FromSt:%x ToSt:%x] Because Of Event:%d \n",
			__FUNCTION__,
			hw->FleaPowerState,
			NextPS,
			PowerEvt);

		crystalhd_flea_set_power_state(hw,NextPS);
	}

	return;
}

/* was FleaSetRxPicFireAddr */
#if 0
static
void crystalhd_flea_set_rx_pic_fire_addr(struct crystalhd_hw *hw, uint32_t BorshContents)
{
	hw->FleaRxPicDelAddr = BorshContents + 1 + HOST_TO_FW_PIC_DEL_INFO_ADDR;
	hw->FleaFLLUpdateAddr = BorshContents + 1 + HOST_TO_FW_FLL_ADDR;

	return;
}
#endif

void crystalhd_flea_init_temperature_measure (struct crystalhd_hw *hw, bool bTurnOn)
{
	hw->TemperatureRegVal=0;

	if(bTurnOn) {
		hw->pfnWriteDevRegister(hw->adp, BCHP_CLK_TEMP_MON_CTRL, 0x3);
		hw->pfnWriteDevRegister(hw->adp, BCHP_CLK_TEMP_MON_CTRL, 0x203);
	} else {
		hw->pfnWriteDevRegister(hw->adp, BCHP_CLK_TEMP_MON_CTRL, 0x103);
	}

	return;
}

/* was HwFleaUpdateTempInfo */
void crystalhd_flea_update_temperature(struct crystalhd_hw *hw)
{
	uint32_t	regVal = 0;

	regVal = hw->pfnReadDevRegister(hw->adp, BCHP_CLK_TEMP_MON_STATUS);
	hw->TemperatureRegVal = regVal;

	return;
}

/**
* crystalhd_flea_download_fw - Write data to DRAM area.
* @adp: Adapter instance
* @pBuffer: Buffer pointer for the FW data.
* @buffSz: data size in bytes.
*
* Return:
*	Status.
*
* Flea firmware download routine.
*/
BC_STATUS crystalhd_flea_download_fw(struct crystalhd_hw *hw, uint8_t *pBuffer, uint32_t buffSz)
{
	uint32_t pollCnt=0,regVal=0;
	uint32_t borchStachAddr=0;
	uint32_t *pCmacSig=NULL,cmacOffset=0,i=0;
	/*uint32_t BuffSz = (BuffSzInDWords * 4); */
	/*uint32_t HBCnt=0; */

	bool bRetVal = true;
	bool bSecure = true; // Default production cards. Can be false only for internal Broadcom dev cards

	dev_dbg(&hw->adp->pdev->dev, "[%s]: Sz:%d\n", __func__, buffSz);

/*
 *-- Step 1. Enable the SRCUBBING and DRAM SCRAMBLING
 *-- Step 2. Poll for SCRAM_KEY_DONE_INT.
 *-- Step 3. Write the BORCH and STARCH addresses.
 *-- Step 4. Write the firmware to DRAM.
 *-- Step 5. Write the CMAC to SCRUB->CMAC registers.
 *-- Step 6. Write the ARM run bit to 1.
 *-- Step 7. Poll for BOOT verification done interrupt.
 */

	/* First validate that we got data in the FW buffer */
	if (buffSz == 0)
		return BC_STS_ERROR;

/*-- Step 1. Enable the SRCUBBING and DRAM SCRAMBLING. */
/*   Can we set both the bits at the same time?? Security Arch Doc describes the steps */
/*   and the first step is to enable scrubbing and then scrambling. */

	if(bSecure)
	{
		dev_dbg(&hw->adp->pdev->dev,"[crystalhd_flea_download_fw]: step 1. Enable scrubbing\n");

		/* Enable Scrubbing */
		regVal = hw->pfnReadDevRegister(hw->adp, BCHP_SCRUB_CTRL_SCRUB_ENABLE);
		regVal |= SCRUB_ENABLE_BIT;
		hw->pfnWriteDevRegister(hw->adp, BCHP_SCRUB_CTRL_SCRUB_ENABLE, regVal);

		/* Enable Scrambling */
		regVal |= DRAM_SCRAM_ENABLE_BIT;
		hw->pfnWriteDevRegister(hw->adp, BCHP_SCRUB_CTRL_SCRUB_ENABLE, regVal);


		//-- Step 2. Poll for SCRAM_KEY_DONE_INT.
		dev_dbg(&hw->adp->pdev->dev,"[crystalhd_flea_download_fw]: step 2. Poll for SCRAM_KEY_DONE_INT\n");

		pollCnt=0;
		while(pollCnt < FLEA_MAX_POLL_CNT)
		{
			regVal = hw->pfnReadDevRegister(hw->adp, BCHP_WRAP_MISC_INTR2_PCI_STATUS);

			if(regVal & SCRAM_KEY_DONE_INT_BIT)
				break;

			pollCnt++;
			msleep_interruptible(1); /*1 Milli Sec delay*/
		}

		/* -- Will Assert when we do not see SCRAM_KEY_DONE_INTERRUPT */
		if(!(regVal & SCRAM_KEY_DONE_INT_BIT))
		{
			dev_err(&hw->adp->pdev->dev,"[crystalhd_flea_download_fw]: step 2. Did not get scram key done interrupt.\n");
			return BC_STS_ERROR;
		}
	}

	/*Clear the interrupts by writing the register value back*/
	regVal &= 0x00FFFFFF; /*Mask off the reserved bits.[24-31] */
	hw->pfnWriteDevRegister(hw->adp, BCHP_WRAP_MISC_INTR2_PCI_CLEAR, regVal);

/*-- Step 3. Write the BORCH and STARCH addresses. */
	borchStachAddr = GetScrubEndAddr(buffSz);
	if(!bSecure)
		borchStachAddr = (buffSz - 1) & BCHP_SCRUB_CTRL_BORCH_END_ADDRESS_BORCH_END_ADDR_MASK;

	hw->pfnWriteDevRegister(hw->adp, BCHP_SCRUB_CTRL_BORCH_END_ADDRESS, borchStachAddr);
	hw->pfnWriteDevRegister(hw->adp, BCHP_SCRUB_CTRL_STARCH_END_ADDRESS, borchStachAddr);

	/*
	 *	Now the command address is
	 *	relative to firmware file size.
	 */
	/*FWIFSetFleaCmdAddr(pHWExt->pFwExt, */
	/*		borchStachAddr+1+DDRADDR_4_FWCMDS); */

	hw->fwcmdPostAddr = borchStachAddr+1+DDRADDR_4_FWCMDS;
	hw->fwcmdPostMbox = FW_CMD_POST_MBOX;
	hw->fwcmdRespMbox = FW_CMD_RES_MBOX;
	/*FleaSetRxPicFireAddr(pHWExt,borchStachAddr); */
	hw->FleaRxPicDelAddr = borchStachAddr + 1 + HOST_TO_FW_PIC_DEL_INFO_ADDR;
	hw->FleaFLLUpdateAddr = borchStachAddr + 1 + HOST_TO_FW_FLL_ADDR;

	dev_dbg(&hw->adp->pdev->dev,"[crystalhd_flea_download_fw]: step 3. Write the BORCH and STARCH addresses. %x:%x, %x:%x\n",
			BCHP_SCRUB_CTRL_BORCH_END_ADDRESS,
			borchStachAddr,
			BCHP_SCRUB_CTRL_STARCH_END_ADDRESS,
			borchStachAddr );

/*-- Step 4. Write the firmware to DRAM. [Without the Signature, 32-bit access to DRAM] */

	dev_dbg(&hw->adp->pdev->dev,"[crystalhd_flea_download_fw]: step 4. Write the firmware to DRAM. Sz:%d Bytes\n",
			buffSz - FLEA_FW_SIG_LEN_IN_BYTES - LENGTH_FIELD_SIZE);

	if(bSecure)
		hw->pfnDevDRAMWrite(hw, FW_DOWNLOAD_START_ADDR, (buffSz - FLEA_FW_SIG_LEN_IN_BYTES - LENGTH_FIELD_SIZE)/4, (uint32_t *)pBuffer);
	else
		hw->pfnDevDRAMWrite(hw, FW_DOWNLOAD_START_ADDR, buffSz/4, (uint32_t*)pBuffer);

/* -- Step 5. Write the signature to CMAC register. */
/*
-- This is what we need to write to CMAC registers.
==================================================================================
Register							Offset				Boot Image CMAC
														Value
==================================================================================
BCHP_SCRUB_CTRL_BI_CMAC_31_0		0x000f600c			CMAC Bits[31:0]
BCHP_SCRUB_CTRL_BI_CMAC_63_32		0x000f6010			CMAC Bits[63:32]
BCHP_SCRUB_CTRL_BI_CMAC_95_64		0x000f6014			CMAC Bits[95:64]
BCHP_SCRUB_CTRL_BI_CMAC_127_96		0x000f6018			CMAC Bits[127:96]
==================================================================================
*/

	if(bSecure)
	{
		dev_dbg(&hw->adp->pdev->dev,"[crystalhd_flea_download_fw]: step 5. Write the signature to CMAC register.\n");
		cmacOffset = buffSz - FLEA_FW_SIG_LEN_IN_BYTES;
		pCmacSig = (uint32_t *) &pBuffer[cmacOffset];

		for(i=0;i < FLEA_FW_SIG_LEN_IN_DWORD;i++)
		{
			uint32_t offSet = (BCHP_SCRUB_CTRL_BI_CMAC_127_96 - (i * 4));

			hw->pfnWriteDevRegister(hw->adp, offSet, cpu_to_be32(*pCmacSig));

			pCmacSig++;
		}
	}

/*-- Step 6. Write the ARM run bit to 1. */
/*   We need a write back because we do not want to change other bits */
	dev_dbg(&hw->adp->pdev->dev,"[crystalhd_flea_download_fw]: step 6. Write the ARM run bit to 1.\n");

	regVal = hw->pfnReadDevRegister(hw->adp, BCHP_ARMCR4_BRIDGE_REG_BRIDGE_CTL);
	regVal |= ARM_RUN_REQ_BIT;
	hw->pfnWriteDevRegister(hw->adp, BCHP_ARMCR4_BRIDGE_REG_BRIDGE_CTL, regVal);

	if(bSecure)
	{
		/* -- Step 7. Poll for Boot Verification done/failure interrupt.*/
		dev_dbg(&hw->adp->pdev->dev,"[crystalhd_flea_download_fw]: step 7. Poll for Boot Verification done/failure interrupt.\n");
		pollCnt=0;
		while(1)
		{
			regVal = hw->pfnReadDevRegister(hw->adp, BCHP_WRAP_MISC_INTR2_PCI_STATUS);

			if(regVal & BOOT_VER_FAIL_BIT )
			{
				dev_err(&hw->adp->pdev->dev,"[crystalhd_flea_download_fw]: step 7. Error bit occured. RetVal:%x\n", regVal);

				bRetVal = false;
				break;
			}

			if(regVal & BOOT_VER_DONE_BIT)
			{
				dev_dbg(&hw->adp->pdev->dev,"[crystalhd_flea_download_fw]: step 7. Done  RetVal:%x\n", regVal);

				bRetVal = true; /*This is the only place we return TRUE from*/
				break;
			}

			pollCnt++;
			if( pollCnt >= FLEA_MAX_POLL_CNT )
			{
				dev_err(&hw->adp->pdev->dev,"[crystalhd_flea_download_fw]: step 7. Both done and failure bits are not set.\n");
				bRetVal = false;
				break;
			}

			msleep_interruptible(5); /*5 Milli Sec delay*/
		}

		if( !bRetVal )
		{
			dev_info(&hw->adp->pdev->dev,"[crystalhd_flea_download_fw]: step 7. Firmware image signature failure.\n");
			return BC_STS_ERROR;
		}

		/*Clear the interrupts by writing the register value back*/
		regVal &= 0x00FFFFFF; //Mask off the reserved bits.[24-31]
		hw->pfnWriteDevRegister(hw->adp, BCHP_WRAP_MISC_INTR2_PCI_CLEAR, regVal);

		msleep_interruptible(10); /*10 Milli Sec delay*/
	}
	else
		bRetVal = true;

	/*
	   -- It was seen on Dell390 systems that the firmware command was fired before the
	   -- firmware was actually ready to accept the firmware commands. The driver did
	   -- not recieve a response for the firmware commands and this was causing the DIL to timeout
	   -- ,reclaim the resources and crash. The following code looks for the heartbeat and
	   -- to make sure that we return from this function only when we get the heart beat making sure
	   -- that the firmware is running.
	   */

	bRetVal = crystalhd_flea_detect_fw_alive(hw);
	if( !bRetVal )
	{
		dev_info(&hw->adp->pdev->dev,"[crystalhd_flea_download_fw]: step 8. Detect firmware heart beat failed.\n");
		return BC_STS_ERROR;
	}

	dev_dbg(&hw->adp->pdev->dev, "[%s]: Complete.\n", __func__);
	return BC_STS_SUCCESS;
}

bool crystalhd_flea_start_device(struct crystalhd_hw *hw)
{
	uint32_t	regVal	= 0;
	bool		bRetVal = false;

	/*
	-- Issue Core reset to bring in the default values in place
	*/
	crystalhd_flea_core_reset(hw);

	/*
	-- If the gisb arbitar register is not set to some other value
	-- and the firmware crashes, we see a NMI since the hardware did
	-- not respond to a register read at all. The PCI-E trace confirms the problem.
	-- Right now we are setting the register values to 0x7e00 and will check later
	-- what should be the correct value to program.
	*/
	hw->pfnWriteDevRegister(hw->adp, BCHP_SUN_GISB_ARB_TIMER, 0xd80);

	/*
	-- Disable all interrupts
	*/
	crystalhd_flea_clear_interrupts(hw);
	crystalhd_flea_disable_interrupts(hw);

	/*
	-- Enable the option for getting the done count in
	-- Rx DMA engine.
	*/
	regVal = hw->pfnReadDevRegister(hw->adp, BCHP_MISC1_DMA_DEBUG_OPTIONS_REG);
	regVal |= 0x10;
	hw->pfnWriteDevRegister(hw->adp, BCHP_MISC1_DMA_DEBUG_OPTIONS_REG, regVal);

	/*
	-- Enable the TX DMA Engine once on startup.
	-- This is a new bit added.
	*/
	hw->pfnWriteDevRegister(hw->adp, BCHP_MISC1_TX_DMA_CTRL, 0x01);

	/*
	-- Enable the RX3 DMA Engine once on startup.
	-- This is a new bit added.
	*/
	hw->pfnWriteDevRegister(hw->adp, BCHP_MISC1_HIF_DMA_CTRL, 0x01);

	/*
	-- Set the Run bit for RX-Y and RX-UV DMA engines.
	*/
	hw->pfnWriteDevRegister(hw->adp, BCHP_MISC1_Y_RX_SW_DESC_LIST_CTRL_STS, 0x01);

	/*
	-- Make sure Early L1 is disabled - NAREN - This will not prevent the device from entering L1 under active mode
	*/
	regVal = hw->pfnReadDevRegister(hw->adp, BCHP_MISC_PERST_CLOCK_CTRL);
	regVal &= ~BCHP_MISC_PERST_CLOCK_CTRL_EARLY_L1_EXIT_MASK;
	hw->pfnWriteDevRegister(hw->adp, BCHP_MISC_PERST_CLOCK_CTRL, regVal);

	crystalhd_flea_init_dram(hw);

	msleep_interruptible(5);

	/* Enable the Single Shot Transaction on PCI by disabling the */
	/* bit 29 of transaction configuration register */

	regVal = hw->pfnReadDevRegister(hw->adp, BCHP_PCIE_TL_TRANSACTION_CONFIGURATION);
	regVal &= (~(BC_BIT(29)));
	hw->pfnWriteDevRegister(hw->adp, BCHP_PCIE_TL_TRANSACTION_CONFIGURATION, regVal);

	crystalhd_flea_init_temperature_measure(hw,true);

	crystalhd_flea_init_power_state(hw);
	crystalhd_flea_set_next_power_state(hw, FLEA_EVT_START_DEVICE);

	/*
	-- Enable all interrupts
	*/
	crystalhd_flea_clear_interrupts(hw);
	crystalhd_flea_enable_interrupts(hw);

	/*
	-- This is the only time we set this pointer for Flea.
	-- Since there is no stop the pointer is not reset anytime....
	-- except for fatal errors.
	*/
	hw->rx_list_post_index = 0;
	hw->RxCaptureState = 0;

	msleep_interruptible(1);

	return bRetVal;
}


bool crystalhd_flea_stop_device(struct crystalhd_hw *hw)
{
	uint32_t regVal=0, pollCnt=0;

	/*
	-- Issue the core reset so that we
	-- make sure there is nothing running.
	*/
	crystalhd_flea_core_reset(hw);

	crystalhd_flea_init_temperature_measure(hw, false);

	/*
	-- If the gisb arbitrater register is not set to some other value
	-- and the firmware crashes, we see a NMI since the hardware did
	-- not respond to a register read at all. The PCI-E trace confirms the problem.
	-- Right now we are setting the register values to 0x7e00 and will check later
	-- what should be the correct value to program.
	*/
	hw->pfnWriteDevRegister(hw->adp, BCHP_SUN_GISB_ARB_TIMER, 0xd80);

	/*
	-- Disable the TX DMA Engine once on shutdown.
	-- This is a new bit added.
	*/
	hw->pfnWriteDevRegister(hw->adp, BCHP_MISC1_TX_DMA_CTRL, 0x0);

	/*
	-- Disable the RX3 DMA Engine once on Stop.
	-- This is a new bit added.
	*/
	hw->pfnWriteDevRegister(hw->adp, BCHP_MISC1_HIF_DMA_CTRL, 0x0);

	/*
	-- Clear the RunStop Bit For RX DMA Control
	*/
	hw->pfnWriteDevRegister(hw->adp, BCHP_MISC1_Y_RX_SW_DESC_LIST_CTRL_STS, 0x0);

	hw->pfnWriteDevRegister(hw->adp, BCHP_PRI_ARB_CONTROL_REGS_REFRESH_CTL_0, 0x0);

	/* * Wait for MEMC to become idle */
	pollCnt=0;
	while (1)
	{
		regVal = hw->pfnReadDevRegister(hw->adp, BCHP_DDR23_CTL_REGS_0_CTL_STATUS);

		if(regVal & BCHP_DDR23_CTL_REGS_0_CTL_STATUS_idle_MASK)
			break;

		pollCnt++;
		if(pollCnt >= 100)
			break;

		msleep_interruptible(1);
	}

	/*First Disable the AVD and ARM before disabling the DRAM*/
	regVal = hw->pfnReadDevRegister(hw->adp, BCHP_CLK_PM_CTRL);

	regVal = BCHP_CLK_PM_CTRL_DIS_ARM_CLK_MASK |
			 BCHP_CLK_PM_CTRL_DIS_AVD_CLK_MASK |
			 BCHP_CLK_PM_CTRL_DIS_AVD_108_CLK_MASK |
			 BCHP_CLK_PM_CTRL_DIS_AVD_216_CLK_MASK;

	hw->pfnWriteDevRegister(hw->adp, BCHP_CLK_PM_CTRL, regVal);

	/*
	-- Disable the interrupt after disabling the ARM and AVD.
	-- We should be able to access the registers because we still
	-- have not disabled the clock for blink block. We disable the
	-- blick 108 abd 216 clock at the end of this function.
	*/
	crystalhd_flea_clear_interrupts(hw);
	crystalhd_flea_disable_interrupts(hw);

	/*Now try disabling the DRAM.*/
	regVal = hw->pfnReadDevRegister(hw->adp, BCHP_DDR23_CTL_REGS_0_PARAMS2);

	regVal |= BCHP_DDR23_CTL_REGS_0_PARAMS2_clke_MASK;

	/* * disable CKE */
	hw->pfnWriteDevRegister(hw->adp, BCHP_DDR23_CTL_REGS_0_PARAMS2, regVal);

	/* * issue refresh command */
	hw->pfnWriteDevRegister(hw->adp, BCHP_DDR23_CTL_REGS_0_REFRESH_CMD, 0x60);

	pollCnt=0;
	while(1)
	{
		regVal = hw->pfnReadDevRegister(hw->adp, BCHP_DDR23_CTL_REGS_0_CTL_STATUS);

		if(!(regVal & BCHP_DDR23_CTL_REGS_0_CTL_STATUS_clke_MASK))
			break;

		pollCnt++;
		if(pollCnt >= 100)
			break;

		msleep_interruptible(1);
	}

	/* * Enable DDR clock, DM and READ_ENABLE pads power down and force into the power down */
	hw->pfnWriteDevRegister(hw->adp, BCHP_DDR23_PHY_BYTE_LANE_0_IDLE_PAD_CONTROL,
							BCHP_DDR23_PHY_BYTE_LANE_0_IDLE_PAD_CONTROL_idle_MASK |
							BCHP_DDR23_PHY_BYTE_LANE_0_IDLE_PAD_CONTROL_dm_iddq_MASK |
							BCHP_DDR23_PHY_BYTE_LANE_0_IDLE_PAD_CONTROL_dq_iddq_MASK |
							BCHP_DDR23_PHY_BYTE_LANE_0_IDLE_PAD_CONTROL_read_enb_iddq_MASK |
							BCHP_DDR23_PHY_BYTE_LANE_0_IDLE_PAD_CONTROL_dqs_iddq_MASK |
							BCHP_DDR23_PHY_BYTE_LANE_0_IDLE_PAD_CONTROL_clk_iddq_MASK);

	hw->pfnWriteDevRegister(hw->adp, BCHP_DDR23_PHY_BYTE_LANE_1_IDLE_PAD_CONTROL,
							BCHP_DDR23_PHY_BYTE_LANE_1_IDLE_PAD_CONTROL_idle_MASK |
							BCHP_DDR23_PHY_BYTE_LANE_1_IDLE_PAD_CONTROL_dm_iddq_MASK |
							BCHP_DDR23_PHY_BYTE_LANE_1_IDLE_PAD_CONTROL_dq_iddq_MASK |
							BCHP_DDR23_PHY_BYTE_LANE_1_IDLE_PAD_CONTROL_read_enb_iddq_MASK |
							BCHP_DDR23_PHY_BYTE_LANE_1_IDLE_PAD_CONTROL_dqs_iddq_MASK |
							BCHP_DDR23_PHY_BYTE_LANE_1_IDLE_PAD_CONTROL_clk_iddq_MASK);

	/* * Power down BL LDO cells */
	hw->pfnWriteDevRegister(hw->adp, BCHP_DDR23_PHY_BYTE_LANE_0_CLOCK_REG_CONTROL,
							BCHP_DDR23_PHY_BYTE_LANE_0_CLOCK_REG_CONTROL_pwrdn_MASK);

	hw->pfnWriteDevRegister(hw->adp, BCHP_DDR23_PHY_BYTE_LANE_1_CLOCK_REG_CONTROL,
							BCHP_DDR23_PHY_BYTE_LANE_1_CLOCK_REG_CONTROL_pwrdn_MASK);

	/* * Enable DDR control signal pad power down and force into the power down */
	hw->pfnWriteDevRegister(hw->adp, BCHP_DDR23_PHY_CONTROL_REGS_IDLE_PAD_CONTROL,
							BCHP_DDR23_PHY_CONTROL_REGS_IDLE_PAD_CONTROL_idle_MASK |
							BCHP_DDR23_PHY_CONTROL_REGS_IDLE_PAD_CONTROL_ctl_iddq_MASK);

	/* * Disable ddr phy clock */
	hw->pfnWriteDevRegister(hw->adp, BCHP_DDR23_PHY_CONTROL_REGS_CLK_PM_CTRL,
							BCHP_DDR23_PHY_CONTROL_REGS_CLK_PM_CTRL_DIS_DDR_CLK_MASK);

	/* * Disable PLL output */
	regVal = hw->pfnReadDevRegister(hw->adp, BCHP_DDR23_PHY_CONTROL_REGS_PLL_CONFIG);

	hw->pfnWriteDevRegister(hw->adp, BCHP_DDR23_PHY_CONTROL_REGS_PLL_CONFIG,
							regVal & ~BCHP_DDR23_PHY_CONTROL_REGS_PLL_CONFIG_ENB_CLKOUT_MASK);

	/* * Power down addr_ctl LDO cells */
	hw->pfnWriteDevRegister(hw->adp, BCHP_DDR23_PHY_CONTROL_REGS_CLOCK_REG_CONTROL,
							BCHP_DDR23_PHY_CONTROL_REGS_CLOCK_REG_CONTROL_pwrdn_MASK);

	/* * Power down the PLL */
	regVal = hw->pfnReadDevRegister(hw->adp, BCHP_DDR23_PHY_CONTROL_REGS_PLL_CONFIG);

	hw->pfnWriteDevRegister(hw->adp, BCHP_DDR23_PHY_CONTROL_REGS_PLL_CONFIG,
							regVal | BCHP_DDR23_PHY_CONTROL_REGS_PLL_CONFIG_PWRDN_MASK);

	/* shut down the PLL1 */
	regVal = hw->pfnReadDevRegister(hw->adp, BCHP_CLK_PLL1_CTRL);

	hw->pfnWriteDevRegister(hw->adp, BCHP_CLK_PLL1_CTRL,
							regVal | BCHP_CLK_PLL1_CTRL_POWERDOWN_MASK);

	hw->pfnWriteDevRegister(hw->adp, BCHP_CLK_PLL0_ARM_DIV,	0xff);

	regVal = hw->pfnReadDevRegister(hw->adp, BCHP_CLK_PM_CTRL);

	regVal |= BCHP_CLK_PM_CTRL_DIS_SUN_27_LOW_PWR_MASK |
			  BCHP_CLK_PM_CTRL_DIS_SUN_108_LOW_PWR_MASK |
			  BCHP_CLK_PM_CTRL_DIS_MISC_OTP_9_CLK_MASK |
			  BCHP_CLK_PM_CTRL_DIS_ARM_CLK_MASK |
			  BCHP_CLK_PM_CTRL_DIS_AVD_CLK_MASK |
			  BCHP_CLK_PM_CTRL_DIS_AVD_108_CLK_MASK |
			  BCHP_CLK_PM_CTRL_DIS_BLINK_108_CLK_MASK |
			  BCHP_CLK_PM_CTRL_DIS_MISC_108_CLK_MASK |
			  BCHP_CLK_PM_CTRL_DIS_BLINK_216_CLK_MASK |
			  BCHP_CLK_PM_CTRL_DIS_DDR_108_CLK_MASK |
			  BCHP_CLK_PM_CTRL_DIS_DDR_216_CLK_MASK |
			  BCHP_CLK_PM_CTRL_DIS_AVD_216_CLK_MASK |
			  BCHP_CLK_PM_CTRL_DIS_MISC_216_CLK_MASK |
			  BCHP_CLK_PM_CTRL_DIS_SUN_216_CLK_MASK;

	hw->pfnWriteDevRegister(hw->adp, BCHP_CLK_PM_CTRL, regVal);

	crystalhd_flea_set_next_power_state(hw, FLEA_EVT_STOP_DEVICE);
	return true;
}

bool
crystalhd_flea_wake_up_hw(struct crystalhd_hw *hw)
{
	if(hw->FleaPowerState != FLEA_PS_ACTIVE)
	{
		crystalhd_flea_set_next_power_state(hw,	FLEA_EVT_FLL_CHANGE);
	}

	/* Now notify HW of the number of entries in the Free List */
	/* This starts up the channel bitmap delivery */
	crystalhd_flea_notify_fll_change(hw, false);

	hw->WakeUpDecodeDone = true;

	return true;
}

bool crystalhd_flea_check_input_full(struct crystalhd_hw *hw, uint32_t needed_sz, uint32_t *empty_sz, bool b_188_byte_pkts, uint8_t *flags)
{
	uint32_t				regVal=0;
	TX_INPUT_BUFFER_INFO	*pTxBuffInfo;
	uint32_t				FlagsAddr=0;

	*empty_sz = 0;
/*	*DramAddrOut=0; */


	/* Add condition here to wake up the HW in case some application is trying to do TX before starting RX - like FP */
	/* To prevent deadlocks. We are called here from Synchronized context so we can safely call this directly */

	if(hw->WakeUpDecodeDone != true)
	{
		/* Only wake up the HW if we are either being called from a single threaded app - like FP */
		/* or if we are not checking for the input buffer size as just a test */
		if(*flags == 0)
			crystalhd_flea_wake_up_hw(hw);
		else {
			*empty_sz = 2 * 1024 * 1024; /* FW Buffer size */
			/**DramAddrOut=0; */
			*flags=0;
			return false;
		}
	}

	/* if we have told the app that we have buffer empty then we cannot go to low power */
	if((hw->FleaPowerState != FLEA_PS_ACTIVE) && !hw->SingleThreadAppFIFOEmpty)
	{
		/**TxBuffSzOut=0; */
		/**DramAddrOut=0; */
		*empty_sz = 0;
		*flags=0;
		/*printk("PD can't Tx\n"); */
		return true; /*Indicate FULL*/
	}


	if(hw->TxFwInputBuffInfo.Flags & DFW_FLAGS_TX_ABORT)
	{
		*empty_sz=0;
		/**DramAddrOut=0; */
		*flags |= DFW_FLAGS_TX_ABORT;
		return true;
	}

	if( (hw->TxFwInputBuffInfo.DramBuffSzInBytes < needed_sz)
		||(!hw->TxFwInputBuffInfo.DramBuffAdd))
	{
		*empty_sz=0;
		/**DramAddrOut=0; */
		*flags=0;
		return true; /*Indicate FULL*/
	}

	if(hw->TxFwInputBuffInfo.DramBuffAdd % 4)
	{
		/*
		-- Indicate Full if we get a non-dowrd aligned address.
		-- This will avoid us posting the command to firmware and
		-- The TX will timeout and we will close the application properly.
		-- This avoids a illegal operation as far as the TX is concerned.
		*/
		printk("TxSDRAM-Destination Address Not DWORD Aligned:%x\n",hw->TxFwInputBuffInfo.DramBuffAdd);
		return true;
	}

	/*
	-- We got everything correctly from the firmware and hence we should be
	-- able to do the DMA. Indicate what app wants to hear.
	-- Firmware SAYS: I AM HUNGRY, GIVE ME FOOD. :)
	*/
	*empty_sz=hw->TxFwInputBuffInfo.DramBuffSzInBytes;
	/**dramAddrOut=pHWExt->TxFwInputBuffInfo.DramBuffAdd; */
/*	printk("empty size is %d\n", *empty_sz); */

	/* If we are just checking stats and are not actually going to DMA, don't increment */
	/* But we have to account for single threaded apps */
	if((*flags & 0x08) == 0x08)
	{
		/* This is a synchronized function */
		/* NAREN - In single threaded mode, if we have less than a defined size of buffer */
		/* ask the firmware to wrap around. To prevent deadlocks. */
		if(hw->TxFwInputBuffInfo.DramBuffSzInBytes < TX_WRAP_THRESHOLD)
		{
			pTxBuffInfo = (TX_INPUT_BUFFER_INFO *) (0);
			FlagsAddr = hw->TxBuffInfoAddr + ((uintptr_t) (&pTxBuffInfo->Flags));
			/* Read Modify the Flags to ask the FW to WRAP */
			hw->pfnDevDRAMRead(hw,FlagsAddr,1,&regVal);
			regVal |= DFW_FLAGS_WRAP;
			hw->pfnDevDRAMWrite(hw,FlagsAddr,1,&regVal);

			/* Indicate Busy to the application because we have to get new buffers from FW */
			*empty_sz=0;
			/* *DramAddrOut=0; */
			*flags=0;
			/* Wait for the next interrupt from the HW */
			hw->TxFwInputBuffInfo.DramBuffSzInBytes = 0;
			hw->TxFwInputBuffInfo.DramBuffAdd = 0;
			return true;
		}
		else
			hw->SingleThreadAppFIFOEmpty = true;
	}
	else if((*flags & 0x04) != 0x04)
		hw->EmptyCnt++;		/*OS_INTERLOCK_INCREMENT(&pHWExt->EmptyCnt); */

	/* Different from our Windows implementation */
	/* set bit 7 of the flags field to indicate that we have to use the destination address for TX */
	*flags |= BC_BIT(7);

	return false; /*Indicate Empty*/
}

BC_STATUS crystalhd_flea_fw_cmd_post_proc(struct crystalhd_hw *hw, BC_FW_CMD *fw_cmd)
{
	BC_STATUS sts = BC_STS_SUCCESS;
	struct DecRspChannelStartVideo *st_rsp = NULL;
	struct C011_TS_CMD				*pGenRsp = NULL;
	struct DecRspChannelChannelOpen *pRsp  = NULL;

	pGenRsp = (struct C011_TS_CMD *) fw_cmd->rsp;

	switch (fw_cmd->cmd[0]) {
		case eCMD_C011_DEC_CHAN_STREAM_OPEN:
			hw->channelNum = pGenRsp->ulParams[2];

			dev_dbg(&hw->adp->pdev->dev, "Snooped Stream Open Cmd For ChNo:%x\n", hw->channelNum);
			break;
		case eCMD_C011_DEC_CHAN_OPEN:
			pRsp = (struct DecRspChannelChannelOpen *)pGenRsp;
			hw->channelNum = pRsp->ChannelID;

			/* used in Flea to update the Tx Buffer stats */
			hw->TxBuffInfoAddr = pRsp->transportStreamCaptureAddr;
			hw->TxFwInputBuffInfo.DramBuffAdd=0;
			hw->TxFwInputBuffInfo.DramBuffSzInBytes=0;
			hw->TxFwInputBuffInfo.Flags=0;
			hw->TxFwInputBuffInfo.HostXferSzInBytes=0;
			hw->TxFwInputBuffInfo.SeqNum=0;

			/* NAREN Init power management states here when we start the channel */
			hw->PwrDwnTxIntr = false;
			hw->PwrDwnPiQIntr = false;
			hw->EmptyCnt = 0;
			hw->SingleThreadAppFIFOEmpty = false;

			dev_dbg(&hw->adp->pdev->dev, "Snooped ChOpen Cmd For ChNo:%x TxBuffAddr:%x\n",
					hw->channelNum,
					hw->TxBuffInfoAddr);
			break;
		case eCMD_C011_DEC_CHAN_START_VIDEO:
			st_rsp = (struct DecRspChannelStartVideo *)fw_cmd->rsp;
			hw->pib_del_Q_addr = st_rsp->picInfoDeliveryQ;
			hw->pib_rel_Q_addr = st_rsp->picInfoReleaseQ;

			dev_dbg(&hw->adp->pdev->dev, "Snooping CHAN_START_VIDEO command to get the Addr of Del/Rel Queue\n");
			dev_dbg(&hw->adp->pdev->dev, "DelQAddr:%x RelQAddr:%x\n",
					hw->pib_del_Q_addr, hw->pib_rel_Q_addr);
			break;
		default:
			break;
	}
	return sts;
}

BC_STATUS crystalhd_flea_do_fw_cmd(struct crystalhd_hw *hw, BC_FW_CMD *fw_cmd)
{
	struct device *dev;
	uint32_t cnt = 0, cmd_res_addr;
	uint32_t *cmd_buff, *res_buff;
	wait_queue_head_t fw_cmd_event;
	int rc = 0;
	BC_STATUS sts;
	unsigned long flags;

	crystalhd_create_event(&fw_cmd_event);

	if (!hw || !fw_cmd) {
		printk(KERN_ERR "%s: Invalid Arguments\n", __func__);
		return BC_STS_INV_ARG;
	}

	dev = &hw->adp->pdev->dev;

	dev_dbg(dev, "%s entered\n", __func__);

	cmd_buff = fw_cmd->cmd;
	res_buff = fw_cmd->rsp;

	if (!cmd_buff || !res_buff) {
		dev_err(dev, "Invalid Parameters for F/W Command\n");
		return BC_STS_INV_ARG;
	}

	hw->fwcmd_evt_sts = 0;
	hw->pfw_cmd_event = &fw_cmd_event;
	hw->FwCmdCnt++;

	if(hw->FleaPowerState != FLEA_PS_ACTIVE)
	{
		crystalhd_flea_set_next_power_state(hw,	FLEA_EVT_FW_CMD_POST);
	}

	spin_lock_irqsave(&hw->lock, flags);

	/*Write the command to the memory*/
	hw->pfnDevDRAMWrite(hw, hw->fwcmdPostAddr, FW_CMD_BUFF_SZ, cmd_buff);

	/*Memory Read for memory arbitrator flush*/
	hw->pfnDevDRAMRead(hw, hw->fwcmdPostAddr, 1, &cnt);

	/* Write the command address to mailbox */
	hw->pfnWriteDevRegister(hw->adp, hw->fwcmdPostMbox, hw->fwcmdPostAddr);

	spin_unlock_irqrestore(&hw->lock, flags);

	msleep_interruptible(50);

	/* FW commands should complete even if we got a signal from the upper layer */
	crystalhd_wait_on_event(&fw_cmd_event, hw->fwcmd_evt_sts,
							20000, rc, true);

	if (!rc) {
		sts = BC_STS_SUCCESS;
	} else if (rc == -EBUSY) {
		dev_err(dev, "Firmware command T/O\n");
		sts = BC_STS_TIMEOUT;
	} else if (rc == -EINTR) {
		dev_info(dev, "FwCmd Wait Signal - Can Never Happen\n");
		sts = BC_STS_IO_USER_ABORT;
	} else {
		dev_err(dev, "FwCmd IO Error.\n");
		sts = BC_STS_IO_ERROR;
	}

	if (sts != BC_STS_SUCCESS) {
		dev_err(dev, "FwCmd Failed.\n");
		return sts;
	}

	spin_lock_irqsave(&hw->lock, flags);

	/*Get the Responce Address*/
	cmd_res_addr = hw->pfnReadDevRegister(hw->adp, hw->fwcmdRespMbox);

	/*Read the Response*/
	hw->pfnDevDRAMRead(hw, cmd_res_addr, FW_CMD_BUFF_SZ, res_buff);

	spin_unlock_irqrestore(&hw->lock, flags);

	if (res_buff[2] != 0) {
		dev_err(dev, "res_buff[2] != C011_RET_SUCCESS\n");
		return BC_STS_FW_CMD_ERR;
	}

	sts = crystalhd_flea_fw_cmd_post_proc(hw, fw_cmd);
	if (sts != BC_STS_SUCCESS)
		dev_err(dev, "crystalhd_fw_cmd_post_proc Failed.\n");

	return sts;

}

void crystalhd_flea_get_dnsz(struct crystalhd_hw *hw, uint32_t list_index, uint32_t *y_dw_dnsz, uint32_t *uv_dw_dnsz)
{
	uint32_t y_dn_sz_reg, uv_dn_sz_reg;

	if (!list_index) {
		y_dn_sz_reg  = BCHP_MISC1_Y_RX_LIST0_CUR_BYTE_CNT;
		uv_dn_sz_reg = BCHP_MISC1_HIF_RX_LIST0_CUR_BYTE_CNT;
	} else {
		y_dn_sz_reg  = BCHP_MISC1_Y_RX_LIST1_CUR_BYTE_CNT;
		uv_dn_sz_reg = BCHP_MISC1_HIF_RX_LIST1_CUR_BYTE_CNT;
	}

	*y_dw_dnsz  = hw->pfnReadFPGARegister(hw->adp, y_dn_sz_reg);
	*uv_dw_dnsz = hw->pfnReadFPGARegister(hw->adp, uv_dn_sz_reg);

	return ;
}

BC_STATUS crystalhd_flea_hw_pause(struct crystalhd_hw *hw, bool state)
{
	/*printk("%s: Set flea to power down.\n", __func__); */
	crystalhd_flea_set_next_power_state(hw,	FLEA_EVT_FLL_CHANGE);
	return BC_STS_SUCCESS;
}

bool crystalhd_flea_peek_next_decoded_frame(struct crystalhd_hw *hw, uint64_t *meta_payload, uint32_t *picNumFlags, uint32_t PicWidth)
{
	unsigned long flags = 0;
	struct crystalhd_dioq *ioq;
	struct crystalhd_elem *tmp;
	struct crystalhd_rx_dma_pkt *rpkt;

	*meta_payload = 0;

	ioq = hw->rx_rdyq;
	spin_lock_irqsave(&ioq->lock, flags);

	if ((ioq->count > 0) && (ioq->head != (struct crystalhd_elem *)&ioq->head)) {
		tmp = ioq->head;
		spin_unlock_irqrestore(&ioq->lock, flags);
		rpkt = (struct crystalhd_rx_dma_pkt *)tmp->data;
		if (rpkt) {
			flea_GetPictureInfo(hw, rpkt, picNumFlags, meta_payload);
			/*printk("%s: flea_GetPictureInfo Pic#:%d\n", __func__, PicNumber); */
		}
		return true;
	}
	spin_unlock_irqrestore(&ioq->lock, flags);

	return false;

}

void crystalhd_flea_clear_rx_errs_intrs(struct crystalhd_hw *hw)
/*
-- Clears all the errors and interrupt on RX DMA engine.
*/
{
	uint32_t ulRegVal;
	union FLEA_INTR_BITS_COMMON	IntrToClear,IntrSts;

	IntrToClear.WholeReg = 0;
	IntrSts.WholeReg = 0;

	IntrSts.WholeReg = hw->pfnReadDevRegister(hw->adp, BCHP_INTR_INTR_STATUS);
	if(IntrSts.WholeReg)
	{
		ulRegVal = hw->pfnReadDevRegister(hw->adp, BCHP_MISC1_Y_RX_ERROR_STATUS);
		hw->pfnWriteDevRegister(hw->adp, BCHP_MISC1_Y_RX_ERROR_STATUS, ulRegVal);
		ulRegVal = hw->pfnReadDevRegister(hw->adp, BCHP_MISC1_HIF_RX_ERROR_STATUS);
		hw->pfnWriteDevRegister(hw->adp, BCHP_MISC1_HIF_RX_ERROR_STATUS, ulRegVal);

		IntrToClear.L0UVRxDMADone	=	IntrSts.L0UVRxDMADone;
		IntrToClear.L0UVRxDMAErr	=	IntrSts.L0UVRxDMAErr;
		IntrToClear.L0YRxDMADone	=	IntrSts.L0YRxDMADone;
		IntrToClear.L0YRxDMAErr		=	IntrSts.L0YRxDMAErr;
		IntrToClear.L1UVRxDMADone	=	IntrSts.L1UVRxDMADone;
		IntrToClear.L1UVRxDMAErr	=	IntrSts.L1UVRxDMAErr;
		IntrToClear.L1YRxDMADone	=	IntrSts.L1YRxDMADone;
		IntrToClear.L1YRxDMAErr		=	IntrSts.L1YRxDMAErr;

		hw->pfnWriteDevRegister(hw->adp, BCHP_INTR_INTR_CLR_REG, IntrToClear.WholeReg);

		hw->pfnWriteDevRegister(hw->adp, BCHP_INTR_EOI_CTRL, 1);
	}
	return;
}


void crystalhd_flea_stop_rx_dma_engine(struct crystalhd_hw *hw)
{
	union FLEA_INTR_BITS_COMMON	IntrStsValue;
	bool failedL0 = true, failedL1 = true;
	uint32_t pollCnt = 0;

	hw->RxCaptureState = 2;

	if((hw->rx_list_sts[0] == sts_free) && (hw->rx_list_sts[1] == sts_free)) {
		hw->RxCaptureState = 0;
		hw->RxSeqNum = 0;
		return; /* Nothing to be done */
	}

	if(hw->rx_list_sts[0] == sts_free)
		failedL0 = false;
	if(hw->rx_list_sts[1] == sts_free)
		failedL1 = false;

	while(1)
	{
		IntrStsValue.WholeReg = hw->pfnReadDevRegister(hw->adp, BCHP_INTR_INTR_STATUS);

		if(hw->rx_list_sts[0] != sts_free) {
			if( (IntrStsValue.L0YRxDMADone)  || (IntrStsValue.L0YRxDMAErr) ||
				(IntrStsValue.L0UVRxDMADone) || (IntrStsValue.L0UVRxDMAErr) )
			{
				failedL0 = false;
			}
		}
		else
			failedL0 = false;

		if(hw->rx_list_sts[1] != sts_free) {
			if( (IntrStsValue.L1YRxDMADone)  || (IntrStsValue.L1YRxDMAErr) ||
				(IntrStsValue.L1UVRxDMADone) || (IntrStsValue.L1UVRxDMAErr) )
			{
				failedL1 = false;
			}
		}
		else
			failedL1 = false;

		msleep_interruptible(10);

		if(pollCnt >= MAX_VALID_POLL_CNT)
			break;

		if((failedL0 == false) && (failedL1 == false))
			break;

		pollCnt++;
	}

	if(failedL0 || failedL1)
		printk("Failed to stop RX DMA\n");

	hw->RxCaptureState = 0;
	hw->RxSeqNum = 0;

	crystalhd_flea_clear_rx_errs_intrs(hw);
}

BC_STATUS crystalhd_flea_hw_fire_rxdma(struct crystalhd_hw *hw,
									   struct crystalhd_rx_dma_pkt *rx_pkt)
{
	struct device *dev;
	addr_64 desc_addr;
	unsigned long flags;
	PIC_DELIVERY_HOST_INFO	PicDeliInfo;
	uint32_t BuffSzInDwords;

	if (!hw || !rx_pkt) {
		printk(KERN_ERR "%s: Invalid Arguments\n", __func__);
		return BC_STS_INV_ARG;
	}

	dev = &hw->adp->pdev->dev;

	if (hw->rx_list_post_index >= DMA_ENGINE_CNT) {
		dev_err(dev, "List Out Of bounds %x\n", hw->rx_list_post_index);
		return BC_STS_INV_ARG;
	}

	if(hw->RxCaptureState != 1) {
		dev_err(dev, "Capture not enabled\n");
		return BC_STS_BUSY;
	}

	spin_lock_irqsave(&hw->rx_lock, flags);
	if (hw->rx_list_sts[hw->rx_list_post_index]) {
		dev_dbg(dev, "HW list is busy\n");
		spin_unlock_irqrestore(&hw->rx_lock, flags);
		return BC_STS_BUSY;
	}

	if (!TEST_BIT(hw->PicQSts, hw->channelNum)) {
		/* NO pictures available for this channel */
		dev_dbg(dev, "No Picture Available for DMA\n");
		spin_unlock_irqrestore(&hw->rx_lock, flags);
		return BC_STS_BUSY;
	}

	CLEAR_BIT(hw->PicQSts, hw->channelNum);

	desc_addr.full_addr = rx_pkt->desc_mem.phy_addr;

	PicDeliInfo.ListIndex = hw->rx_list_post_index;
	PicDeliInfo.RxSeqNumber = hw->RxSeqNum;
	PicDeliInfo.HostDescMemLowAddr_Y = desc_addr.low_part;
	PicDeliInfo.HostDescMemHighAddr_Y = desc_addr.high_part;

	if (rx_pkt->uv_phy_addr) {
		/* Program the UV descriptor */
		desc_addr.full_addr = rx_pkt->uv_phy_addr;
		PicDeliInfo.HostDescMemLowAddr_UV = desc_addr.low_part;
		PicDeliInfo.HostDescMemHighAddr_UV = desc_addr.high_part;
	}

	rx_pkt->pkt_tag = hw->rx_pkt_tag_seed + hw->rx_list_post_index;
	hw->rx_list_sts[hw->rx_list_post_index] |= rx_waiting_y_intr;
	if (rx_pkt->uv_phy_addr)
		hw->rx_list_sts[hw->rx_list_post_index] |= rx_waiting_uv_intr;
	hw->rx_list_post_index = (hw->rx_list_post_index + 1) % DMA_ENGINE_CNT;

	spin_unlock_irqrestore(&hw->rx_lock, flags);

	crystalhd_dioq_add(hw->rx_actq, (void *)rx_pkt, false, rx_pkt->pkt_tag);

	BuffSzInDwords = (sizeof (PicDeliInfo) - sizeof(PicDeliInfo.Reserved))/4;

	/*
	-- Write the parameters in DRAM.
	*/
	spin_lock_irqsave(&hw->lock, flags);
	hw->pfnDevDRAMWrite(hw, hw->FleaRxPicDelAddr, BuffSzInDwords, (uint32_t*)&PicDeliInfo);
	hw->pfnWriteDevRegister(hw->adp, RX_POST_MAILBOX, hw->channelNum);
	spin_unlock_irqrestore(&hw->lock, flags);

	hw->RxSeqNum++;

	return BC_STS_SUCCESS;
}

BC_STATUS crystalhd_flea_hw_post_cap_buff(struct crystalhd_hw *hw, struct crystalhd_rx_dma_pkt *rx_pkt)
{
	BC_STATUS sts = crystalhd_flea_hw_fire_rxdma(hw, rx_pkt);

	if (sts != BC_STS_SUCCESS)
		crystalhd_dioq_add(hw->rx_freeq, (void *)rx_pkt, false, rx_pkt->pkt_tag);

	hw->pfnNotifyFLLChange(hw, false);

	return sts;
}

void crystalhd_flea_start_tx_dma_engine(struct crystalhd_hw *hw, uint8_t list_id, addr_64 desc_addr)
{
	uint32_t dma_cntrl;
	uint32_t first_desc_u_addr, first_desc_l_addr;
	TX_INPUT_BUFFER_INFO	TxBuffInfo;
	uint32_t WrAddr=0, WrSzInDWords=0;

	hw->EmptyCnt--;
	hw->SingleThreadAppFIFOEmpty = false;

	/* For FLEA, first update the HW with the DMA parameters */
	WrSzInDWords = (sizeof(TxBuffInfo.DramBuffAdd) +
					sizeof(TxBuffInfo.DramBuffSzInBytes) +
					sizeof(TxBuffInfo.HostXferSzInBytes))/4;

	/*Make the DramBuffSz as Zero skip first ULONG*/
	WrAddr = hw->TxBuffInfoAddr;
	hw->TxFwInputBuffInfo.DramBuffAdd = TxBuffInfo.DramBuffAdd = 0;
	hw->TxFwInputBuffInfo.DramBuffSzInBytes =  TxBuffInfo.DramBuffSzInBytes = 0;
	TxBuffInfo.HostXferSzInBytes = hw->TxFwInputBuffInfo.HostXferSzInBytes;

	hw->pfnDevDRAMWrite(hw,	WrAddr,	WrSzInDWords, (uint32_t *)&TxBuffInfo);

	if (list_id == 0) {
		first_desc_u_addr = BCHP_MISC1_TX_FIRST_DESC_U_ADDR_LIST0;
		first_desc_l_addr = BCHP_MISC1_TX_FIRST_DESC_L_ADDR_LIST0;
	} else {
		first_desc_u_addr = BCHP_MISC1_TX_FIRST_DESC_U_ADDR_LIST1;
		first_desc_l_addr = BCHP_MISC1_TX_FIRST_DESC_L_ADDR_LIST1;
	}

	dma_cntrl = hw->pfnReadFPGARegister(hw->adp, BCHP_MISC1_TX_SW_DESC_LIST_CTRL_STS);
	if (!(dma_cntrl & BCHP_MISC1_TX_SW_DESC_LIST_CTRL_STS_TX_DMA_RUN_STOP_MASK)) {
		dma_cntrl |= BCHP_MISC1_TX_SW_DESC_LIST_CTRL_STS_TX_DMA_RUN_STOP_MASK;
		hw->pfnWriteFPGARegister(hw->adp, BCHP_MISC1_TX_SW_DESC_LIST_CTRL_STS,
								 dma_cntrl);
	}

	hw->pfnWriteFPGARegister(hw->adp, first_desc_u_addr, desc_addr.high_part);

	hw->pfnWriteFPGARegister(hw->adp, first_desc_l_addr, desc_addr.low_part | 0x01);
	/* Be sure we set the valid bit ^^^^ */

	return;
}

BC_STATUS crystalhd_flea_stop_tx_dma_engine(struct crystalhd_hw *hw)
{
	struct device *dev;
	uint32_t dma_cntrl, cnt = 30;
	uint32_t l1 = 1, l2 = 1;

	dma_cntrl = hw->pfnReadFPGARegister(hw->adp, BCHP_MISC1_TX_SW_DESC_LIST_CTRL_STS);

	dev = &hw->adp->pdev->dev;

	dev_dbg(dev, "Stopping TX DMA Engine..\n");

	if (!(dma_cntrl & BCHP_MISC1_TX_SW_DESC_LIST_CTRL_STS_TX_DMA_RUN_STOP_MASK)) {
		hw->TxList0Sts = ListStsFree;
		hw->TxList1Sts = ListStsFree;
		hw->tx_list_post_index = 0;

		dev_dbg(dev, "Already Stopped\n");
		return BC_STS_SUCCESS;
	}

	crystalhd_flea_disable_interrupts(hw);

	/* Issue stop to HW */
	dma_cntrl &= ~BCHP_MISC1_TX_SW_DESC_LIST_CTRL_STS_TX_DMA_RUN_STOP_MASK;
	hw->pfnWriteFPGARegister(hw->adp, BCHP_MISC1_TX_SW_DESC_LIST_CTRL_STS, dma_cntrl);

	dev_dbg(dev, "Cleared the DMA Start bit\n");

	/* Poll for 3seconds (30 * 100ms) on both the lists..*/
	while ((l1 || l2) && cnt) {

		if (l1) {
			l1 = hw->pfnReadFPGARegister(hw->adp,
										 BCHP_MISC1_TX_FIRST_DESC_L_ADDR_LIST0);
			l1 &= BCHP_MISC1_TX_SW_DESC_LIST_CTRL_STS_TX_DMA_RUN_STOP_MASK;
		}

		if (l2) {
			l2 = hw->pfnReadFPGARegister(hw->adp,
										 BCHP_MISC1_TX_FIRST_DESC_L_ADDR_LIST1);
			l2 &= BCHP_MISC1_TX_SW_DESC_LIST_CTRL_STS_TX_DMA_RUN_STOP_MASK;
		}

		msleep_interruptible(100);

		cnt--;
	}

	if (!cnt) {
		dev_err(dev, "Failed to stop TX DMA.. l1 %d, l2 %d\n", l1, l2);
		crystalhd_flea_enable_interrupts(hw);
		return BC_STS_ERROR;
	}

	hw->TxList0Sts = ListStsFree;
	hw->TxList1Sts = ListStsFree;

	hw->tx_list_post_index = 0;
	dev_dbg(dev, "stopped TX DMA..\n");
	crystalhd_flea_enable_interrupts(hw);

	return BC_STS_SUCCESS;
}

static void crystalhd_flea_update_tx_done_to_fw(struct crystalhd_hw *hw)
{
	struct device *dev;
	uint32_t				regVal		= 0;
	uint32_t				seqNumAddr	= 0;
	uint32_t				seqVal		= 0;
	TX_INPUT_BUFFER_INFO	*pTxBuffInfo;

	dev = &hw->adp->pdev->dev;
	/*
	-- first update the sequence number and then update the
	-- scratch.
	*/
	pTxBuffInfo = (TX_INPUT_BUFFER_INFO *) (0);
	seqNumAddr = hw->TxBuffInfoAddr + ((uintptr_t) (&pTxBuffInfo->SeqNum));

	/*Read the seqnece number */
	hw->pfnDevDRAMRead(hw, seqNumAddr, 1, &regVal);

	seqVal = regVal;
	regVal++;

	/*Increment and Write back to same memory location. */
	hw->pfnDevDRAMWrite(hw,	seqNumAddr, 1, &regVal);

	regVal = hw->pfnReadDevRegister(hw->adp, INDICATE_TX_DONE_REG);
	regVal++;
	hw->pfnWriteDevRegister(hw->adp, INDICATE_TX_DONE_REG, regVal);

	dev_dbg(dev, "TxUpdate[SeqNum DRAM Addr:%x] SeqNum:%x ScratchValue:%x\n",
		seqNumAddr, seqVal, regVal);

	return;
}

bool crystalhd_flea_tx_list0_handler(struct crystalhd_hw *hw, uint32_t err_sts)
{
	uint32_t err_mask, tmp;

	err_mask = MISC1_TX_DMA_ERROR_STATUS_TX_L0_DESC_TX_ABORT_ERRORS_MASK |
	MISC1_TX_DMA_ERROR_STATUS_TX_L0_DMA_DATA_TX_ABORT_ERRORS_MASK |
	MISC1_TX_DMA_ERROR_STATUS_TX_L0_FIFO_FULL_ERRORS_MASK;

	if (!(err_sts & err_mask))
		return false;

	dev_err(&hw->adp->pdev->dev, "Error on Tx-L0 %x\n", err_sts);

	tmp = err_mask;

	if (err_sts & MISC1_TX_DMA_ERROR_STATUS_TX_L0_FIFO_FULL_ERRORS_MASK)
		tmp &= ~MISC1_TX_DMA_ERROR_STATUS_TX_L0_FIFO_FULL_ERRORS_MASK;

	if (tmp) {
		/* reset list index.*/
		hw->tx_list_post_index = 0;
	}

	tmp = err_sts & err_mask;
	hw->pfnWriteDevRegister(hw->adp, BCHP_MISC1_TX_DMA_ERROR_STATUS, tmp);

	return true;
}

bool crystalhd_flea_tx_list1_handler(struct crystalhd_hw *hw, uint32_t err_sts)
{
	uint32_t err_mask, tmp;

	err_mask = MISC1_TX_DMA_ERROR_STATUS_TX_L1_DESC_TX_ABORT_ERRORS_MASK |
	MISC1_TX_DMA_ERROR_STATUS_TX_L1_DMA_DATA_TX_ABORT_ERRORS_MASK |
	MISC1_TX_DMA_ERROR_STATUS_TX_L1_FIFO_FULL_ERRORS_MASK;

	if (!(err_sts & err_mask))
		return false;

	dev_err(&hw->adp->pdev->dev, "Error on Tx-L1 %x\n", err_sts);

	tmp = err_mask;

	if (err_sts & MISC1_TX_DMA_ERROR_STATUS_TX_L1_FIFO_FULL_ERRORS_MASK)
		tmp &= ~MISC1_TX_DMA_ERROR_STATUS_TX_L1_FIFO_FULL_ERRORS_MASK;

	if (tmp) {
		/* reset list index.*/
		hw->tx_list_post_index = 0;
	}

	tmp = err_sts & err_mask;
	hw->pfnWriteDevRegister(hw->adp, BCHP_MISC1_TX_DMA_ERROR_STATUS, tmp);

	return true;
}

void crystalhd_flea_tx_isr(struct crystalhd_hw *hw, union FLEA_INTR_BITS_COMMON int_sts)
{
	uint32_t err_sts;

	if (int_sts.L0TxDMADone) {
		hw->TxList0Sts &= ~TxListWaitingForIntr;
		crystalhd_hw_tx_req_complete(hw, hw->tx_ioq_tag_seed + 0, BC_STS_SUCCESS);
	}

	if (int_sts.L1TxDMADone) {
		hw->TxList1Sts &= ~TxListWaitingForIntr;
		crystalhd_hw_tx_req_complete(hw, hw->tx_ioq_tag_seed + 1, BC_STS_SUCCESS);
	}

	if (!(int_sts.L0TxDMAErr || int_sts.L1TxDMAErr))
		/* No error mask set.. */
		return;

	/* Handle Tx errors. */
	err_sts = hw->pfnReadDevRegister(hw->adp, BCHP_MISC1_TX_DMA_ERROR_STATUS);

	if (crystalhd_flea_tx_list0_handler(hw, err_sts))
		crystalhd_hw_tx_req_complete(hw, hw->tx_ioq_tag_seed + 0, BC_STS_ERROR);

	if (crystalhd_flea_tx_list1_handler(hw, err_sts))
		crystalhd_hw_tx_req_complete(hw, hw->tx_ioq_tag_seed + 1, BC_STS_ERROR);

	hw->stats.tx_errors++;
}

bool crystalhd_flea_rx_list0_handler(struct crystalhd_hw *hw,
									 union FLEA_INTR_BITS_COMMON int_sts,
									 uint32_t y_err_sts,
									 uint32_t uv_err_sts)
{
	uint32_t tmp;
	enum list_sts tmp_lsts;

	if (!(y_err_sts & GET_Y0_ERR_MSK) && !(uv_err_sts & GET_UV0_ERR_MSK))
		return false;

	tmp_lsts = hw->rx_list_sts[0];

	/* Y0 - DMA */
	tmp = y_err_sts & GET_Y0_ERR_MSK;
	if (int_sts.L0YRxDMADone)
		hw->rx_list_sts[0] &= ~rx_waiting_y_intr;

	if (y_err_sts & MISC1_Y_RX_ERROR_STATUS_RX_L0_UNDERRUN_ERROR_MASK) {
		hw->rx_list_sts[0] &= ~rx_waiting_y_intr;
		tmp &= ~MISC1_Y_RX_ERROR_STATUS_RX_L0_UNDERRUN_ERROR_MASK;
	}

	if (y_err_sts & MISC1_Y_RX_ERROR_STATUS_RX_L0_FIFO_FULL_ERRORS_MASK) {
		/* Can never happen for Flea */
		printk("FLEA fifo full - impossible\n");
		hw->rx_list_sts[0] &= ~rx_y_mask;
		hw->rx_list_sts[0] |= rx_y_error;
		tmp &= ~MISC1_Y_RX_ERROR_STATUS_RX_L0_FIFO_FULL_ERRORS_MASK;
	}

	if (tmp) {
		hw->rx_list_sts[0] &= ~rx_y_mask;
		hw->rx_list_sts[0] |= rx_y_error;
		hw->rx_list_post_index = 0;
	}

	/* UV0 - DMA */
	tmp = uv_err_sts & GET_UV0_ERR_MSK;
	if (int_sts.L0UVRxDMADone)
		hw->rx_list_sts[0] &= ~rx_waiting_uv_intr;

	if (uv_err_sts & MISC1_UV_RX_ERROR_STATUS_RX_L0_UNDERRUN_ERROR_MASK) {
		hw->rx_list_sts[0] &= ~rx_waiting_uv_intr;
		tmp &= ~MISC1_UV_RX_ERROR_STATUS_RX_L0_UNDERRUN_ERROR_MASK;
	}

	if (uv_err_sts & MISC1_UV_RX_ERROR_STATUS_RX_L0_FIFO_FULL_ERRORS_MASK) {
		/* Can never happen for Flea */
		printk("FLEA fifo full - impossible\n");
		hw->rx_list_sts[0] &= ~rx_uv_mask;
		hw->rx_list_sts[0] |= rx_uv_error;
		tmp &= ~MISC1_UV_RX_ERROR_STATUS_RX_L0_FIFO_FULL_ERRORS_MASK;
	}

	if (tmp) {
		hw->rx_list_sts[0] &= ~rx_uv_mask;
		hw->rx_list_sts[0] |= rx_uv_error;
		hw->rx_list_post_index = 0;
	}

	if (y_err_sts & GET_Y0_ERR_MSK) {
		tmp = y_err_sts & GET_Y0_ERR_MSK;
		hw->pfnWriteDevRegister(hw->adp, BCHP_MISC1_Y_RX_ERROR_STATUS, tmp);
	}

	if (uv_err_sts & GET_UV0_ERR_MSK) {
		tmp = uv_err_sts & GET_UV0_ERR_MSK;
		hw->pfnWriteDevRegister(hw->adp, BCHP_MISC1_HIF_RX_ERROR_STATUS, tmp);
	}

	return (tmp_lsts != hw->rx_list_sts[0]);
}

bool crystalhd_flea_rx_list1_handler(struct crystalhd_hw *hw,
									 union FLEA_INTR_BITS_COMMON int_sts,
									 uint32_t y_err_sts,
									 uint32_t uv_err_sts)
{
	uint32_t tmp;
	enum list_sts tmp_lsts;

	if (!(y_err_sts & GET_Y1_ERR_MSK) && !(uv_err_sts & GET_UV1_ERR_MSK))
		return false;

	tmp_lsts = hw->rx_list_sts[1];

	/* Y1 - DMA */
	tmp = y_err_sts & GET_Y1_ERR_MSK;
	if (int_sts.L1YRxDMADone)
		hw->rx_list_sts[1] &= ~rx_waiting_y_intr;

	if (y_err_sts & MISC1_Y_RX_ERROR_STATUS_RX_L1_UNDERRUN_ERROR_MASK) {
		hw->rx_list_sts[1] &= ~rx_waiting_y_intr;
		tmp &= ~MISC1_Y_RX_ERROR_STATUS_RX_L1_UNDERRUN_ERROR_MASK;
	}

	if (y_err_sts & MISC1_Y_RX_ERROR_STATUS_RX_L1_FIFO_FULL_ERRORS_MASK) {
		/* Can never happen for Flea */
		printk("FLEA fifo full - impossible\n");
		hw->rx_list_sts[1] &= ~rx_y_mask;
		hw->rx_list_sts[1] |= rx_y_error;
		tmp &= ~MISC1_Y_RX_ERROR_STATUS_RX_L1_FIFO_FULL_ERRORS_MASK;
	}

	if (tmp) {
		hw->rx_list_sts[1] &= ~rx_y_mask;
		hw->rx_list_sts[1] |= rx_y_error;
		hw->rx_list_post_index = 0;
	}

	/* UV1 - DMA */
	tmp = uv_err_sts & GET_UV1_ERR_MSK;
	if (int_sts.L1UVRxDMADone)
		hw->rx_list_sts[1] &= ~rx_waiting_uv_intr;

	if (uv_err_sts & MISC1_UV_RX_ERROR_STATUS_RX_L1_UNDERRUN_ERROR_MASK) {
		hw->rx_list_sts[1] &= ~rx_waiting_uv_intr;
		tmp &= ~MISC1_UV_RX_ERROR_STATUS_RX_L1_UNDERRUN_ERROR_MASK;
	}

	if (uv_err_sts & MISC1_UV_RX_ERROR_STATUS_RX_L1_FIFO_FULL_ERRORS_MASK) {
		/* Can never happen for Flea */
		printk("FLEA fifo full - impossible\n");
		hw->rx_list_sts[1] &= ~rx_uv_mask;
		hw->rx_list_sts[1] |= rx_uv_error;
		tmp &= ~MISC1_UV_RX_ERROR_STATUS_RX_L1_FIFO_FULL_ERRORS_MASK;
	}

	if (tmp) {
		hw->rx_list_sts[1] &= ~rx_uv_mask;
		hw->rx_list_sts[1] |= rx_uv_error;
		hw->rx_list_post_index = 0;
	}

	if (y_err_sts & GET_Y1_ERR_MSK) {
		tmp = y_err_sts & GET_Y1_ERR_MSK;
		hw->pfnWriteDevRegister(hw->adp, BCHP_MISC1_Y_RX_ERROR_STATUS, tmp);
	}

	if (uv_err_sts & GET_UV1_ERR_MSK) {
		tmp = uv_err_sts & GET_UV1_ERR_MSK;
		hw->pfnWriteDevRegister(hw->adp, BCHP_MISC1_HIF_RX_ERROR_STATUS, tmp);
	}

	return (tmp_lsts != hw->rx_list_sts[1]);
}

void crystalhd_flea_rx_isr(struct crystalhd_hw *hw, union FLEA_INTR_BITS_COMMON intr_sts)
{
	unsigned long flags;
	uint32_t i, list_avail = 0;
	BC_STATUS comp_sts = BC_STS_NO_DATA;
	uint32_t y_err_sts, uv_err_sts, y_dn_sz = 0, uv_dn_sz = 0;
	bool ret = 0;

	if (!hw) {
		printk(KERN_ERR "%s: Invalid Arguments\n", __func__);
		return;
	}

	if (!(intr_sts.L0YRxDMADone || intr_sts.L1YRxDMADone || intr_sts.L0UVRxDMADone || intr_sts.L1UVRxDMADone ||
		intr_sts.L0YRxDMAErr || intr_sts.L1YRxDMAErr || intr_sts.L0UVRxDMAErr || intr_sts.L1UVRxDMAErr))
		return;

	spin_lock_irqsave(&hw->rx_lock, flags);

	y_err_sts = hw->pfnReadDevRegister(hw->adp, BCHP_MISC1_Y_RX_ERROR_STATUS);
	uv_err_sts = hw->pfnReadDevRegister(hw->adp, BCHP_MISC1_HIF_RX_ERROR_STATUS);

	for (i = 0; i < DMA_ENGINE_CNT; i++) {
		/* Update States..*/
		if (i == 0)
			ret = crystalhd_flea_rx_list0_handler(hw, intr_sts, y_err_sts, uv_err_sts);
		else
			ret = crystalhd_flea_rx_list1_handler(hw, intr_sts, y_err_sts, uv_err_sts);
		if (ret) {
			switch (hw->rx_list_sts[i]) {
				case sts_free:
					comp_sts = BC_STS_SUCCESS;
					list_avail = 1;
					hw->stats.rx_success++;
					break;
				case rx_y_error:
				case rx_uv_error:
				case rx_sts_error:
					/* We got error on both or Y or uv. */
					hw->stats.rx_errors++;
					hw->pfnHWGetDoneSize(hw, i, &y_dn_sz, &uv_dn_sz);
					dev_info(&hw->adp->pdev->dev, "list_index:%x "
					"rx[%d] rxtot[%d] Y:%x UV:%x Int:%x YDnSz:%x "
					"UVDnSz:%x\n", i, hw->stats.rx_errors,
							 hw->stats.rx_errors + hw->stats.rx_success,
							 y_err_sts, uv_err_sts, intr_sts.WholeReg,
							 y_dn_sz, uv_dn_sz);
							 hw->rx_list_sts[i] = sts_free;
							 comp_sts = BC_STS_ERROR;
							 break;
				default:
					/* Wait for completion..*/
					comp_sts = BC_STS_NO_DATA;
					break;
			}
		}
		/* handle completion...*/
		if (comp_sts != BC_STS_NO_DATA) {
			crystalhd_rx_pkt_done(hw, i, comp_sts);
			comp_sts = BC_STS_NO_DATA;
		}
	}

	spin_unlock_irqrestore(&hw->rx_lock, flags);

	if (list_avail)
		crystalhd_hw_start_capture(hw);
}

bool crystalhd_flea_hw_interrupt_handle(struct crystalhd_adp *adp, struct crystalhd_hw *hw)
{
	union FLEA_INTR_BITS_COMMON	IntrStsValue;
	bool				bIntFound		= false;
	bool				bPostRxBuff		= false;
	bool				bSomeCmdDone	= false;
	struct crystalhd_rx_dma_pkt *rx_pkt;

	bool	rc = false;

	if (!adp || !hw->dev_started)
		return rc;

	IntrStsValue.WholeReg=0;

	IntrStsValue.WholeReg = hw->pfnReadDevRegister(hw->adp, BCHP_INTR_INTR_STATUS);

	if(!IntrStsValue.WholeReg)
		return rc;	/*Not Our interrupt*/

	/*If any of the bit is set we have a problem*/
	if(IntrStsValue.HaltIntr || IntrStsValue.PcieTgtCaAttn || IntrStsValue.PcieTgtUrAttn)
	{
		printk("Bad HW Error in CrystalHD Driver\n");
		return rc;
	}

	/* Our interrupt */
	hw->stats.num_interrupts++;
	rc = true;

	/* NAREN When In Power Down state, only interrupts possible are TXFIFO and PiQ       */
	/* Save the state of these interrupts to process them when we resume from power down */
	if(hw->FleaPowerState == FLEA_PS_LP_COMPLETE)
	{
		if(IntrStsValue.ArmMbox1Int)
		{
			hw->PwrDwnPiQIntr = true;
			bIntFound = true;
		}

		if(IntrStsValue.ArmMbox2Int)
		{
			hw->PwrDwnTxIntr = true;
			bIntFound = true;
		}

		/*Write End Of Interrupt for PCIE*/
		if(bIntFound)
		{
			hw->pfnWriteDevRegister(hw->adp, BCHP_INTR_INTR_CLR_REG, IntrStsValue.WholeReg);
			hw->pfnWriteDevRegister(hw->adp, BCHP_INTR_EOI_CTRL, 1);
		}
		return (bIntFound);
	}

	/*
	-- Arm Mail box Zero interrupt is
	-- BCHP_ARMCR4_BRIDGE_REG_MBOX_ARM1
	*/
	if(IntrStsValue.ArmMbox0Int)
	{
		/*HWFWCmdComplete(pHWExt,IntrBmp); */
		/*Set the Event and the status flag*/
		if (hw->pfw_cmd_event) {
			hw->fwcmd_evt_sts = 1;
			crystalhd_set_event(hw->pfw_cmd_event);
		}
		bIntFound = true;
		bSomeCmdDone = true;
		hw->FwCmdCnt--;
	}

	/* Rx interrupts */
	crystalhd_flea_rx_isr(hw, IntrStsValue);

	if( IntrStsValue.L0YRxDMADone || IntrStsValue.L1YRxDMADone || IntrStsValue.L0UVRxDMADone || IntrStsValue.L1UVRxDMADone || IntrStsValue.L0YRxDMAErr || IntrStsValue.L1YRxDMAErr )
	{
		bSomeCmdDone = true;
	}


	/* Tx interrupts*/
	crystalhd_flea_tx_isr(hw, IntrStsValue);

	/*
	-- Indicate the TX Done to Flea Firmware.
	*/
	if(IntrStsValue.L0TxDMADone || IntrStsValue.L1TxDMADone || IntrStsValue.L0TxDMAErr || IntrStsValue.L1TxDMAErr)
	{
		crystalhd_flea_update_tx_done_to_fw(hw);
		bSomeCmdDone = true;
	}
	/*
	-- We are doing this here because we processed the interrupts.
	-- We might want to change the PicQSts bitmap in any of the interrupts.
	-- This should be done before trying to post the next RX buffer.
	-- NOTE: ArmMbox1Int is BCHP_ARMCR4_BRIDGE_REG_MBOX_ARM2
	*/
	if(IntrStsValue.ArmMbox1Int)
	{
		/*pHWExt->FleaBmpIntrCnt++; */
		crystalhd_flea_update_temperature(hw);
		crystalhd_flea_handle_PicQSts_intr(hw);
		bPostRxBuff = true;
		bIntFound = true;
	}

	if(IntrStsValue.ArmMbox2Int)
	{
		crystalhd_flea_update_temperature(hw);
		crystalhd_flea_update_tx_buff_info(hw);
		bIntFound = true;
	}

	/*Write End Of Interrupt for PCIE*/
	if(rc)
	{
		hw->pfnWriteDevRegister(hw->adp, BCHP_INTR_INTR_CLR_REG, IntrStsValue.WholeReg);
		hw->pfnWriteDevRegister(hw->adp, BCHP_INTR_EOI_CTRL, 1);
	}

	/* Try to post RX Capture buffer from ISR context */
	if(bPostRxBuff) {
		rx_pkt = crystalhd_dioq_fetch(hw->rx_freeq);
		if (rx_pkt)
			hw->pfnPostRxSideBuff(hw, rx_pkt);
	}

	if( (hw->FleaPowerState == FLEA_PS_LP_PENDING) && (bSomeCmdDone))
	{
		/*printk("interrupt_handle: current PS:%d, bSomeCmdDone%d\n", hw->FleaPowerState,bSomeCmdDone); */
		crystalhd_flea_set_next_power_state(hw, FLEA_EVT_CMD_COMP);
	}

	/* NAREN place the device in low power mode if we have not started playing video */
	/*if((hw->FleaPowerState == FLEA_PS_ACTIVE) && (hw->WakeUpDecodeDone != true)) */
	/*{ */
	/*	if((hw->ReadyListLen == 0) && (hw->FreeListLen == 0)) */
	/*	{ */
	/*		crystalhd_flea_set_next_power_state(hw, FLEA_EVT_FLL_CHANGE); */
	/*		printk("ISR Idle\n"); */
	/*	} */
	/*} */

	return rc;
}

/* This function cannot be called from ISR context since it uses APIs that can sleep */
bool flea_GetPictureInfo(struct crystalhd_hw *hw, struct crystalhd_rx_dma_pkt * rx_pkt,
							uint32_t *PicNumber, uint64_t *PicMetaData)
{
	struct device *dev = &hw->adp->pdev->dev;
	uint32_t PicInfoLineNum = 0, offset = 0, size = 0;
	PBC_PIC_INFO_BLOCK pPicInfoLine = NULL;
	uint32_t tmpYBuffData;
	unsigned long res = 0;
	uint32_t widthField = 0;
	bool rtVal = true;

	void *tmpPicInfo = NULL;
	struct crystalhd_dio_req *dio = rx_pkt->dio_req;
	*PicNumber = 0;
	*PicMetaData = 0;

	if (!dio)
		goto getpictureinfo_err_nosem;

/*	if(down_interruptible(&hw->fetch_sem)) */
/*		goto getpictureinfo_err_nosem; */

	tmpPicInfo = kmalloc(2 * sizeof(BC_PIC_INFO_BLOCK) + 16, GFP_KERNEL); /* since copy_from_user can sleep anyway */
	if(tmpPicInfo == NULL)
		goto getpictureinfo_err;
	dio->pib_va = kmalloc(32, GFP_KERNEL); /* temp buffer of 32 bytes for the rest; */
	if(dio->pib_va == NULL)
		goto getpictureinfo_err;

	offset = (rx_pkt->dio_req->uinfo.y_done_sz * 4) - PIC_PIB_DATA_OFFSET_FROM_END;
	res = copy_from_user(dio->pib_va, (void *)(dio->uinfo.xfr_buff + offset), 4);
	if (res != 0)
		goto getpictureinfo_err;
	PicInfoLineNum = *(uint32_t*)(dio->pib_va);
	if (PicInfoLineNum > 1092) {
		dev_err(dev, "Invalid Line Number[%x], DoneSz:0x%x Bytes\n",
			(int)PicInfoLineNum, rx_pkt->dio_req->uinfo.y_done_sz * 4);
		goto getpictureinfo_err;
	}

	offset = (rx_pkt->dio_req->uinfo.y_done_sz * 4) - PIC_WIDTH_OFFSET_FROM_END;
	res = copy_from_user(dio->pib_va, (void *)(dio->uinfo.xfr_buff + offset), 4);
	if (res != 0)
		goto getpictureinfo_err;
	widthField = *(uint32_t*)(dio->pib_va);

	hw->PICWidth = widthField & 0x3FFFFFFF; /* bit 31 is FMT Change, bit 30 is EOS */
	if (hw->PICWidth > 2048) {
		dev_err(dev, "Invalid width [%d]\n", hw->PICWidth);
		goto getpictureinfo_err;
	}

	/* calc pic info line offset */
	if (dio->uinfo.b422mode) {
		size = 2 * sizeof(BC_PIC_INFO_BLOCK);
		offset = (PicInfoLineNum * hw->PICWidth * 2) + 4;
	} else {
		size = sizeof(BC_PIC_INFO_BLOCK);
		offset = (PicInfoLineNum * hw->PICWidth) + 4;
	}

	res = copy_from_user(tmpPicInfo, (void *)(dio->uinfo.xfr_buff+offset), size);
	if (res != 0)
		goto getpictureinfo_err;

	pPicInfoLine = (PBC_PIC_INFO_BLOCK)(tmpPicInfo);

	*PicMetaData = pPicInfoLine->timeStamp;

	if(widthField & PIB_EOS_DETECTED_BIT)
	{
		dev_dbg(dev, "Got EOS flag.\n");
		hw->DrvEosDetected = 1;
		*(uint32_t *)(dio->pib_va) = 0xFFFFFFFF;
		res = copy_to_user((void *)(dio->uinfo.xfr_buff), dio->pib_va, 4);
		if (res != 0)
			goto getpictureinfo_err;
	}
	else
	{
		if( hw->DrvEosDetected == 1 )
			hw->DrvCancelEosFlag = 1;

		hw->DrvEosDetected = 0;
		res = copy_from_user(dio->pib_va, (void *)(dio->uinfo.xfr_buff), 4);
		if (res != 0)
			goto getpictureinfo_err;

		tmpYBuffData = *(uint32_t *)(dio->pib_va);
		pPicInfoLine->ycom = tmpYBuffData;
		res = copy_to_user((void *)(dio->uinfo.xfr_buff+offset), tmpPicInfo, size);
		if (res != 0)
			goto getpictureinfo_err;

		*(uint32_t *)(dio->pib_va) = PicInfoLineNum;
		res = copy_to_user((void *)(dio->uinfo.xfr_buff), dio->pib_va, 4);
		if (res != 0)
			goto getpictureinfo_err;
	}

	if(widthField & PIB_FORMAT_CHANGE_BIT)
	{
		rx_pkt->flags = 0;
		rx_pkt->flags |= COMP_FLAG_PIB_VALID | COMP_FLAG_FMT_CHANGE;

		rx_pkt->pib.picture_number			= pPicInfoLine->picture_number;
		rx_pkt->pib.width					= pPicInfoLine->width;
		rx_pkt->pib.height					= pPicInfoLine->height;
		rx_pkt->pib.chroma_format			= pPicInfoLine->chroma_format;
		rx_pkt->pib.pulldown				= pPicInfoLine->pulldown;
		rx_pkt->pib.flags					= pPicInfoLine->flags;
		rx_pkt->pib.sess_num				= pPicInfoLine->sess_num;
		rx_pkt->pib.aspect_ratio			= pPicInfoLine->aspect_ratio;
		rx_pkt->pib.colour_primaries		= pPicInfoLine->colour_primaries;
		rx_pkt->pib.picture_meta_payload	= pPicInfoLine->picture_meta_payload;
		rx_pkt->pib.frame_rate				= pPicInfoLine->frame_rate;
		rx_pkt->pib.custom_aspect_ratio_width_height = pPicInfoLine->custom_aspect_ratio_width_height;
		rx_pkt->pib.n_drop				= pPicInfoLine->n_drop;
		rx_pkt->pib.ycom				= pPicInfoLine->ycom;
		hw->PICHeight = rx_pkt->pib.height;
		hw->PICWidth = rx_pkt->pib.width;
		hw->LastPicNo=0;
		hw->LastTwoPicNo=0;
		hw->PDRatio = 0; /* NAREN - reset PD ratio to start measuring for new clip */
		hw->PauseThreshold = hw->DefaultPauseThreshold;
		hw->TickSpentInPD = 0;
		rdtscll(hw->TickCntDecodePU);

		dev_dbg(dev, "[FMT CH] DoneSz:0x%x, PIB:%x %x %x %x %x %x %x %x %x %x\n",
			rx_pkt->dio_req->uinfo.y_done_sz * 4,
				 rx_pkt->pib.picture_number,
				 rx_pkt->pib.aspect_ratio,
				 rx_pkt->pib.chroma_format,
				 rx_pkt->pib.colour_primaries,
				 rx_pkt->pib.frame_rate,
				 rx_pkt->pib.height,
				 rx_pkt->pib.width,
				 rx_pkt->pib.n_drop,
				 rx_pkt->pib.pulldown,
				 rx_pkt->pib.ycom);
		rtVal = false;
	}

	if(pPicInfoLine->flags & FLEA_DECODE_ERROR_FLAG)
	{
		*PicNumber = 0;
	} else {
		/* get pic number and flags */
		if (dio->uinfo.b422mode)
			offset = (PicInfoLineNum * hw->PICWidth * 2);
		else
			offset = (PicInfoLineNum * hw->PICWidth);

		res = copy_from_user(dio->pib_va, (void *)(dio->uinfo.xfr_buff+offset), 4);
		if (res != 0)
			goto getpictureinfo_err;

		*PicNumber = *(uint32_t *)(dio->pib_va);
	}

	if(dio->pib_va)
		kfree(dio->pib_va);
	if(tmpPicInfo)
		kfree(tmpPicInfo);

/*	up(&hw->fetch_sem); */

	return rtVal;

getpictureinfo_err:
/*	up(&hw->fetch_sem); */

getpictureinfo_err_nosem:
	if(dio->pib_va)
		kfree(dio->pib_va);
	if(tmpPicInfo)
		kfree(tmpPicInfo);

	*PicNumber = 0;
	*PicMetaData = 0;

	return false;
}

uint32_t flea_GetRptDropParam(struct crystalhd_hw *hw, void* pRxDMAReq)
{
	uint32_t PicNumber = 0,result = 0;
	uint64_t PicMetaData = 0;

	if(flea_GetPictureInfo(hw, (struct crystalhd_rx_dma_pkt *)pRxDMAReq,
		&PicNumber, &PicMetaData))
		result = PicNumber;

	return result;
}

bool crystalhd_flea_notify_event(struct crystalhd_hw *hw, enum BRCM_EVENT EventCode)
{
	switch(EventCode)
	{
		case BC_EVENT_START_CAPTURE:
		{
			crystalhd_flea_wake_up_hw(hw);
			break;
		}
		default:
			break;
	}

	return true;
}
