2956 lines
88 KiB
C
2956 lines
88 KiB
C
/***************************************************************************
|
|
* 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,®Val);
|
|
regVal |= DFW_FLAGS_WRAP;
|
|
hw->pfnDevDRAMWrite(hw,FlagsAddr,1,®Val);
|
|
|
|
/* 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, ®Val);
|
|
|
|
seqVal = regVal;
|
|
regVal++;
|
|
|
|
/*Increment and Write back to same memory location. */
|
|
hw->pfnDevDRAMWrite(hw, seqNumAddr, 1, ®Val);
|
|
|
|
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;
|
|
}
|