diff options
Diffstat (limited to 'drivers/staging/crystalhd/crystalhd_hw.c')
-rw-r--r-- | drivers/staging/crystalhd/crystalhd_hw.c | 2458 |
1 files changed, 0 insertions, 2458 deletions
diff --git a/drivers/staging/crystalhd/crystalhd_hw.c b/drivers/staging/crystalhd/crystalhd_hw.c deleted file mode 100644 index 4765d528279b..000000000000 --- a/drivers/staging/crystalhd/crystalhd_hw.c +++ /dev/null @@ -1,2458 +0,0 @@ -/*************************************************************************** - * Copyright (c) 2005-2009, Broadcom Corporation. - * - * Name: crystalhd_hw . c - * - * Description: - * BCM70010 Linux driver HW layer. - * - ********************************************************************** - * 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 "crystalhd.h" - -#include <linux/pci.h> -#include <linux/slab.h> -#include <linux/delay.h> - -/* Functions internal to this file */ - -static void crystalhd_enable_uarts(struct crystalhd_adp *adp) -{ - bc_dec_reg_wr(adp, UartSelectA, BSVS_UART_STREAM); - bc_dec_reg_wr(adp, UartSelectB, BSVS_UART_DEC_OUTER); -} - - -static void crystalhd_start_dram(struct crystalhd_adp *adp) -{ - bc_dec_reg_wr(adp, SDRAM_PARAM, ((40 / 5 - 1) << 0) | - /* tras (40ns tras)/(5ns period) -1 ((15/5 - 1) << 4) | // trcd */ - ((15 / 5 - 1) << 7) | /* trp */ - ((10 / 5 - 1) << 10) | /* trrd */ - ((15 / 5 + 1) << 12) | /* twr */ - ((2 + 1) << 16) | /* twtr */ - ((70 / 5 - 2) << 19) | /* trfc */ - (0 << 23)); - - bc_dec_reg_wr(adp, SDRAM_PRECHARGE, 0); - bc_dec_reg_wr(adp, SDRAM_EXT_MODE, 2); - bc_dec_reg_wr(adp, SDRAM_MODE, 0x132); - bc_dec_reg_wr(adp, SDRAM_PRECHARGE, 0); - bc_dec_reg_wr(adp, SDRAM_REFRESH, 0); - bc_dec_reg_wr(adp, SDRAM_REFRESH, 0); - bc_dec_reg_wr(adp, SDRAM_MODE, 0x32); - /* setting the refresh rate here */ - bc_dec_reg_wr(adp, SDRAM_REF_PARAM, ((1 << 12) | 96)); -} - - -static bool crystalhd_bring_out_of_rst(struct crystalhd_adp *adp) -{ - union link_misc_perst_deco_ctrl rst_deco_cntrl; - union link_misc_perst_clk_ctrl rst_clk_cntrl; - uint32_t temp; - - /* - * Link clocks: MISC_PERST_CLOCK_CTRL Clear PLL power down bit, - * delay to allow PLL to lock Clear alternate clock, stop clock bits - */ - rst_clk_cntrl.whole_reg = crystalhd_reg_rd(adp, MISC_PERST_CLOCK_CTRL); - rst_clk_cntrl.pll_pwr_dn = 0; - crystalhd_reg_wr(adp, MISC_PERST_CLOCK_CTRL, rst_clk_cntrl.whole_reg); - msleep_interruptible(50); - - rst_clk_cntrl.whole_reg = crystalhd_reg_rd(adp, MISC_PERST_CLOCK_CTRL); - rst_clk_cntrl.stop_core_clk = 0; - rst_clk_cntrl.sel_alt_clk = 0; - - crystalhd_reg_wr(adp, MISC_PERST_CLOCK_CTRL, rst_clk_cntrl.whole_reg); - msleep_interruptible(50); - - /* - * Bus Arbiter Timeout: GISB_ARBITER_TIMER - * Set internal bus arbiter timeout to 40us based on core clock speed - * (63MHz * 40us = 0x9D8) - */ - crystalhd_reg_wr(adp, GISB_ARBITER_TIMER, 0x9D8); - - /* - * Decoder clocks: MISC_PERST_DECODER_CTRL - * Enable clocks while 7412 reset is asserted, delay - * De-assert 7412 reset - */ - rst_deco_cntrl.whole_reg = crystalhd_reg_rd(adp, - MISC_PERST_DECODER_CTRL); - rst_deco_cntrl.stop_bcm_7412_clk = 0; - rst_deco_cntrl.bcm7412_rst = 1; - crystalhd_reg_wr(adp, MISC_PERST_DECODER_CTRL, - rst_deco_cntrl.whole_reg); - msleep_interruptible(10); - - rst_deco_cntrl.whole_reg = crystalhd_reg_rd(adp, - MISC_PERST_DECODER_CTRL); - rst_deco_cntrl.bcm7412_rst = 0; - crystalhd_reg_wr(adp, MISC_PERST_DECODER_CTRL, - rst_deco_cntrl.whole_reg); - msleep_interruptible(50); - - /* Disable OTP_CONTENT_MISC to 0 to disable all secure modes */ - crystalhd_reg_wr(adp, OTP_CONTENT_MISC, 0); - - /* Clear bit 29 of 0x404 */ - temp = crystalhd_reg_rd(adp, PCIE_TL_TRANSACTION_CONFIGURATION); - temp &= ~BC_BIT(29); - crystalhd_reg_wr(adp, PCIE_TL_TRANSACTION_CONFIGURATION, temp); - - /* 2.5V regulator must be set to 2.6 volts (+6%) */ - /* FIXME: jarod: what's the point of this reg read? */ - temp = crystalhd_reg_rd(adp, MISC_PERST_VREG_CTRL); - crystalhd_reg_wr(adp, MISC_PERST_VREG_CTRL, 0xF3); - - return true; -} - -static bool crystalhd_put_in_reset(struct crystalhd_adp *adp) -{ - union link_misc_perst_deco_ctrl rst_deco_cntrl; - union link_misc_perst_clk_ctrl rst_clk_cntrl; - uint32_t temp; - - /* - * Decoder clocks: MISC_PERST_DECODER_CTRL - * Assert 7412 reset, delay - * Assert 7412 stop clock - */ - rst_deco_cntrl.whole_reg = crystalhd_reg_rd(adp, - MISC_PERST_DECODER_CTRL); - rst_deco_cntrl.stop_bcm_7412_clk = 1; - crystalhd_reg_wr(adp, MISC_PERST_DECODER_CTRL, - rst_deco_cntrl.whole_reg); - msleep_interruptible(50); - - /* Bus Arbiter Timeout: GISB_ARBITER_TIMER - * Set internal bus arbiter timeout to 40us based on core clock speed - * (6.75MHZ * 40us = 0x10E) - */ - crystalhd_reg_wr(adp, GISB_ARBITER_TIMER, 0x10E); - - /* Link clocks: MISC_PERST_CLOCK_CTRL - * Stop core clk, delay - * Set alternate clk, delay, set PLL power down - */ - rst_clk_cntrl.whole_reg = crystalhd_reg_rd(adp, MISC_PERST_CLOCK_CTRL); - rst_clk_cntrl.stop_core_clk = 1; - rst_clk_cntrl.sel_alt_clk = 1; - crystalhd_reg_wr(adp, MISC_PERST_CLOCK_CTRL, rst_clk_cntrl.whole_reg); - msleep_interruptible(50); - - rst_clk_cntrl.whole_reg = crystalhd_reg_rd(adp, MISC_PERST_CLOCK_CTRL); - rst_clk_cntrl.pll_pwr_dn = 1; - crystalhd_reg_wr(adp, MISC_PERST_CLOCK_CTRL, rst_clk_cntrl.whole_reg); - - /* - * Read and restore the Transaction Configuration Register - * after core reset - */ - temp = crystalhd_reg_rd(adp, PCIE_TL_TRANSACTION_CONFIGURATION); - - /* - * Link core soft reset: MISC3_RESET_CTRL - * - Write BIT[0]=1 and read it back for core reset to take place - */ - crystalhd_reg_wr(adp, MISC3_RESET_CTRL, 1); - rst_deco_cntrl.whole_reg = crystalhd_reg_rd(adp, MISC3_RESET_CTRL); - msleep_interruptible(50); - - /* restore the transaction configuration register */ - crystalhd_reg_wr(adp, PCIE_TL_TRANSACTION_CONFIGURATION, temp); - - return true; -} - -static void crystalhd_disable_interrupts(struct crystalhd_adp *adp) -{ - union intr_mask_reg intr_mask; - intr_mask.whole_reg = crystalhd_reg_rd(adp, INTR_INTR_MSK_STS_REG); - intr_mask.mask_pcie_err = 1; - intr_mask.mask_pcie_rbusmast_err = 1; - intr_mask.mask_pcie_rgr_bridge = 1; - intr_mask.mask_rx_done = 1; - intr_mask.mask_rx_err = 1; - intr_mask.mask_tx_done = 1; - intr_mask.mask_tx_err = 1; - crystalhd_reg_wr(adp, INTR_INTR_MSK_SET_REG, intr_mask.whole_reg); - - return; -} - -static void crystalhd_enable_interrupts(struct crystalhd_adp *adp) -{ - union intr_mask_reg intr_mask; - intr_mask.whole_reg = crystalhd_reg_rd(adp, INTR_INTR_MSK_STS_REG); - intr_mask.mask_pcie_err = 1; - intr_mask.mask_pcie_rbusmast_err = 1; - intr_mask.mask_pcie_rgr_bridge = 1; - intr_mask.mask_rx_done = 1; - intr_mask.mask_rx_err = 1; - intr_mask.mask_tx_done = 1; - intr_mask.mask_tx_err = 1; - crystalhd_reg_wr(adp, INTR_INTR_MSK_CLR_REG, intr_mask.whole_reg); - - return; -} - -static void crystalhd_clear_errors(struct crystalhd_adp *adp) -{ - uint32_t reg; - - /* FIXME: jarod: wouldn't we want to write a 0 to the reg? - Or does the write clear the bits specified? */ - reg = crystalhd_reg_rd(adp, MISC1_Y_RX_ERROR_STATUS); - if (reg) - crystalhd_reg_wr(adp, MISC1_Y_RX_ERROR_STATUS, reg); - - reg = crystalhd_reg_rd(adp, MISC1_UV_RX_ERROR_STATUS); - if (reg) - crystalhd_reg_wr(adp, MISC1_UV_RX_ERROR_STATUS, reg); - - reg = crystalhd_reg_rd(adp, MISC1_TX_DMA_ERROR_STATUS); - if (reg) - crystalhd_reg_wr(adp, MISC1_TX_DMA_ERROR_STATUS, reg); -} - -static void crystalhd_clear_interrupts(struct crystalhd_adp *adp) -{ - uint32_t intr_sts = crystalhd_reg_rd(adp, INTR_INTR_STATUS); - - if (intr_sts) { - crystalhd_reg_wr(adp, INTR_INTR_CLR_REG, intr_sts); - - /* Write End Of Interrupt for PCIE */ - crystalhd_reg_wr(adp, INTR_EOI_CTRL, 1); - } -} - -static void crystalhd_soft_rst(struct crystalhd_adp *adp) -{ - uint32_t val; - - /* Assert c011 soft reset*/ - bc_dec_reg_wr(adp, DecHt_HostSwReset, 0x00000001); - msleep_interruptible(50); - - /* Release c011 soft reset*/ - bc_dec_reg_wr(adp, DecHt_HostSwReset, 0x00000000); - - /* Disable Stuffing..*/ - val = crystalhd_reg_rd(adp, MISC2_GLOBAL_CTRL); - val |= BC_BIT(8); - crystalhd_reg_wr(adp, MISC2_GLOBAL_CTRL, val); -} - -static bool crystalhd_load_firmware_config(struct crystalhd_adp *adp) -{ - uint32_t i = 0, reg; - - crystalhd_reg_wr(adp, DCI_DRAM_BASE_ADDR, (BC_DRAM_FW_CFG_ADDR >> 19)); - - crystalhd_reg_wr(adp, AES_CMD, 0); - crystalhd_reg_wr(adp, AES_CONFIG_INFO, - (BC_DRAM_FW_CFG_ADDR & 0x7FFFF)); - crystalhd_reg_wr(adp, AES_CMD, 0x1); - - /* FIXME: jarod: I've seen this fail, - and introducing extra delays helps... */ - for (i = 0; i < 100; ++i) { - reg = crystalhd_reg_rd(adp, AES_STATUS); - if (reg & 0x1) - return true; - msleep_interruptible(10); - } - - return false; -} - - -static bool crystalhd_start_device(struct crystalhd_adp *adp) -{ - uint32_t dbg_options, glb_cntrl = 0, reg_pwrmgmt = 0; - - BCMLOG(BCMLOG_INFO, "Starting BCM70012 Device\n"); - - reg_pwrmgmt = crystalhd_reg_rd(adp, PCIE_DLL_DATA_LINK_CONTROL); - reg_pwrmgmt &= ~ASPM_L1_ENABLE; - - crystalhd_reg_wr(adp, PCIE_DLL_DATA_LINK_CONTROL, reg_pwrmgmt); - - if (!crystalhd_bring_out_of_rst(adp)) { - BCMLOG_ERR("Failed To Bring Link Out Of Reset\n"); - return false; - } - - crystalhd_disable_interrupts(adp); - - crystalhd_clear_errors(adp); - - crystalhd_clear_interrupts(adp); - - crystalhd_enable_interrupts(adp); - - /* Enable the option for getting the total no. of DWORDS - * that have been transferred by the RXDMA engine - */ - dbg_options = crystalhd_reg_rd(adp, MISC1_DMA_DEBUG_OPTIONS_REG); - dbg_options |= 0x10; - crystalhd_reg_wr(adp, MISC1_DMA_DEBUG_OPTIONS_REG, dbg_options); - - /* Enable PCI Global Control options */ - glb_cntrl = crystalhd_reg_rd(adp, MISC2_GLOBAL_CTRL); - glb_cntrl |= 0x100; - glb_cntrl |= 0x8000; - crystalhd_reg_wr(adp, MISC2_GLOBAL_CTRL, glb_cntrl); - - crystalhd_enable_interrupts(adp); - - crystalhd_soft_rst(adp); - crystalhd_start_dram(adp); - crystalhd_enable_uarts(adp); - - return true; -} - -static bool crystalhd_stop_device(struct crystalhd_adp *adp) -{ - uint32_t reg; - - BCMLOG(BCMLOG_INFO, "Stopping BCM70012 Device\n"); - /* Clear and disable interrupts */ - crystalhd_disable_interrupts(adp); - crystalhd_clear_errors(adp); - crystalhd_clear_interrupts(adp); - - if (!crystalhd_put_in_reset(adp)) - BCMLOG_ERR("Failed to Put Link To Reset State\n"); - - reg = crystalhd_reg_rd(adp, PCIE_DLL_DATA_LINK_CONTROL); - reg |= ASPM_L1_ENABLE; - crystalhd_reg_wr(adp, PCIE_DLL_DATA_LINK_CONTROL, reg); - - /* Set PCI Clk Req */ - reg = crystalhd_reg_rd(adp, PCIE_CLK_REQ_REG); - reg |= PCI_CLK_REQ_ENABLE; - crystalhd_reg_wr(adp, PCIE_CLK_REQ_REG, reg); - - return true; -} - -static struct crystalhd_rx_dma_pkt *crystalhd_hw_alloc_rx_pkt( - struct crystalhd_hw *hw) -{ - unsigned long flags = 0; - struct crystalhd_rx_dma_pkt *temp = NULL; - - if (!hw) - return NULL; - - spin_lock_irqsave(&hw->lock, flags); - temp = hw->rx_pkt_pool_head; - if (temp) { - hw->rx_pkt_pool_head = hw->rx_pkt_pool_head->next; - temp->dio_req = NULL; - temp->pkt_tag = 0; - temp->flags = 0; - } - spin_unlock_irqrestore(&hw->lock, flags); - - return temp; -} - -static void crystalhd_hw_free_rx_pkt(struct crystalhd_hw *hw, - struct crystalhd_rx_dma_pkt *pkt) -{ - unsigned long flags = 0; - - if (!hw || !pkt) - return; - - spin_lock_irqsave(&hw->lock, flags); - pkt->next = hw->rx_pkt_pool_head; - hw->rx_pkt_pool_head = pkt; - spin_unlock_irqrestore(&hw->lock, flags); -} - -/* - * Call back from TX - IOQ deletion. - * - * This routine will release the TX DMA rings allocated - * during setup_dma rings interface. - * - * Memory is allocated per DMA ring basis. This is just - * a place holder to be able to create the dio queues. - */ -static void crystalhd_tx_desc_rel_call_back(void *context, void *data) -{ -} - -/* - * Rx Packet release callback.. - * - * Release All user mapped capture buffers and Our DMA packets - * back to our free pool. The actual cleanup of the DMA - * ring descriptors happen during dma ring release. - */ -static void crystalhd_rx_pkt_rel_call_back(void *context, void *data) -{ - struct crystalhd_hw *hw = (struct crystalhd_hw *)context; - struct crystalhd_rx_dma_pkt *pkt = (struct crystalhd_rx_dma_pkt *)data; - - if (!pkt || !hw) { - BCMLOG_ERR("Invalid arg - %p %p\n", hw, pkt); - return; - } - - if (pkt->dio_req) - crystalhd_unmap_dio(hw->adp, pkt->dio_req); - else - BCMLOG_ERR("Missing dio_req: 0x%x\n", pkt->pkt_tag); - - crystalhd_hw_free_rx_pkt(hw, pkt); -} - -#define crystalhd_hw_delete_ioq(adp, q) \ -do { \ - if (q) { \ - crystalhd_delete_dioq(adp, q); \ - q = NULL; \ - } \ -} while (0) - -static void crystalhd_hw_delete_ioqs(struct crystalhd_hw *hw) -{ - if (!hw) - return; - - BCMLOG(BCMLOG_DBG, "Deleting IOQs\n"); - crystalhd_hw_delete_ioq(hw->adp, hw->tx_actq); - crystalhd_hw_delete_ioq(hw->adp, hw->tx_freeq); - crystalhd_hw_delete_ioq(hw->adp, hw->rx_actq); - crystalhd_hw_delete_ioq(hw->adp, hw->rx_freeq); - crystalhd_hw_delete_ioq(hw->adp, hw->rx_rdyq); -} - -#define crystalhd_hw_create_ioq(sts, hw, q, cb) \ -do { \ - sts = crystalhd_create_dioq(hw->adp, &q, cb, hw); \ - if (sts != BC_STS_SUCCESS) \ - goto hw_create_ioq_err; \ -} while (0) - -/* - * Create IOQs.. - * - * TX - Active & Free - * RX - Active, Ready and Free. - */ -static enum BC_STATUS crystalhd_hw_create_ioqs(struct crystalhd_hw *hw) -{ - enum BC_STATUS sts = BC_STS_SUCCESS; - - if (!hw) { - BCMLOG_ERR("Invalid Arg!!\n"); - return BC_STS_INV_ARG; - } - - crystalhd_hw_create_ioq(sts, hw, hw->tx_freeq, - crystalhd_tx_desc_rel_call_back); - crystalhd_hw_create_ioq(sts, hw, hw->tx_actq, - crystalhd_tx_desc_rel_call_back); - - crystalhd_hw_create_ioq(sts, hw, hw->rx_freeq, - crystalhd_rx_pkt_rel_call_back); - crystalhd_hw_create_ioq(sts, hw, hw->rx_rdyq, - crystalhd_rx_pkt_rel_call_back); - crystalhd_hw_create_ioq(sts, hw, hw->rx_actq, - crystalhd_rx_pkt_rel_call_back); - - return sts; - -hw_create_ioq_err: - crystalhd_hw_delete_ioqs(hw); - - return sts; -} - - -static bool crystalhd_code_in_full(struct crystalhd_adp *adp, - uint32_t needed_sz, bool b_188_byte_pkts, uint8_t flags) -{ - uint32_t base, end, writep, readp; - uint32_t cpbSize, cpbFullness, fifoSize; - - if (flags & 0x02) { /* ASF Bit is set */ - base = bc_dec_reg_rd(adp, REG_Dec_TsAudCDB2Base); - end = bc_dec_reg_rd(adp, REG_Dec_TsAudCDB2End); - writep = bc_dec_reg_rd(adp, REG_Dec_TsAudCDB2Wrptr); - readp = bc_dec_reg_rd(adp, REG_Dec_TsAudCDB2Rdptr); - } else if (b_188_byte_pkts) { /*Encrypted 188 byte packets*/ - base = bc_dec_reg_rd(adp, REG_Dec_TsUser0Base); - end = bc_dec_reg_rd(adp, REG_Dec_TsUser0End); - writep = bc_dec_reg_rd(adp, REG_Dec_TsUser0Wrptr); - readp = bc_dec_reg_rd(adp, REG_Dec_TsUser0Rdptr); - } else { - base = bc_dec_reg_rd(adp, REG_DecCA_RegCinBase); - end = bc_dec_reg_rd(adp, REG_DecCA_RegCinEnd); - writep = bc_dec_reg_rd(adp, REG_DecCA_RegCinWrPtr); - readp = bc_dec_reg_rd(adp, REG_DecCA_RegCinRdPtr); - } - - cpbSize = end - base; - if (writep >= readp) - cpbFullness = writep - readp; - else - cpbFullness = (end - base) - (readp - writep); - - fifoSize = cpbSize - cpbFullness; - - if (fifoSize < BC_INFIFO_THRESHOLD) - return true; - - if (needed_sz > (fifoSize - BC_INFIFO_THRESHOLD)) - return true; - - return false; -} - -static enum BC_STATUS crystalhd_hw_tx_req_complete(struct crystalhd_hw *hw, - uint32_t list_id, enum BC_STATUS cs) -{ - struct tx_dma_pkt *tx_req; - - if (!hw || !list_id) { - BCMLOG_ERR("Invalid Arg..\n"); - return BC_STS_INV_ARG; - } - - hw->pwr_lock--; - - tx_req = (struct tx_dma_pkt *)crystalhd_dioq_find_and_fetch( - hw->tx_actq, list_id); - if (!tx_req) { - if (cs != BC_STS_IO_USER_ABORT) - BCMLOG_ERR("Find and Fetch Did not find req\n"); - return BC_STS_NO_DATA; - } - - if (tx_req->call_back) { - tx_req->call_back(tx_req->dio_req, tx_req->cb_event, cs); - tx_req->dio_req = NULL; - tx_req->cb_event = NULL; - tx_req->call_back = NULL; - } else { - BCMLOG(BCMLOG_DBG, "Missing Tx Callback - %X\n", - tx_req->list_tag); - } - - /* Now put back the tx_list back in FreeQ */ - tx_req->list_tag = 0; - - return crystalhd_dioq_add(hw->tx_freeq, tx_req, false, 0); -} - -static bool crystalhd_tx_list0_handler(struct crystalhd_hw *hw, - uint32_t err_sts) -{ - uint32_t err_mask, tmp; - unsigned long flags = 0; - - 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; - - BCMLOG_ERR("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) { - spin_lock_irqsave(&hw->lock, flags); - /* reset list index.*/ - hw->tx_list_post_index = 0; - spin_unlock_irqrestore(&hw->lock, flags); - } - - tmp = err_sts & err_mask; - crystalhd_reg_wr(hw->adp, MISC1_TX_DMA_ERROR_STATUS, tmp); - - return true; -} - -static bool crystalhd_tx_list1_handler(struct crystalhd_hw *hw, - uint32_t err_sts) -{ - uint32_t err_mask, tmp; - unsigned long flags = 0; - - 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; - - BCMLOG_ERR("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) { - spin_lock_irqsave(&hw->lock, flags); - /* reset list index.*/ - hw->tx_list_post_index = 0; - spin_unlock_irqrestore(&hw->lock, flags); - } - - tmp = err_sts & err_mask; - crystalhd_reg_wr(hw->adp, MISC1_TX_DMA_ERROR_STATUS, tmp); - - return true; -} - -static void crystalhd_tx_isr(struct crystalhd_hw *hw, uint32_t int_sts) -{ - uint32_t err_sts; - - if (int_sts & INTR_INTR_STATUS_L0_TX_DMA_DONE_INTR_MASK) - crystalhd_hw_tx_req_complete(hw, hw->tx_ioq_tag_seed + 0, - BC_STS_SUCCESS); - - if (int_sts & INTR_INTR_STATUS_L1_TX_DMA_DONE_INTR_MASK) - crystalhd_hw_tx_req_complete(hw, hw->tx_ioq_tag_seed + 1, - BC_STS_SUCCESS); - - if (!(int_sts & (INTR_INTR_STATUS_L0_TX_DMA_ERR_INTR_MASK | - INTR_INTR_STATUS_L1_TX_DMA_ERR_INTR_MASK))) { - /* No error mask set.. */ - return; - } - - /* Handle Tx errors. */ - err_sts = crystalhd_reg_rd(hw->adp, MISC1_TX_DMA_ERROR_STATUS); - - if (crystalhd_tx_list0_handler(hw, err_sts)) - crystalhd_hw_tx_req_complete(hw, hw->tx_ioq_tag_seed + 0, - BC_STS_ERROR); - - if (crystalhd_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++; -} - -static void crystalhd_hw_dump_desc(struct dma_descriptor *p_dma_desc, - uint32_t ul_desc_index, uint32_t cnt) -{ - uint32_t ix, ll = 0; - - if (!p_dma_desc || !cnt) - return; - - /* FIXME: jarod: perhaps a modparam desc_debug to enable this, - rather than setting ll (log level, I presume) to non-zero? */ - if (!ll) - return; - - for (ix = ul_desc_index; ix < (ul_desc_index + cnt); ix++) { - BCMLOG(ll, - "%s[%d] Buff[%x:%x] Next:[%x:%x] XferSz:%x Intr:%x,Last:%x\n", - ((p_dma_desc[ul_desc_index].dma_dir) ? "TDesc" : "RDesc"), - ul_desc_index, - p_dma_desc[ul_desc_index].buff_addr_high, - p_dma_desc[ul_desc_index].buff_addr_low, - p_dma_desc[ul_desc_index].next_desc_addr_high, - p_dma_desc[ul_desc_index].next_desc_addr_low, - p_dma_desc[ul_desc_index].xfer_size, - p_dma_desc[ul_desc_index].intr_enable, - p_dma_desc[ul_desc_index].last_rec_indicator); - } - -} - -static enum BC_STATUS crystalhd_hw_fill_desc(struct crystalhd_dio_req *ioreq, - struct dma_descriptor *desc, - dma_addr_t desc_paddr_base, - uint32_t sg_cnt, uint32_t sg_st_ix, - uint32_t sg_st_off, uint32_t xfr_sz) -{ - uint32_t count = 0, ix = 0, sg_ix = 0, len = 0, last_desc_ix = 0; - dma_addr_t desc_phy_addr = desc_paddr_base; - union addr_64 addr_temp; - - if (!ioreq || !desc || !desc_paddr_base || !xfr_sz || - (!sg_cnt && !ioreq->uinfo.dir_tx)) { - BCMLOG_ERR("Invalid Args\n"); - return BC_STS_INV_ARG; - } - - for (ix = 0; ix < sg_cnt; ix++) { - - /* Setup SGLE index. */ - sg_ix = ix + sg_st_ix; - - /* Get SGLE length */ - len = crystalhd_get_sgle_len(ioreq, sg_ix); - if (len % 4) { - BCMLOG_ERR(" len in sg %d %d %d\n", len, sg_ix, - sg_cnt); - return BC_STS_NOT_IMPL; - } - /* Setup DMA desc with Phy addr & Length at current index. */ - addr_temp.full_addr = crystalhd_get_sgle_paddr(ioreq, sg_ix); - if (sg_ix == sg_st_ix) { - addr_temp.full_addr += sg_st_off; - len -= sg_st_off; - } - memset(&desc[ix], 0, sizeof(desc[ix])); - desc[ix].buff_addr_low = addr_temp.low_part; - desc[ix].buff_addr_high = addr_temp.high_part; - desc[ix].dma_dir = ioreq->uinfo.dir_tx; - - /* Chain DMA descriptor. */ - addr_temp.full_addr = desc_phy_addr + - sizeof(struct dma_descriptor); - desc[ix].next_desc_addr_low = addr_temp.low_part; - desc[ix].next_desc_addr_high = addr_temp.high_part; - - if ((count + len) > xfr_sz) - len = xfr_sz - count; - - /* Debug.. */ - if ((!len) || (len > crystalhd_get_sgle_len(ioreq, sg_ix))) { - BCMLOG_ERR( - "inv-len(%x) Ix(%d) count:%x xfr_sz:%x sg_cnt:%d\n", - len, ix, count, xfr_sz, sg_cnt); - return BC_STS_ERROR; - } - /* Length expects Multiple of 4 */ - desc[ix].xfer_size = (len / 4); - - crystalhd_hw_dump_desc(desc, ix, 1); - - count += len; - desc_phy_addr += sizeof(struct dma_descriptor); - } - - last_desc_ix = ix - 1; - - if (ioreq->fb_size) { - memset(&desc[ix], 0, sizeof(desc[ix])); - addr_temp.full_addr = ioreq->fb_pa; - desc[ix].buff_addr_low = addr_temp.low_part; - desc[ix].buff_addr_high = addr_temp.high_part; - desc[ix].dma_dir = ioreq->uinfo.dir_tx; - desc[ix].xfer_size = 1; - desc[ix].fill_bytes = 4 - ioreq->fb_size; - count += ioreq->fb_size; - last_desc_ix++; - } - - /* setup last descriptor..*/ - desc[last_desc_ix].last_rec_indicator = 1; - desc[last_desc_ix].next_desc_addr_low = 0; - desc[last_desc_ix].next_desc_addr_high = 0; - desc[last_desc_ix].intr_enable = 1; - - crystalhd_hw_dump_desc(desc, last_desc_ix, 1); - - if (count != xfr_sz) { - BCMLOG_ERR("internal error sz curr:%x exp:%x\n", count, xfr_sz); - return BC_STS_ERROR; - } - - return BC_STS_SUCCESS; -} - -static enum BC_STATUS crystalhd_xlat_sgl_to_dma_desc( - struct crystalhd_dio_req *ioreq, - struct dma_desc_mem *pdesc_mem, - uint32_t *uv_desc_index) -{ - struct dma_descriptor *desc = NULL; - dma_addr_t desc_paddr_base = 0; - uint32_t sg_cnt = 0, sg_st_ix = 0, sg_st_off = 0; - uint32_t xfr_sz = 0; - enum BC_STATUS sts = BC_STS_SUCCESS; - - /* Check params.. */ - if (!ioreq || !pdesc_mem || !uv_desc_index) { - BCMLOG_ERR("Invalid Args\n"); - return BC_STS_INV_ARG; - } - - if (!pdesc_mem->sz || !pdesc_mem->pdma_desc_start || - !ioreq->sg || (!ioreq->sg_cnt && !ioreq->uinfo.dir_tx)) { - BCMLOG_ERR("Invalid Args\n"); - return BC_STS_INV_ARG; - } - - if ((ioreq->uinfo.dir_tx) && (ioreq->uinfo.uv_offset)) { - BCMLOG_ERR("UV offset for TX??\n"); - return BC_STS_INV_ARG; - - } - - desc = pdesc_mem->pdma_desc_start; - desc_paddr_base = pdesc_mem->phy_addr; - - if (ioreq->uinfo.dir_tx || (ioreq->uinfo.uv_offset == 0)) { - sg_cnt = ioreq->sg_cnt; - xfr_sz = ioreq->uinfo.xfr_len; - } else { - sg_cnt = ioreq->uinfo.uv_sg_ix + 1; - xfr_sz = ioreq->uinfo.uv_offset; - } - - sts = crystalhd_hw_fill_desc(ioreq, desc, desc_paddr_base, sg_cnt, - sg_st_ix, sg_st_off, xfr_sz); - - if ((sts != BC_STS_SUCCESS) || !ioreq->uinfo.uv_offset) - return sts; - - /* Prepare for UV mapping.. */ - desc = &pdesc_mem->pdma_desc_start[sg_cnt]; - desc_paddr_base = pdesc_mem->phy_addr + - (sg_cnt * sizeof(struct dma_descriptor)); - - /* Done with desc addr.. now update sg stuff.*/ - sg_cnt = ioreq->sg_cnt - ioreq->uinfo.uv_sg_ix; - xfr_sz = ioreq->uinfo.xfr_len - ioreq->uinfo.uv_offset; - sg_st_ix = ioreq->uinfo.uv_sg_ix; - sg_st_off = ioreq->uinfo.uv_sg_off; - - sts = crystalhd_hw_fill_desc(ioreq, desc, desc_paddr_base, sg_cnt, - sg_st_ix, sg_st_off, xfr_sz); - if (sts != BC_STS_SUCCESS) - return sts; - - *uv_desc_index = sg_st_ix; - - return sts; -} - -static void crystalhd_start_tx_dma_engine(struct crystalhd_hw *hw) -{ - uint32_t dma_cntrl; - - dma_cntrl = crystalhd_reg_rd(hw->adp, MISC1_TX_SW_DESC_LIST_CTRL_STS); - if (!(dma_cntrl & DMA_START_BIT)) { - dma_cntrl |= DMA_START_BIT; - crystalhd_reg_wr(hw->adp, MISC1_TX_SW_DESC_LIST_CTRL_STS, - dma_cntrl); - } - - return; -} - -/* _CHECK_THIS_ - * - * Verify if the Stop generates a completion interrupt or not. - * if it does not generate an interrupt, then add polling here. - */ -static enum BC_STATUS crystalhd_stop_tx_dma_engine(struct crystalhd_hw *hw) -{ - uint32_t dma_cntrl, cnt = 30; - uint32_t l1 = 1, l2 = 1; - unsigned long flags = 0; - - dma_cntrl = crystalhd_reg_rd(hw->adp, MISC1_TX_SW_DESC_LIST_CTRL_STS); - - BCMLOG(BCMLOG_DBG, "Stopping TX DMA Engine..\n"); - - if (!(dma_cntrl & DMA_START_BIT)) { - BCMLOG(BCMLOG_DBG, "Already Stopped\n"); - return BC_STS_SUCCESS; - } - - crystalhd_disable_interrupts(hw->adp); - - /* Issue stop to HW */ - /* This bit when set gave problems. Please check*/ - dma_cntrl &= ~DMA_START_BIT; - crystalhd_reg_wr(hw->adp, MISC1_TX_SW_DESC_LIST_CTRL_STS, dma_cntrl); - - BCMLOG(BCMLOG_DBG, "Cleared the DMA Start bit\n"); - - /* Poll for 3seconds (30 * 100ms) on both the lists..*/ - while ((l1 || l2) && cnt) { - - if (l1) { - l1 = crystalhd_reg_rd(hw->adp, - MISC1_TX_FIRST_DESC_L_ADDR_LIST0); - l1 &= DMA_START_BIT; - } - - if (l2) { - l2 = crystalhd_reg_rd(hw->adp, - MISC1_TX_FIRST_DESC_L_ADDR_LIST1); - l2 &= DMA_START_BIT; - } - - msleep_interruptible(100); - - cnt--; - } - - if (!cnt) { - BCMLOG_ERR("Failed to stop TX DMA.. l1 %d, l2 %d\n", l1, l2); - crystalhd_enable_interrupts(hw->adp); - return BC_STS_ERROR; - } - - spin_lock_irqsave(&hw->lock, flags); - hw->tx_list_post_index = 0; - spin_unlock_irqrestore(&hw->lock, flags); - BCMLOG(BCMLOG_DBG, "stopped TX DMA..\n"); - crystalhd_enable_interrupts(hw->adp); - - return BC_STS_SUCCESS; -} - -static uint32_t crystalhd_get_pib_avail_cnt(struct crystalhd_hw *hw) -{ - /* - * Position of the PIB Entries can be found at - * 0th and the 1st location of the Circular list. - */ - uint32_t Q_addr; - uint32_t pib_cnt, r_offset, w_offset; - - Q_addr = hw->pib_del_Q_addr; - - /* Get the Read Pointer */ - crystalhd_mem_rd(hw->adp, Q_addr, 1, &r_offset); - - /* Get the Write Pointer */ - crystalhd_mem_rd(hw->adp, Q_addr + sizeof(uint32_t), 1, &w_offset); - - if (r_offset == w_offset) - return 0; /* Queue is empty */ - - if (w_offset > r_offset) - pib_cnt = w_offset - r_offset; - else - pib_cnt = (w_offset + MAX_PIB_Q_DEPTH) - - (r_offset + MIN_PIB_Q_DEPTH); - - if (pib_cnt > MAX_PIB_Q_DEPTH) { - BCMLOG_ERR("Invalid PIB Count (%u)\n", pib_cnt); - return 0; - } - - return pib_cnt; -} - -static uint32_t crystalhd_get_addr_from_pib_Q(struct crystalhd_hw *hw) -{ - uint32_t Q_addr; - uint32_t addr_entry, r_offset, w_offset; - - Q_addr = hw->pib_del_Q_addr; - - /* Get the Read Pointer 0Th Location is Read Pointer */ - crystalhd_mem_rd(hw->adp, Q_addr, 1, &r_offset); - - /* Get the Write Pointer 1st Location is Write pointer */ - crystalhd_mem_rd(hw->adp, Q_addr + sizeof(uint32_t), 1, &w_offset); - - /* Queue is empty */ - if (r_offset == w_offset) - return 0; - - if ((r_offset < MIN_PIB_Q_DEPTH) || (r_offset >= MAX_PIB_Q_DEPTH)) - return 0; - - /* Get the Actual Address of the PIB */ - crystalhd_mem_rd(hw->adp, Q_addr + (r_offset * sizeof(uint32_t)), - 1, &addr_entry); - - /* Increment the Read Pointer */ - r_offset++; - - if (MAX_PIB_Q_DEPTH == r_offset) - r_offset = MIN_PIB_Q_DEPTH; - - /* Write back the read pointer to It's Location */ - crystalhd_mem_wr(hw->adp, Q_addr, 1, &r_offset); - - return addr_entry; -} - -static bool crystalhd_rel_addr_to_pib_Q(struct crystalhd_hw *hw, - uint32_t addr_to_rel) -{ - uint32_t Q_addr; - uint32_t r_offset, w_offset, n_offset; - - Q_addr = hw->pib_rel_Q_addr; - - /* Get the Read Pointer */ - crystalhd_mem_rd(hw->adp, Q_addr, 1, &r_offset); - - /* Get the Write Pointer */ - crystalhd_mem_rd(hw->adp, Q_addr + sizeof(uint32_t), 1, &w_offset); - - if ((r_offset < MIN_PIB_Q_DEPTH) || - (r_offset >= MAX_PIB_Q_DEPTH)) - return false; - - n_offset = w_offset + 1; - - if (MAX_PIB_Q_DEPTH == n_offset) - n_offset = MIN_PIB_Q_DEPTH; - - if (r_offset == n_offset) - return false; /* should never happen */ - - /* Write the DRAM ADDR to the Queue at Next Offset */ - crystalhd_mem_wr(hw->adp, Q_addr + (w_offset * sizeof(uint32_t)), - 1, &addr_to_rel); - - /* Put the New value of the write pointer in Queue */ - crystalhd_mem_wr(hw->adp, Q_addr + sizeof(uint32_t), 1, &n_offset); - - return true; -} - -static void cpy_pib_to_app(struct c011_pib *src_pib, - struct BC_PIC_INFO_BLOCK *dst_pib) -{ - if (!src_pib || !dst_pib) { - BCMLOG_ERR("Invalid Arguments\n"); - return; - } - - dst_pib->timeStamp = 0; - dst_pib->picture_number = src_pib->ppb.picture_number; - dst_pib->width = src_pib->ppb.width; - dst_pib->height = src_pib->ppb.height; - dst_pib->chroma_format = src_pib->ppb.chroma_format; - dst_pib->pulldown = src_pib->ppb.pulldown; - dst_pib->flags = src_pib->ppb.flags; - dst_pib->sess_num = src_pib->ptsStcOffset; - dst_pib->aspect_ratio = src_pib->ppb.aspect_ratio; - dst_pib->colour_primaries = src_pib->ppb.colour_primaries; - dst_pib->picture_meta_payload = src_pib->ppb.picture_meta_payload; - dst_pib->frame_rate = src_pib->resolution; - return; -} - -static void crystalhd_hw_proc_pib(struct crystalhd_hw *hw) -{ - unsigned int cnt; - struct c011_pib src_pib; - uint32_t pib_addr, pib_cnt; - struct BC_PIC_INFO_BLOCK *AppPib; - struct crystalhd_rx_dma_pkt *rx_pkt = NULL; - - pib_cnt = crystalhd_get_pib_avail_cnt(hw); - - if (!pib_cnt) - return; - - for (cnt = 0; cnt < pib_cnt; cnt++) { - - pib_addr = crystalhd_get_addr_from_pib_Q(hw); - crystalhd_mem_rd(hw->adp, pib_addr, sizeof(struct c011_pib) / 4, - (uint32_t *)&src_pib); - - if (src_pib.bFormatChange) { - rx_pkt = (struct crystalhd_rx_dma_pkt *) - crystalhd_dioq_fetch(hw->rx_freeq); - if (!rx_pkt) - return; - rx_pkt->flags = 0; - rx_pkt->flags |= COMP_FLAG_PIB_VALID | - COMP_FLAG_FMT_CHANGE; - AppPib = &rx_pkt->pib; - cpy_pib_to_app(&src_pib, AppPib); - - BCMLOG(BCMLOG_DBG, - "App PIB:%x %x %x %x %x %x %x %x %x %x\n", - 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.height, - rx_pkt->pib.n_drop, - rx_pkt->pib.pulldown, - rx_pkt->pib.ycom); - - crystalhd_dioq_add(hw->rx_rdyq, (void *)rx_pkt, true, - rx_pkt->pkt_tag); - - } - - crystalhd_rel_addr_to_pib_Q(hw, pib_addr); - } -} - -static void crystalhd_start_rx_dma_engine(struct crystalhd_hw *hw) -{ - uint32_t dma_cntrl; - - dma_cntrl = crystalhd_reg_rd(hw->adp, - MISC1_Y_RX_SW_DESC_LIST_CTRL_STS); - if (!(dma_cntrl & DMA_START_BIT)) { - dma_cntrl |= DMA_START_BIT; - crystalhd_reg_wr(hw->adp, - MISC1_Y_RX_SW_DESC_LIST_CTRL_STS, dma_cntrl); - } - - dma_cntrl = crystalhd_reg_rd(hw->adp, - MISC1_UV_RX_SW_DESC_LIST_CTRL_STS); - if (!(dma_cntrl & DMA_START_BIT)) { - dma_cntrl |= DMA_START_BIT; - crystalhd_reg_wr(hw->adp, - MISC1_UV_RX_SW_DESC_LIST_CTRL_STS, dma_cntrl); - } - - return; -} - -static void crystalhd_stop_rx_dma_engine(struct crystalhd_hw *hw) -{ - uint32_t dma_cntrl = 0, count = 30; - uint32_t l0y = 1, l0uv = 1, l1y = 1, l1uv = 1; - - dma_cntrl = crystalhd_reg_rd(hw->adp, - MISC1_Y_RX_SW_DESC_LIST_CTRL_STS); - if ((dma_cntrl & DMA_START_BIT)) { - dma_cntrl &= ~DMA_START_BIT; - crystalhd_reg_wr(hw->adp, - MISC1_Y_RX_SW_DESC_LIST_CTRL_STS, dma_cntrl); - } - - dma_cntrl = crystalhd_reg_rd(hw->adp, - MISC1_UV_RX_SW_DESC_LIST_CTRL_STS); - if ((dma_cntrl & DMA_START_BIT)) { - dma_cntrl &= ~DMA_START_BIT; - crystalhd_reg_wr(hw->adp, - MISC1_UV_RX_SW_DESC_LIST_CTRL_STS, dma_cntrl); - } - - /* Poll for 3seconds (30 * 100ms) on both the lists..*/ - while ((l0y || l0uv || l1y || l1uv) && count) { - - if (l0y) { - l0y = crystalhd_reg_rd(hw->adp, - MISC1_Y_RX_FIRST_DESC_L_ADDR_LIST0); - l0y &= DMA_START_BIT; - if (!l0y) - hw->rx_list_sts[0] &= ~rx_waiting_y_intr; - } - - if (l1y) { - l1y = crystalhd_reg_rd(hw->adp, - MISC1_Y_RX_FIRST_DESC_L_ADDR_LIST1); - l1y &= DMA_START_BIT; - if (!l1y) - hw->rx_list_sts[1] &= ~rx_waiting_y_intr; - } - - if (l0uv) { - l0uv = crystalhd_reg_rd(hw->adp, - MISC1_UV_RX_FIRST_DESC_L_ADDR_LIST0); - l0uv &= DMA_START_BIT; - if (!l0uv) - hw->rx_list_sts[0] &= ~rx_waiting_uv_intr; - } - - if (l1uv) { - l1uv = crystalhd_reg_rd(hw->adp, - MISC1_UV_RX_FIRST_DESC_L_ADDR_LIST1); - l1uv &= DMA_START_BIT; - if (!l1uv) - hw->rx_list_sts[1] &= ~rx_waiting_uv_intr; - } - msleep_interruptible(100); - count--; - } - - hw->rx_list_post_index = 0; - - BCMLOG(BCMLOG_SSTEP, "Capture Stop: %d List0:Sts:%x List1:Sts:%x\n", - count, hw->rx_list_sts[0], hw->rx_list_sts[1]); -} - -static enum BC_STATUS crystalhd_hw_prog_rxdma(struct crystalhd_hw *hw, - struct crystalhd_rx_dma_pkt *rx_pkt) -{ - uint32_t y_low_addr_reg, y_high_addr_reg; - uint32_t uv_low_addr_reg, uv_high_addr_reg; - union addr_64 desc_addr; - unsigned long flags; - - if (!hw || !rx_pkt) { - BCMLOG_ERR("Invalid Arguments\n"); - return BC_STS_INV_ARG; - } - - if (hw->rx_list_post_index >= DMA_ENGINE_CNT) { - BCMLOG_ERR("List Out Of bounds %x\n", hw->rx_list_post_index); - return BC_STS_INV_ARG; - } - - spin_lock_irqsave(&hw->rx_lock, flags); - /* FIXME: jarod: sts_free is an enum for 0, - in crystalhd_hw.h... yuk... */ - if (sts_free != hw->rx_list_sts[hw->rx_list_post_index]) { - spin_unlock_irqrestore(&hw->rx_lock, flags); - return BC_STS_BUSY; - } - - if (!hw->rx_list_post_index) { - y_low_addr_reg = MISC1_Y_RX_FIRST_DESC_L_ADDR_LIST0; - y_high_addr_reg = MISC1_Y_RX_FIRST_DESC_U_ADDR_LIST0; - uv_low_addr_reg = MISC1_UV_RX_FIRST_DESC_L_ADDR_LIST0; - uv_high_addr_reg = MISC1_UV_RX_FIRST_DESC_U_ADDR_LIST0; - } else { - y_low_addr_reg = MISC1_Y_RX_FIRST_DESC_L_ADDR_LIST1; - y_high_addr_reg = MISC1_Y_RX_FIRST_DESC_U_ADDR_LIST1; - uv_low_addr_reg = MISC1_UV_RX_FIRST_DESC_L_ADDR_LIST1; - uv_high_addr_reg = MISC1_UV_RX_FIRST_DESC_U_ADDR_LIST1; - } - 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); - - crystalhd_start_rx_dma_engine(hw); - /* Program the Y descriptor */ - desc_addr.full_addr = rx_pkt->desc_mem.phy_addr; - crystalhd_reg_wr(hw->adp, y_high_addr_reg, desc_addr.high_part); - crystalhd_reg_wr(hw->adp, y_low_addr_reg, desc_addr.low_part | 0x01); - - if (rx_pkt->uv_phy_addr) { - /* Program the UV descriptor */ - desc_addr.full_addr = rx_pkt->uv_phy_addr; - crystalhd_reg_wr(hw->adp, uv_high_addr_reg, - desc_addr.high_part); - crystalhd_reg_wr(hw->adp, uv_low_addr_reg, - desc_addr.low_part | 0x01); - } - - return BC_STS_SUCCESS; -} - -static enum BC_STATUS crystalhd_hw_post_cap_buff(struct crystalhd_hw *hw, - struct crystalhd_rx_dma_pkt *rx_pkt) -{ - enum BC_STATUS sts = crystalhd_hw_prog_rxdma(hw, rx_pkt); - - if (sts == BC_STS_BUSY) - crystalhd_dioq_add(hw->rx_freeq, (void *)rx_pkt, - false, rx_pkt->pkt_tag); - - return sts; -} - -static void crystalhd_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 = MISC1_Y_RX_LIST0_CUR_BYTE_CNT; - uv_dn_sz_reg = MISC1_UV_RX_LIST0_CUR_BYTE_CNT; - } else { - y_dn_sz_reg = MISC1_Y_RX_LIST1_CUR_BYTE_CNT; - uv_dn_sz_reg = MISC1_UV_RX_LIST1_CUR_BYTE_CNT; - } - - *y_dw_dnsz = crystalhd_reg_rd(hw->adp, y_dn_sz_reg); - *uv_dw_dnsz = crystalhd_reg_rd(hw->adp, uv_dn_sz_reg); -} - -/* - * This function should be called only after making sure that the two DMA - * lists are free. This function does not check if DMA's are active, before - * turning off the DMA. - */ -static void crystalhd_hw_finalize_pause(struct crystalhd_hw *hw) -{ - uint32_t dma_cntrl, aspm; - - hw->stop_pending = 0; - - dma_cntrl = crystalhd_reg_rd(hw->adp, - MISC1_Y_RX_SW_DESC_LIST_CTRL_STS); - if (dma_cntrl & DMA_START_BIT) { - dma_cntrl &= ~DMA_START_BIT; - crystalhd_reg_wr(hw->adp, - MISC1_Y_RX_SW_DESC_LIST_CTRL_STS, dma_cntrl); - } - - dma_cntrl = crystalhd_reg_rd(hw->adp, - MISC1_UV_RX_SW_DESC_LIST_CTRL_STS); - if (dma_cntrl & DMA_START_BIT) { - dma_cntrl &= ~DMA_START_BIT; - crystalhd_reg_wr(hw->adp, - MISC1_UV_RX_SW_DESC_LIST_CTRL_STS, dma_cntrl); - } - hw->rx_list_post_index = 0; - - aspm = crystalhd_reg_rd(hw->adp, PCIE_DLL_DATA_LINK_CONTROL); - aspm |= ASPM_L1_ENABLE; - /* NAREN BCMLOG(BCMLOG_INFO, "aspm on\n"); */ - crystalhd_reg_wr(hw->adp, PCIE_DLL_DATA_LINK_CONTROL, aspm); -} - -static enum BC_STATUS crystalhd_rx_pkt_done(struct crystalhd_hw *hw, - uint32_t list_index, enum BC_STATUS comp_sts) -{ - struct crystalhd_rx_dma_pkt *rx_pkt = NULL; - uint32_t y_dw_dnsz, uv_dw_dnsz; - enum BC_STATUS sts = BC_STS_SUCCESS; - - if (!hw || list_index >= DMA_ENGINE_CNT) { - BCMLOG_ERR("Invalid Arguments\n"); - return BC_STS_INV_ARG; - } - - rx_pkt = crystalhd_dioq_find_and_fetch(hw->rx_actq, - hw->rx_pkt_tag_seed + list_index); - if (!rx_pkt) { - BCMLOG_ERR( - "Act-Q:PostIx:%x L0Sts:%x L1Sts:%x current L:%x tag:%x comp:%x\n", - hw->rx_list_post_index, hw->rx_list_sts[0], - hw->rx_list_sts[1], list_index, - hw->rx_pkt_tag_seed + list_index, comp_sts); - return BC_STS_INV_ARG; - } - - if (comp_sts == BC_STS_SUCCESS) { - crystalhd_get_dnsz(hw, list_index, &y_dw_dnsz, &uv_dw_dnsz); - rx_pkt->dio_req->uinfo.y_done_sz = y_dw_dnsz; - rx_pkt->flags = COMP_FLAG_DATA_VALID; - if (rx_pkt->uv_phy_addr) - rx_pkt->dio_req->uinfo.uv_done_sz = uv_dw_dnsz; - crystalhd_dioq_add(hw->rx_rdyq, rx_pkt, true, - hw->rx_pkt_tag_seed + list_index); - return sts; - } - - /* Check if we can post this DIO again. */ - return crystalhd_hw_post_cap_buff(hw, rx_pkt); -} - -static bool crystalhd_rx_list0_handler(struct crystalhd_hw *hw, - uint32_t 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 & INTR_INTR_STATUS_L0_Y_RX_DMA_DONE_INTR_MASK) - 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) { - 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 & INTR_INTR_STATUS_L0_UV_RX_DMA_DONE_INTR_MASK) - 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) { - 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; - crystalhd_reg_wr(hw->adp, MISC1_Y_RX_ERROR_STATUS, tmp); - } - - if (uv_err_sts & GET_UV0_ERR_MSK) { - tmp = uv_err_sts & GET_UV0_ERR_MSK; - crystalhd_reg_wr(hw->adp, MISC1_UV_RX_ERROR_STATUS, tmp); - } - - return tmp_lsts != hw->rx_list_sts[0]; -} - -static bool crystalhd_rx_list1_handler(struct crystalhd_hw *hw, - uint32_t 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 & INTR_INTR_STATUS_L1_Y_RX_DMA_DONE_INTR_MASK) - 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) { - /* Add retry-support..*/ - 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 & INTR_INTR_STATUS_L1_UV_RX_DMA_DONE_INTR_MASK) - 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) { - /* Add retry-support*/ - 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; - crystalhd_reg_wr(hw->adp, MISC1_Y_RX_ERROR_STATUS, tmp); - } - - if (uv_err_sts & GET_UV1_ERR_MSK) { - tmp = uv_err_sts & GET_UV1_ERR_MSK; - crystalhd_reg_wr(hw->adp, MISC1_UV_RX_ERROR_STATUS, tmp); - } - - return tmp_lsts != hw->rx_list_sts[1]; -} - - -static void crystalhd_rx_isr(struct crystalhd_hw *hw, uint32_t intr_sts) -{ - unsigned long flags; - uint32_t i, list_avail = 0; - enum 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 = false; - - if (!hw) { - BCMLOG_ERR("Invalid Arguments\n"); - return; - } - - if (!(intr_sts & GET_RX_INTR_MASK)) - return; - - y_err_sts = crystalhd_reg_rd(hw->adp, MISC1_Y_RX_ERROR_STATUS); - uv_err_sts = crystalhd_reg_rd(hw->adp, MISC1_UV_RX_ERROR_STATUS); - - for (i = 0; i < DMA_ENGINE_CNT; i++) { - /* Update States..*/ - spin_lock_irqsave(&hw->rx_lock, flags); - if (i == 0) - ret = crystalhd_rx_list0_handler(hw, intr_sts, - y_err_sts, uv_err_sts); - else - ret = crystalhd_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; - 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++; - crystalhd_get_dnsz(hw, i, &y_dn_sz, &uv_dn_sz); - /* FIXME: jarod: this is where - my mini pci-e card is tripping up */ - BCMLOG(BCMLOG_DBG, "list_index:%x rx[%d] Y:%x UV:%x Int:%x YDnSz:%x UVDnSz:%x\n", - i, hw->stats.rx_errors, y_err_sts, - uv_err_sts, intr_sts, 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; - } - } - spin_unlock_irqrestore(&hw->rx_lock, flags); - - /* handle completion...*/ - if (comp_sts != BC_STS_NO_DATA) { - crystalhd_rx_pkt_done(hw, i, comp_sts); - comp_sts = BC_STS_NO_DATA; - } - } - - if (list_avail) { - if (hw->stop_pending) { - if ((hw->rx_list_sts[0] == sts_free) && - (hw->rx_list_sts[1] == sts_free)) - crystalhd_hw_finalize_pause(hw); - } else { - crystalhd_hw_start_capture(hw); - } - } -} - -static enum BC_STATUS crystalhd_fw_cmd_post_proc(struct crystalhd_hw *hw, - struct BC_FW_CMD *fw_cmd) -{ - enum BC_STATUS sts = BC_STS_SUCCESS; - struct dec_rsp_channel_start_video *st_rsp = NULL; - - switch (fw_cmd->cmd[0]) { - case eCMD_C011_DEC_CHAN_START_VIDEO: - st_rsp = (struct dec_rsp_channel_start_video *)fw_cmd->rsp; - hw->pib_del_Q_addr = st_rsp->picInfoDeliveryQ; - hw->pib_rel_Q_addr = st_rsp->picInfoReleaseQ; - BCMLOG(BCMLOG_DBG, "DelQAddr:%x RelQAddr:%x\n", - hw->pib_del_Q_addr, hw->pib_rel_Q_addr); - break; - case eCMD_C011_INIT: - if (!(crystalhd_load_firmware_config(hw->adp))) { - BCMLOG_ERR("Invalid Params.\n"); - sts = BC_STS_FW_AUTH_FAILED; - } - break; - default: - break; - } - return sts; -} - -static enum BC_STATUS crystalhd_put_ddr2sleep(struct crystalhd_hw *hw) -{ - uint32_t reg; - union link_misc_perst_decoder_ctrl rst_cntrl_reg; - - /* Pulse reset pin of 7412 (MISC_PERST_DECODER_CTRL) */ - rst_cntrl_reg.whole_reg = crystalhd_reg_rd(hw->adp, - MISC_PERST_DECODER_CTRL); - - rst_cntrl_reg.bcm_7412_rst = 1; - crystalhd_reg_wr(hw->adp, MISC_PERST_DECODER_CTRL, - rst_cntrl_reg.whole_reg); - msleep_interruptible(50); - - rst_cntrl_reg.bcm_7412_rst = 0; - crystalhd_reg_wr(hw->adp, MISC_PERST_DECODER_CTRL, - rst_cntrl_reg.whole_reg); - - /* Close all banks, put DDR in idle */ - bc_dec_reg_wr(hw->adp, SDRAM_PRECHARGE, 0); - - /* Set bit 25 (drop CKE pin of DDR) */ - reg = bc_dec_reg_rd(hw->adp, SDRAM_PARAM); - reg |= 0x02000000; - bc_dec_reg_wr(hw->adp, SDRAM_PARAM, reg); - - /* Reset the audio block */ - bc_dec_reg_wr(hw->adp, AUD_DSP_MISC_SOFT_RESET, 0x1); - - /* Power down Raptor PLL */ - reg = bc_dec_reg_rd(hw->adp, DecHt_PllCCtl); - reg |= 0x00008000; - bc_dec_reg_wr(hw->adp, DecHt_PllCCtl, reg); - - /* Power down all Audio PLL */ - bc_dec_reg_wr(hw->adp, AIO_MISC_PLL_RESET, 0x1); - - /* Power down video clock (75MHz) */ - reg = bc_dec_reg_rd(hw->adp, DecHt_PllECtl); - reg |= 0x00008000; - bc_dec_reg_wr(hw->adp, DecHt_PllECtl, reg); - - /* Power down video clock (75MHz) */ - reg = bc_dec_reg_rd(hw->adp, DecHt_PllDCtl); - reg |= 0x00008000; - bc_dec_reg_wr(hw->adp, DecHt_PllDCtl, reg); - - /* Power down core clock (200MHz) */ - reg = bc_dec_reg_rd(hw->adp, DecHt_PllACtl); - reg |= 0x00008000; - bc_dec_reg_wr(hw->adp, DecHt_PllACtl, reg); - - /* Power down core clock (200MHz) */ - reg = bc_dec_reg_rd(hw->adp, DecHt_PllBCtl); - reg |= 0x00008000; - bc_dec_reg_wr(hw->adp, DecHt_PllBCtl, reg); - - return BC_STS_SUCCESS; -} - -/************************************************ -** -*************************************************/ - -enum BC_STATUS crystalhd_download_fw(struct crystalhd_adp *adp, void *buffer, - uint32_t sz) -{ - uint32_t reg_data, cnt, *temp_buff; - uint32_t fw_sig_len = 36; - uint32_t dram_offset = BC_FWIMG_ST_ADDR, sig_reg; - - - if (!adp || !buffer || !sz) { - BCMLOG_ERR("Invalid Params.\n"); - return BC_STS_INV_ARG; - } - - reg_data = crystalhd_reg_rd(adp, OTP_CMD); - if (!(reg_data & 0x02)) { - BCMLOG_ERR("Invalid hw config.. otp not programmed\n"); - return BC_STS_ERROR; - } - - reg_data = 0; - crystalhd_reg_wr(adp, DCI_CMD, 0); - reg_data |= BC_BIT(0); - crystalhd_reg_wr(adp, DCI_CMD, reg_data); - - reg_data = 0; - cnt = 1000; - msleep_interruptible(10); - - while (reg_data != BC_BIT(4)) { - reg_data = crystalhd_reg_rd(adp, DCI_STATUS); - reg_data &= BC_BIT(4); - if (--cnt == 0) { - BCMLOG_ERR("Firmware Download RDY Timeout.\n"); - return BC_STS_TIMEOUT; - } - } - - msleep_interruptible(10); - /* Load the FW to the FW_ADDR field in the DCI_FIRMWARE_ADDR */ - crystalhd_reg_wr(adp, DCI_FIRMWARE_ADDR, dram_offset); - temp_buff = (uint32_t *)buffer; - for (cnt = 0; cnt < (sz - fw_sig_len); cnt += 4) { - crystalhd_reg_wr(adp, DCI_DRAM_BASE_ADDR, (dram_offset >> 19)); - crystalhd_reg_wr(adp, DCI_FIRMWARE_DATA, *temp_buff); - dram_offset += 4; - temp_buff++; - } - msleep_interruptible(10); - - temp_buff++; - - sig_reg = (uint32_t)DCI_SIGNATURE_DATA_7; - for (cnt = 0; cnt < 8; cnt++) { - uint32_t swapped_data = *temp_buff; - swapped_data = bswap_32_1(swapped_data); - crystalhd_reg_wr(adp, sig_reg, swapped_data); - sig_reg -= 4; - temp_buff++; - } - msleep_interruptible(10); - - reg_data = 0; - reg_data |= BC_BIT(1); - crystalhd_reg_wr(adp, DCI_CMD, reg_data); - msleep_interruptible(10); - - reg_data = 0; - reg_data = crystalhd_reg_rd(adp, DCI_STATUS); - - if ((reg_data & BC_BIT(9)) == BC_BIT(9)) { - cnt = 1000; - while ((reg_data & BC_BIT(0)) != BC_BIT(0)) { - reg_data = crystalhd_reg_rd(adp, DCI_STATUS); - reg_data &= BC_BIT(0); - if (!(--cnt)) - break; - msleep_interruptible(10); - } - reg_data = 0; - reg_data = crystalhd_reg_rd(adp, DCI_CMD); - reg_data |= BC_BIT(4); - crystalhd_reg_wr(adp, DCI_CMD, reg_data); - - } else { - BCMLOG_ERR("F/w Signature mismatch\n"); - return BC_STS_FW_AUTH_FAILED; - } - - BCMLOG(BCMLOG_INFO, "Firmware Downloaded Successfully\n"); - return BC_STS_SUCCESS; -} - -enum BC_STATUS crystalhd_do_fw_cmd(struct crystalhd_hw *hw, - struct BC_FW_CMD *fw_cmd) -{ - uint32_t cnt = 0, cmd_res_addr; - uint32_t *cmd_buff, *res_buff; - wait_queue_head_t fw_cmd_event; - int rc = 0; - enum BC_STATUS sts; - - crystalhd_create_event(&fw_cmd_event); - - if (!hw || !fw_cmd) { - BCMLOG_ERR("Invalid Arguments\n"); - return BC_STS_INV_ARG; - } - - cmd_buff = fw_cmd->cmd; - res_buff = fw_cmd->rsp; - - if (!cmd_buff || !res_buff) { - BCMLOG_ERR("Invalid Parameters for F/W Command\n"); - return BC_STS_INV_ARG; - } - - hw->pwr_lock++; - - hw->fwcmd_evt_sts = 0; - hw->pfw_cmd_event = &fw_cmd_event; - - /*Write the command to the memory*/ - crystalhd_mem_wr(hw->adp, TS_Host2CpuSnd, FW_CMD_BUFF_SZ, cmd_buff); - - /*Memory Read for memory arbitrator flush*/ - crystalhd_mem_rd(hw->adp, TS_Host2CpuSnd, 1, &cnt); - - /* Write the command address to mailbox */ - bc_dec_reg_wr(hw->adp, Hst2CpuMbx1, TS_Host2CpuSnd); - msleep_interruptible(50); - - crystalhd_wait_on_event(&fw_cmd_event, hw->fwcmd_evt_sts, 20000, rc, 0); - - if (!rc) { - sts = BC_STS_SUCCESS; - } else if (rc == -EBUSY) { - BCMLOG_ERR("Firmware command T/O\n"); - sts = BC_STS_TIMEOUT; - } else if (rc == -EINTR) { - BCMLOG(BCMLOG_DBG, "FwCmd Wait Signal int.\n"); - sts = BC_STS_IO_USER_ABORT; - } else { - BCMLOG_ERR("FwCmd IO Error.\n"); - sts = BC_STS_IO_ERROR; - } - - if (sts != BC_STS_SUCCESS) { - BCMLOG_ERR("FwCmd Failed.\n"); - hw->pwr_lock--; - return sts; - } - - /*Get the Response Address*/ - cmd_res_addr = bc_dec_reg_rd(hw->adp, Cpu2HstMbx1); - - /*Read the Response*/ - crystalhd_mem_rd(hw->adp, cmd_res_addr, FW_CMD_BUFF_SZ, res_buff); - - hw->pwr_lock--; - - if (res_buff[2] != C011_RET_SUCCESS) { - BCMLOG_ERR("res_buff[2] != C011_RET_SUCCESS\n"); - return BC_STS_FW_CMD_ERR; - } - - sts = crystalhd_fw_cmd_post_proc(hw, fw_cmd); - if (sts != BC_STS_SUCCESS) - BCMLOG_ERR("crystalhd_fw_cmd_post_proc Failed.\n"); - - return sts; -} - -bool crystalhd_hw_interrupt(struct crystalhd_adp *adp, struct crystalhd_hw *hw) -{ - uint32_t intr_sts = 0; - uint32_t deco_intr = 0; - bool rc = false; - - if (!adp || !hw->dev_started) - return rc; - - hw->stats.num_interrupts++; - hw->pwr_lock++; - - deco_intr = bc_dec_reg_rd(adp, Stream2Host_Intr_Sts); - intr_sts = crystalhd_reg_rd(adp, INTR_INTR_STATUS); - - if (intr_sts) { - /* let system know we processed interrupt..*/ - rc = true; - hw->stats.dev_interrupts++; - } - - if (deco_intr && (deco_intr != 0xdeaddead)) { - - if (deco_intr & 0x80000000) { - /*Set the Event and the status flag*/ - if (hw->pfw_cmd_event) { - hw->fwcmd_evt_sts = 1; - crystalhd_set_event(hw->pfw_cmd_event); - } - } - - if (deco_intr & BC_BIT(1)) - crystalhd_hw_proc_pib(hw); - - bc_dec_reg_wr(adp, Stream2Host_Intr_Sts, deco_intr); - /* FIXME: jarod: No udelay? might this be - the real reason mini pci-e cards were stalling out? */ - bc_dec_reg_wr(adp, Stream2Host_Intr_Sts, 0); - rc = true; - } - - /* Rx interrupts */ - crystalhd_rx_isr(hw, intr_sts); - - /* Tx interrupts*/ - crystalhd_tx_isr(hw, intr_sts); - - /* Clear interrupts */ - if (rc) { - if (intr_sts) - crystalhd_reg_wr(adp, INTR_INTR_CLR_REG, intr_sts); - - crystalhd_reg_wr(adp, INTR_EOI_CTRL, 1); - } - - hw->pwr_lock--; - - return rc; -} - -enum BC_STATUS crystalhd_hw_open(struct crystalhd_hw *hw, - struct crystalhd_adp *adp) -{ - if (!hw || !adp) { - BCMLOG_ERR("Invalid Arguments\n"); - return BC_STS_INV_ARG; - } - - if (hw->dev_started) - return BC_STS_SUCCESS; - - memset(hw, 0, sizeof(struct crystalhd_hw)); - - hw->adp = adp; - spin_lock_init(&hw->lock); - spin_lock_init(&hw->rx_lock); - /* FIXME: jarod: what are these magic numbers?!? */ - hw->tx_ioq_tag_seed = 0x70023070; - hw->rx_pkt_tag_seed = 0x70029070; - - hw->stop_pending = 0; - crystalhd_start_device(hw->adp); - hw->dev_started = true; - - /* set initial core clock */ - hw->core_clock_mhz = CLOCK_PRESET; - hw->prev_n = 0; - hw->pwr_lock = 0; - crystalhd_hw_set_core_clock(hw); - - return BC_STS_SUCCESS; -} - -enum BC_STATUS crystalhd_hw_close(struct crystalhd_hw *hw) -{ - if (!hw) { - BCMLOG_ERR("Invalid Arguments\n"); - return BC_STS_INV_ARG; - } - - if (!hw->dev_started) - return BC_STS_SUCCESS; - - /* Stop and DDR sleep will happen in here */ - crystalhd_hw_suspend(hw); - hw->dev_started = false; - - return BC_STS_SUCCESS; -} - -enum BC_STATUS crystalhd_hw_setup_dma_rings(struct crystalhd_hw *hw) -{ - unsigned int i; - void *mem; - size_t mem_len; - dma_addr_t phy_addr; - enum BC_STATUS sts = BC_STS_SUCCESS; - struct crystalhd_rx_dma_pkt *rpkt; - - if (!hw || !hw->adp) { - BCMLOG_ERR("Invalid Arguments\n"); - return BC_STS_INV_ARG; - } - - sts = crystalhd_hw_create_ioqs(hw); - if (sts != BC_STS_SUCCESS) { - BCMLOG_ERR("Failed to create IOQs..\n"); - return sts; - } - - mem_len = BC_LINK_MAX_SGLS * sizeof(struct dma_descriptor); - - for (i = 0; i < BC_TX_LIST_CNT; i++) { - mem = bc_kern_dma_alloc(hw->adp, mem_len, &phy_addr); - if (mem) { - memset(mem, 0, mem_len); - } else { - BCMLOG_ERR("Insufficient Memory For TX\n"); - crystalhd_hw_free_dma_rings(hw); - return BC_STS_INSUFF_RES; - } - /* rx_pkt_pool -- static memory allocation */ - hw->tx_pkt_pool[i].desc_mem.pdma_desc_start = mem; - hw->tx_pkt_pool[i].desc_mem.phy_addr = phy_addr; - hw->tx_pkt_pool[i].desc_mem.sz = BC_LINK_MAX_SGLS * - sizeof(struct dma_descriptor); - hw->tx_pkt_pool[i].list_tag = 0; - - /* Add TX dma requests to Free Queue..*/ - sts = crystalhd_dioq_add(hw->tx_freeq, - &hw->tx_pkt_pool[i], false, 0); - if (sts != BC_STS_SUCCESS) { - crystalhd_hw_free_dma_rings(hw); - return sts; - } - } - - for (i = 0; i < BC_RX_LIST_CNT; i++) { - rpkt = kzalloc(sizeof(*rpkt), GFP_KERNEL); - if (!rpkt) { - BCMLOG_ERR("Insufficient Memory For RX\n"); - crystalhd_hw_free_dma_rings(hw); - return BC_STS_INSUFF_RES; - } - - mem = bc_kern_dma_alloc(hw->adp, mem_len, &phy_addr); - if (mem) { - memset(mem, 0, mem_len); - } else { - BCMLOG_ERR("Insufficient Memory For RX\n"); - crystalhd_hw_free_dma_rings(hw); - kfree(rpkt); - return BC_STS_INSUFF_RES; - } - rpkt->desc_mem.pdma_desc_start = mem; - rpkt->desc_mem.phy_addr = phy_addr; - rpkt->desc_mem.sz = BC_LINK_MAX_SGLS * - sizeof(struct dma_descriptor); - rpkt->pkt_tag = hw->rx_pkt_tag_seed + i; - crystalhd_hw_free_rx_pkt(hw, rpkt); - } - - return BC_STS_SUCCESS; -} - -enum BC_STATUS crystalhd_hw_free_dma_rings(struct crystalhd_hw *hw) -{ - unsigned int i; - struct crystalhd_rx_dma_pkt *rpkt = NULL; - - if (!hw || !hw->adp) { - BCMLOG_ERR("Invalid Arguments\n"); - return BC_STS_INV_ARG; - } - - /* Delete all IOQs.. */ - crystalhd_hw_delete_ioqs(hw); - - for (i = 0; i < BC_TX_LIST_CNT; i++) { - if (hw->tx_pkt_pool[i].desc_mem.pdma_desc_start) { - bc_kern_dma_free(hw->adp, - hw->tx_pkt_pool[i].desc_mem.sz, - hw->tx_pkt_pool[i].desc_mem.pdma_desc_start, - hw->tx_pkt_pool[i].desc_mem.phy_addr); - - hw->tx_pkt_pool[i].desc_mem.pdma_desc_start = NULL; - } - } - - BCMLOG(BCMLOG_DBG, "Releasing RX Pkt pool\n"); - do { - rpkt = crystalhd_hw_alloc_rx_pkt(hw); - if (!rpkt) - break; - bc_kern_dma_free(hw->adp, rpkt->desc_mem.sz, - rpkt->desc_mem.pdma_desc_start, - rpkt->desc_mem.phy_addr); - kfree(rpkt); - } while (rpkt); - - return BC_STS_SUCCESS; -} - -enum BC_STATUS crystalhd_hw_post_tx(struct crystalhd_hw *hw, - struct crystalhd_dio_req *ioreq, - hw_comp_callback call_back, - wait_queue_head_t *cb_event, uint32_t *list_id, - uint8_t data_flags) -{ - struct tx_dma_pkt *tx_dma_packet = NULL; - uint32_t first_desc_u_addr, first_desc_l_addr; - uint32_t low_addr, high_addr; - union addr_64 desc_addr; - enum BC_STATUS sts, add_sts; - uint32_t dummy_index = 0; - unsigned long flags; - bool rc; - - if (!hw || !ioreq || !call_back || !cb_event || !list_id) { - BCMLOG_ERR("Invalid Arguments\n"); - return BC_STS_INV_ARG; - } - - /* - * Since we hit code in busy condition very frequently, - * we will check the code in status first before - * checking the availability of free elem. - * - * This will avoid the Q fetch/add in normal condition. - */ - rc = crystalhd_code_in_full(hw->adp, ioreq->uinfo.xfr_len, - false, data_flags); - if (rc) { - hw->stats.cin_busy++; - return BC_STS_BUSY; - } - - /* Get a list from TxFreeQ */ - tx_dma_packet = (struct tx_dma_pkt *)crystalhd_dioq_fetch( - hw->tx_freeq); - if (!tx_dma_packet) { - BCMLOG_ERR("No empty elements..\n"); - return BC_STS_ERR_USAGE; - } - - sts = crystalhd_xlat_sgl_to_dma_desc(ioreq, - &tx_dma_packet->desc_mem, - &dummy_index); - if (sts != BC_STS_SUCCESS) { - add_sts = crystalhd_dioq_add(hw->tx_freeq, tx_dma_packet, - false, 0); - if (add_sts != BC_STS_SUCCESS) - BCMLOG_ERR("double fault..\n"); - - return sts; - } - - hw->pwr_lock++; - - desc_addr.full_addr = tx_dma_packet->desc_mem.phy_addr; - low_addr = desc_addr.low_part; - high_addr = desc_addr.high_part; - - tx_dma_packet->call_back = call_back; - tx_dma_packet->cb_event = cb_event; - tx_dma_packet->dio_req = ioreq; - - spin_lock_irqsave(&hw->lock, flags); - - if (hw->tx_list_post_index == 0) { - first_desc_u_addr = MISC1_TX_FIRST_DESC_U_ADDR_LIST0; - first_desc_l_addr = MISC1_TX_FIRST_DESC_L_ADDR_LIST0; - } else { - first_desc_u_addr = MISC1_TX_FIRST_DESC_U_ADDR_LIST1; - first_desc_l_addr = MISC1_TX_FIRST_DESC_L_ADDR_LIST1; - } - - *list_id = tx_dma_packet->list_tag = hw->tx_ioq_tag_seed + - hw->tx_list_post_index; - - hw->tx_list_post_index = (hw->tx_list_post_index + 1) % DMA_ENGINE_CNT; - - spin_unlock_irqrestore(&hw->lock, flags); - - - /* Insert in Active Q..*/ - crystalhd_dioq_add(hw->tx_actq, tx_dma_packet, false, - tx_dma_packet->list_tag); - - /* - * Interrupt will come as soon as you write - * the valid bit. So be ready for that. All - * the initialization should happen before that. - */ - crystalhd_start_tx_dma_engine(hw); - crystalhd_reg_wr(hw->adp, first_desc_u_addr, desc_addr.high_part); - - crystalhd_reg_wr(hw->adp, first_desc_l_addr, desc_addr.low_part | - 0x01); - /* Be sure we set the valid bit ^^^^ */ - - return BC_STS_SUCCESS; -} - -/* - * This is a force cancel and we are racing with ISR. - * - * Will try to remove the req from ActQ before ISR gets it. - * If ISR gets it first then the completion happens in the - * normal path and we will return _STS_NO_DATA from here. - * - * FIX_ME: Not Tested the actual condition.. - */ -enum BC_STATUS crystalhd_hw_cancel_tx(struct crystalhd_hw *hw, - uint32_t list_id) -{ - if (!hw || !list_id) { - BCMLOG_ERR("Invalid Arguments\n"); - return BC_STS_INV_ARG; - } - - crystalhd_stop_tx_dma_engine(hw); - crystalhd_hw_tx_req_complete(hw, list_id, BC_STS_IO_USER_ABORT); - - return BC_STS_SUCCESS; -} - -enum BC_STATUS crystalhd_hw_add_cap_buffer(struct crystalhd_hw *hw, - struct crystalhd_dio_req *ioreq, bool en_post) -{ - struct crystalhd_rx_dma_pkt *rpkt; - uint32_t tag, uv_desc_ix = 0; - enum BC_STATUS sts; - - if (!hw || !ioreq) { - BCMLOG_ERR("Invalid Arguments\n"); - return BC_STS_INV_ARG; - } - - rpkt = crystalhd_hw_alloc_rx_pkt(hw); - if (!rpkt) { - BCMLOG_ERR("Insufficient resources\n"); - return BC_STS_INSUFF_RES; - } - - rpkt->dio_req = ioreq; - tag = rpkt->pkt_tag; - - sts = crystalhd_xlat_sgl_to_dma_desc(ioreq, &rpkt->desc_mem, - &uv_desc_ix); - if (sts != BC_STS_SUCCESS) - return sts; - - rpkt->uv_phy_addr = 0; - - /* Store the address of UV in the rx packet for post*/ - if (uv_desc_ix) - rpkt->uv_phy_addr = rpkt->desc_mem.phy_addr + - (sizeof(struct dma_descriptor) * (uv_desc_ix + 1)); - - if (en_post) - sts = crystalhd_hw_post_cap_buff(hw, rpkt); - else - sts = crystalhd_dioq_add(hw->rx_freeq, rpkt, false, tag); - - return sts; -} - -enum BC_STATUS crystalhd_hw_get_cap_buffer(struct crystalhd_hw *hw, - struct BC_PIC_INFO_BLOCK *pib, - struct crystalhd_dio_req **ioreq) -{ - struct crystalhd_rx_dma_pkt *rpkt; - uint32_t timeout = BC_PROC_OUTPUT_TIMEOUT / 1000; - uint32_t sig_pending = 0; - - - if (!hw || !ioreq || !pib) { - BCMLOG_ERR("Invalid Arguments\n"); - return BC_STS_INV_ARG; - } - - rpkt = crystalhd_dioq_fetch_wait(hw->rx_rdyq, timeout, &sig_pending); - if (!rpkt) { - if (sig_pending) { - BCMLOG(BCMLOG_INFO, "wait on frame time out %d\n", - sig_pending); - return BC_STS_IO_USER_ABORT; - } else { - return BC_STS_TIMEOUT; - } - } - - rpkt->dio_req->uinfo.comp_flags = rpkt->flags; - - if (rpkt->flags & COMP_FLAG_PIB_VALID) - memcpy(pib, &rpkt->pib, sizeof(*pib)); - - *ioreq = rpkt->dio_req; - - crystalhd_hw_free_rx_pkt(hw, rpkt); - - return BC_STS_SUCCESS; -} - -enum BC_STATUS crystalhd_hw_start_capture(struct crystalhd_hw *hw) -{ - struct crystalhd_rx_dma_pkt *rx_pkt; - enum BC_STATUS sts; - uint32_t i; - - if (!hw) { - BCMLOG_ERR("Invalid Arguments\n"); - return BC_STS_INV_ARG; - } - - /* This is start of capture.. Post to both the lists.. */ - for (i = 0; i < DMA_ENGINE_CNT; i++) { - rx_pkt = crystalhd_dioq_fetch(hw->rx_freeq); - if (!rx_pkt) - return BC_STS_NO_DATA; - sts = crystalhd_hw_post_cap_buff(hw, rx_pkt); - if (BC_STS_SUCCESS != sts) - break; - - } - - return BC_STS_SUCCESS; -} - -enum BC_STATUS crystalhd_hw_stop_capture(struct crystalhd_hw *hw) -{ - void *temp = NULL; - - if (!hw) { - BCMLOG_ERR("Invalid Arguments\n"); - return BC_STS_INV_ARG; - } - - crystalhd_stop_rx_dma_engine(hw); - - do { - temp = crystalhd_dioq_fetch(hw->rx_freeq); - if (temp) - crystalhd_rx_pkt_rel_call_back(hw, temp); - } while (temp); - - return BC_STS_SUCCESS; -} - -enum BC_STATUS crystalhd_hw_pause(struct crystalhd_hw *hw) -{ - hw->stats.pause_cnt++; - hw->stop_pending = 1; - - if ((hw->rx_list_sts[0] == sts_free) && - (hw->rx_list_sts[1] == sts_free)) - crystalhd_hw_finalize_pause(hw); - - return BC_STS_SUCCESS; -} - -enum BC_STATUS crystalhd_hw_unpause(struct crystalhd_hw *hw) -{ - enum BC_STATUS sts; - uint32_t aspm; - - hw->stop_pending = 0; - - aspm = crystalhd_reg_rd(hw->adp, PCIE_DLL_DATA_LINK_CONTROL); - aspm &= ~ASPM_L1_ENABLE; -/* NAREN BCMLOG(BCMLOG_INFO, "aspm off\n"); */ - crystalhd_reg_wr(hw->adp, PCIE_DLL_DATA_LINK_CONTROL, aspm); - - sts = crystalhd_hw_start_capture(hw); - return sts; -} - -enum BC_STATUS crystalhd_hw_suspend(struct crystalhd_hw *hw) -{ - enum BC_STATUS sts; - - if (!hw) { - BCMLOG_ERR("Invalid Arguments\n"); - return BC_STS_INV_ARG; - } - - sts = crystalhd_put_ddr2sleep(hw); - if (sts != BC_STS_SUCCESS) { - BCMLOG_ERR("Failed to Put DDR To Sleep!!\n"); - return BC_STS_ERROR; - } - - if (!crystalhd_stop_device(hw->adp)) { - BCMLOG_ERR("Failed to Stop Device!!\n"); - return BC_STS_ERROR; - } - - return BC_STS_SUCCESS; -} - -void crystalhd_hw_stats(struct crystalhd_hw *hw, - struct crystalhd_hw_stats *stats) -{ - if (!hw) { - BCMLOG_ERR("Invalid Arguments\n"); - return; - } - - /* if called w/NULL stats, its a req to zero out the stats */ - if (!stats) { - memset(&hw->stats, 0, sizeof(hw->stats)); - return; - } - - hw->stats.freeq_count = crystalhd_dioq_count(hw->rx_freeq); - hw->stats.rdyq_count = crystalhd_dioq_count(hw->rx_rdyq); - memcpy(stats, &hw->stats, sizeof(*stats)); -} - -enum BC_STATUS crystalhd_hw_set_core_clock(struct crystalhd_hw *hw) -{ - uint32_t reg, n, i; - uint32_t vco_mg, refresh_reg; - - if (!hw) { - BCMLOG_ERR("Invalid Arguments\n"); - return BC_STS_INV_ARG; - } - - /* FIXME: jarod: wha? */ - /*n = (hw->core_clock_mhz * 3) / 20 + 1; */ - n = hw->core_clock_mhz/5; - - if (n == hw->prev_n) - return BC_STS_CLK_NOCHG; - - if (hw->pwr_lock > 0) { - /* BCMLOG(BCMLOG_INFO,"pwr_lock is %u\n", hw->pwr_lock) */ - return BC_STS_CLK_NOCHG; - } - - i = n * 27; - if (i < 560) - vco_mg = 0; - else if (i < 900) - vco_mg = 1; - else if (i < 1030) - vco_mg = 2; - else - vco_mg = 3; - - reg = bc_dec_reg_rd(hw->adp, DecHt_PllACtl); - - reg &= 0xFFFFCFC0; - reg |= n; - reg |= vco_mg << 12; - - BCMLOG(BCMLOG_INFO, "clock is moving to %d with n %d with vco_mg %d\n", - hw->core_clock_mhz, n, vco_mg); - - /* Change the DRAM refresh rate to accommodate the new frequency */ - /* refresh reg = ((refresh_rate * clock_rate)/16) - 1; rounding up*/ - refresh_reg = (7 * hw->core_clock_mhz / 16); - bc_dec_reg_wr(hw->adp, SDRAM_REF_PARAM, ((1 << 12) | refresh_reg)); - - bc_dec_reg_wr(hw->adp, DecHt_PllACtl, reg); - - i = 0; - - for (i = 0; i < 10; i++) { - reg = bc_dec_reg_rd(hw->adp, DecHt_PllACtl); - - if (reg & 0x00020000) { - hw->prev_n = n; - /* FIXME: jarod: outputting - a random "C" is... confusing... */ - BCMLOG(BCMLOG_INFO, "C"); - return BC_STS_SUCCESS; - } else { - msleep_interruptible(10); - } - } - BCMLOG(BCMLOG_INFO, "clk change failed\n"); - return BC_STS_CLK_NOCHG; -} |