1 /***************************************************************************
2 * Copyright (c) 2005-2009, Broadcom Corporation.
4 * Name: crystalhd_hw . c
7 * BCM70010 Linux driver HW layer.
9 **********************************************************************
10 * This file is part of the crystalhd device driver.
12 * This driver is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation, version 2 of the License.
16 * This driver is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this driver. If not, see <http://www.gnu.org/licenses/>.
23 **********************************************************************/
25 #include <linux/pci.h>
26 #include <linux/slab.h>
27 #include <linux/delay.h>
28 #include "crystalhd_hw.h"
30 /* Functions internal to this file */
32 static void crystalhd_enable_uarts(struct crystalhd_adp
*adp
)
34 bc_dec_reg_wr(adp
, UartSelectA
, BSVS_UART_STREAM
);
35 bc_dec_reg_wr(adp
, UartSelectB
, BSVS_UART_DEC_OUTER
);
39 static void crystalhd_start_dram(struct crystalhd_adp
*adp
)
41 bc_dec_reg_wr(adp
, SDRAM_PARAM
, ((40 / 5 - 1) << 0) |
42 /* tras (40ns tras)/(5ns period) -1 ((15/5 - 1) << 4) | // trcd */
43 ((15 / 5 - 1) << 7) | /* trp */
44 ((10 / 5 - 1) << 10) | /* trrd */
45 ((15 / 5 + 1) << 12) | /* twr */
46 ((2 + 1) << 16) | /* twtr */
47 ((70 / 5 - 2) << 19) | /* trfc */
50 bc_dec_reg_wr(adp
, SDRAM_PRECHARGE
, 0);
51 bc_dec_reg_wr(adp
, SDRAM_EXT_MODE
, 2);
52 bc_dec_reg_wr(adp
, SDRAM_MODE
, 0x132);
53 bc_dec_reg_wr(adp
, SDRAM_PRECHARGE
, 0);
54 bc_dec_reg_wr(adp
, SDRAM_REFRESH
, 0);
55 bc_dec_reg_wr(adp
, SDRAM_REFRESH
, 0);
56 bc_dec_reg_wr(adp
, SDRAM_MODE
, 0x32);
57 /* setting the refresh rate here */
58 bc_dec_reg_wr(adp
, SDRAM_REF_PARAM
, ((1 << 12) | 96));
62 static bool crystalhd_bring_out_of_rst(struct crystalhd_adp
*adp
)
64 union link_misc_perst_deco_ctrl rst_deco_cntrl
;
65 union link_misc_perst_clk_ctrl rst_clk_cntrl
;
69 * Link clocks: MISC_PERST_CLOCK_CTRL Clear PLL power down bit,
70 * delay to allow PLL to lock Clear alternate clock, stop clock bits
72 rst_clk_cntrl
.whole_reg
= crystalhd_reg_rd(adp
, MISC_PERST_CLOCK_CTRL
);
73 rst_clk_cntrl
.pll_pwr_dn
= 0;
74 crystalhd_reg_wr(adp
, MISC_PERST_CLOCK_CTRL
, rst_clk_cntrl
.whole_reg
);
75 msleep_interruptible(50);
77 rst_clk_cntrl
.whole_reg
= crystalhd_reg_rd(adp
, MISC_PERST_CLOCK_CTRL
);
78 rst_clk_cntrl
.stop_core_clk
= 0;
79 rst_clk_cntrl
.sel_alt_clk
= 0;
81 crystalhd_reg_wr(adp
, MISC_PERST_CLOCK_CTRL
, rst_clk_cntrl
.whole_reg
);
82 msleep_interruptible(50);
85 * Bus Arbiter Timeout: GISB_ARBITER_TIMER
86 * Set internal bus arbiter timeout to 40us based on core clock speed
87 * (63MHz * 40us = 0x9D8)
89 crystalhd_reg_wr(adp
, GISB_ARBITER_TIMER
, 0x9D8);
92 * Decoder clocks: MISC_PERST_DECODER_CTRL
93 * Enable clocks while 7412 reset is asserted, delay
94 * De-assert 7412 reset
96 rst_deco_cntrl
.whole_reg
= crystalhd_reg_rd(adp
, MISC_PERST_DECODER_CTRL
);
97 rst_deco_cntrl
.stop_bcm_7412_clk
= 0;
98 rst_deco_cntrl
.bcm7412_rst
= 1;
99 crystalhd_reg_wr(adp
, MISC_PERST_DECODER_CTRL
, rst_deco_cntrl
.whole_reg
);
100 msleep_interruptible(10);
102 rst_deco_cntrl
.whole_reg
= crystalhd_reg_rd(adp
, MISC_PERST_DECODER_CTRL
);
103 rst_deco_cntrl
.bcm7412_rst
= 0;
104 crystalhd_reg_wr(adp
, MISC_PERST_DECODER_CTRL
, rst_deco_cntrl
.whole_reg
);
105 msleep_interruptible(50);
107 /* Disable OTP_CONTENT_MISC to 0 to disable all secure modes */
108 crystalhd_reg_wr(adp
, OTP_CONTENT_MISC
, 0);
110 /* Clear bit 29 of 0x404 */
111 temp
= crystalhd_reg_rd(adp
, PCIE_TL_TRANSACTION_CONFIGURATION
);
113 crystalhd_reg_wr(adp
, PCIE_TL_TRANSACTION_CONFIGURATION
, temp
);
115 /* 2.5V regulator must be set to 2.6 volts (+6%) */
116 /* FIXME: jarod: what's the point of this reg read? */
117 temp
= crystalhd_reg_rd(adp
, MISC_PERST_VREG_CTRL
);
118 crystalhd_reg_wr(adp
, MISC_PERST_VREG_CTRL
, 0xF3);
123 static bool crystalhd_put_in_reset(struct crystalhd_adp
*adp
)
125 union link_misc_perst_deco_ctrl rst_deco_cntrl
;
126 union link_misc_perst_clk_ctrl rst_clk_cntrl
;
130 * Decoder clocks: MISC_PERST_DECODER_CTRL
131 * Assert 7412 reset, delay
132 * Assert 7412 stop clock
134 rst_deco_cntrl
.whole_reg
= crystalhd_reg_rd(adp
, MISC_PERST_DECODER_CTRL
);
135 rst_deco_cntrl
.stop_bcm_7412_clk
= 1;
136 crystalhd_reg_wr(adp
, MISC_PERST_DECODER_CTRL
, rst_deco_cntrl
.whole_reg
);
137 msleep_interruptible(50);
139 /* Bus Arbiter Timeout: GISB_ARBITER_TIMER
140 * Set internal bus arbiter timeout to 40us based on core clock speed
141 * (6.75MHZ * 40us = 0x10E)
143 crystalhd_reg_wr(adp
, GISB_ARBITER_TIMER
, 0x10E);
145 /* Link clocks: MISC_PERST_CLOCK_CTRL
146 * Stop core clk, delay
147 * Set alternate clk, delay, set PLL power down
149 rst_clk_cntrl
.whole_reg
= crystalhd_reg_rd(adp
, MISC_PERST_CLOCK_CTRL
);
150 rst_clk_cntrl
.stop_core_clk
= 1;
151 rst_clk_cntrl
.sel_alt_clk
= 1;
152 crystalhd_reg_wr(adp
, MISC_PERST_CLOCK_CTRL
, rst_clk_cntrl
.whole_reg
);
153 msleep_interruptible(50);
155 rst_clk_cntrl
.whole_reg
= crystalhd_reg_rd(adp
, MISC_PERST_CLOCK_CTRL
);
156 rst_clk_cntrl
.pll_pwr_dn
= 1;
157 crystalhd_reg_wr(adp
, MISC_PERST_CLOCK_CTRL
, rst_clk_cntrl
.whole_reg
);
160 * Read and restore the Transaction Configuration Register
163 temp
= crystalhd_reg_rd(adp
, PCIE_TL_TRANSACTION_CONFIGURATION
);
166 * Link core soft reset: MISC3_RESET_CTRL
167 * - Write BIT[0]=1 and read it back for core reset to take place
169 crystalhd_reg_wr(adp
, MISC3_RESET_CTRL
, 1);
170 rst_deco_cntrl
.whole_reg
= crystalhd_reg_rd(adp
, MISC3_RESET_CTRL
);
171 msleep_interruptible(50);
173 /* restore the transaction configuration register */
174 crystalhd_reg_wr(adp
, PCIE_TL_TRANSACTION_CONFIGURATION
, temp
);
179 static void crystalhd_disable_interrupts(struct crystalhd_adp
*adp
)
181 union intr_mask_reg intr_mask
;
182 intr_mask
.whole_reg
= crystalhd_reg_rd(adp
, INTR_INTR_MSK_STS_REG
);
183 intr_mask
.mask_pcie_err
= 1;
184 intr_mask
.mask_pcie_rbusmast_err
= 1;
185 intr_mask
.mask_pcie_rgr_bridge
= 1;
186 intr_mask
.mask_rx_done
= 1;
187 intr_mask
.mask_rx_err
= 1;
188 intr_mask
.mask_tx_done
= 1;
189 intr_mask
.mask_tx_err
= 1;
190 crystalhd_reg_wr(adp
, INTR_INTR_MSK_SET_REG
, intr_mask
.whole_reg
);
195 static void crystalhd_enable_interrupts(struct crystalhd_adp
*adp
)
197 union intr_mask_reg intr_mask
;
198 intr_mask
.whole_reg
= crystalhd_reg_rd(adp
, INTR_INTR_MSK_STS_REG
);
199 intr_mask
.mask_pcie_err
= 1;
200 intr_mask
.mask_pcie_rbusmast_err
= 1;
201 intr_mask
.mask_pcie_rgr_bridge
= 1;
202 intr_mask
.mask_rx_done
= 1;
203 intr_mask
.mask_rx_err
= 1;
204 intr_mask
.mask_tx_done
= 1;
205 intr_mask
.mask_tx_err
= 1;
206 crystalhd_reg_wr(adp
, INTR_INTR_MSK_CLR_REG
, intr_mask
.whole_reg
);
211 static void crystalhd_clear_errors(struct crystalhd_adp
*adp
)
215 /* FIXME: jarod: wouldn't we want to write a 0 to the reg? Or does the write clear the bits specified? */
216 reg
= crystalhd_reg_rd(adp
, MISC1_Y_RX_ERROR_STATUS
);
218 crystalhd_reg_wr(adp
, MISC1_Y_RX_ERROR_STATUS
, reg
);
220 reg
= crystalhd_reg_rd(adp
, MISC1_UV_RX_ERROR_STATUS
);
222 crystalhd_reg_wr(adp
, MISC1_UV_RX_ERROR_STATUS
, reg
);
224 reg
= crystalhd_reg_rd(adp
, MISC1_TX_DMA_ERROR_STATUS
);
226 crystalhd_reg_wr(adp
, MISC1_TX_DMA_ERROR_STATUS
, reg
);
229 static void crystalhd_clear_interrupts(struct crystalhd_adp
*adp
)
231 uint32_t intr_sts
= crystalhd_reg_rd(adp
, INTR_INTR_STATUS
);
234 crystalhd_reg_wr(adp
, INTR_INTR_CLR_REG
, intr_sts
);
236 /* Write End Of Interrupt for PCIE */
237 crystalhd_reg_wr(adp
, INTR_EOI_CTRL
, 1);
241 static void crystalhd_soft_rst(struct crystalhd_adp
*adp
)
245 /* Assert c011 soft reset*/
246 bc_dec_reg_wr(adp
, DecHt_HostSwReset
, 0x00000001);
247 msleep_interruptible(50);
249 /* Release c011 soft reset*/
250 bc_dec_reg_wr(adp
, DecHt_HostSwReset
, 0x00000000);
252 /* Disable Stuffing..*/
253 val
= crystalhd_reg_rd(adp
, MISC2_GLOBAL_CTRL
);
255 crystalhd_reg_wr(adp
, MISC2_GLOBAL_CTRL
, val
);
258 static bool crystalhd_load_firmware_config(struct crystalhd_adp
*adp
)
262 crystalhd_reg_wr(adp
, DCI_DRAM_BASE_ADDR
, (BC_DRAM_FW_CFG_ADDR
>> 19));
264 crystalhd_reg_wr(adp
, AES_CMD
, 0);
265 crystalhd_reg_wr(adp
, AES_CONFIG_INFO
, (BC_DRAM_FW_CFG_ADDR
& 0x7FFFF));
266 crystalhd_reg_wr(adp
, AES_CMD
, 0x1);
268 /* FIXME: jarod: I've seen this fail, and introducing extra delays helps... */
269 for (i
= 0; i
< 100; ++i
) {
270 reg
= crystalhd_reg_rd(adp
, AES_STATUS
);
273 msleep_interruptible(10);
280 static bool crystalhd_start_device(struct crystalhd_adp
*adp
)
282 uint32_t dbg_options
, glb_cntrl
= 0, reg_pwrmgmt
= 0;
284 BCMLOG(BCMLOG_INFO
, "Starting BCM70012 Device\n");
286 reg_pwrmgmt
= crystalhd_reg_rd(adp
, PCIE_DLL_DATA_LINK_CONTROL
);
287 reg_pwrmgmt
&= ~ASPM_L1_ENABLE
;
289 crystalhd_reg_wr(adp
, PCIE_DLL_DATA_LINK_CONTROL
, reg_pwrmgmt
);
291 if (!crystalhd_bring_out_of_rst(adp
)) {
292 BCMLOG_ERR("Failed To Bring Link Out Of Reset\n");
296 crystalhd_disable_interrupts(adp
);
298 crystalhd_clear_errors(adp
);
300 crystalhd_clear_interrupts(adp
);
302 crystalhd_enable_interrupts(adp
);
304 /* Enable the option for getting the total no. of DWORDS
305 * that have been transferred by the RXDMA engine
307 dbg_options
= crystalhd_reg_rd(adp
, MISC1_DMA_DEBUG_OPTIONS_REG
);
309 crystalhd_reg_wr(adp
, MISC1_DMA_DEBUG_OPTIONS_REG
, dbg_options
);
311 /* Enable PCI Global Control options */
312 glb_cntrl
= crystalhd_reg_rd(adp
, MISC2_GLOBAL_CTRL
);
315 crystalhd_reg_wr(adp
, MISC2_GLOBAL_CTRL
, glb_cntrl
);
317 crystalhd_enable_interrupts(adp
);
319 crystalhd_soft_rst(adp
);
320 crystalhd_start_dram(adp
);
321 crystalhd_enable_uarts(adp
);
326 static bool crystalhd_stop_device(struct crystalhd_adp
*adp
)
330 BCMLOG(BCMLOG_INFO
, "Stopping BCM70012 Device\n");
331 /* Clear and disable interrupts */
332 crystalhd_disable_interrupts(adp
);
333 crystalhd_clear_errors(adp
);
334 crystalhd_clear_interrupts(adp
);
336 if (!crystalhd_put_in_reset(adp
))
337 BCMLOG_ERR("Failed to Put Link To Reset State\n");
339 reg
= crystalhd_reg_rd(adp
, PCIE_DLL_DATA_LINK_CONTROL
);
340 reg
|= ASPM_L1_ENABLE
;
341 crystalhd_reg_wr(adp
, PCIE_DLL_DATA_LINK_CONTROL
, reg
);
343 /* Set PCI Clk Req */
344 reg
= crystalhd_reg_rd(adp
, PCIE_CLK_REQ_REG
);
345 reg
|= PCI_CLK_REQ_ENABLE
;
346 crystalhd_reg_wr(adp
, PCIE_CLK_REQ_REG
, reg
);
351 static struct crystalhd_rx_dma_pkt
*crystalhd_hw_alloc_rx_pkt(struct crystalhd_hw
*hw
)
353 unsigned long flags
= 0;
354 struct crystalhd_rx_dma_pkt
*temp
= NULL
;
359 spin_lock_irqsave(&hw
->lock
, flags
);
360 temp
= hw
->rx_pkt_pool_head
;
362 hw
->rx_pkt_pool_head
= hw
->rx_pkt_pool_head
->next
;
363 temp
->dio_req
= NULL
;
367 spin_unlock_irqrestore(&hw
->lock
, flags
);
372 static void crystalhd_hw_free_rx_pkt(struct crystalhd_hw
*hw
,
373 struct crystalhd_rx_dma_pkt
*pkt
)
375 unsigned long flags
= 0;
380 spin_lock_irqsave(&hw
->lock
, flags
);
381 pkt
->next
= hw
->rx_pkt_pool_head
;
382 hw
->rx_pkt_pool_head
= pkt
;
383 spin_unlock_irqrestore(&hw
->lock
, flags
);
387 * Call back from TX - IOQ deletion.
389 * This routine will release the TX DMA rings allocated
390 * druing setup_dma rings interface.
392 * Memory is allocated per DMA ring basis. This is just
393 * a place holder to be able to create the dio queues.
395 static void crystalhd_tx_desc_rel_call_back(void *context
, void *data
)
400 * Rx Packet release callback..
402 * Release All user mapped capture buffers and Our DMA packets
403 * back to our free pool. The actual cleanup of the DMA
404 * ring descriptors happen during dma ring release.
406 static void crystalhd_rx_pkt_rel_call_back(void *context
, void *data
)
408 struct crystalhd_hw
*hw
= (struct crystalhd_hw
*)context
;
409 struct crystalhd_rx_dma_pkt
*pkt
= (struct crystalhd_rx_dma_pkt
*)data
;
412 BCMLOG_ERR("Invalid arg - %p %p\n", hw
, pkt
);
417 crystalhd_unmap_dio(hw
->adp
, pkt
->dio_req
);
419 BCMLOG_ERR("Missing dio_req: 0x%x\n", pkt
->pkt_tag
);
421 crystalhd_hw_free_rx_pkt(hw
, pkt
);
424 #define crystalhd_hw_delete_ioq(adp, q) \
426 crystalhd_delete_dioq(adp, q); \
430 static void crystalhd_hw_delete_ioqs(struct crystalhd_hw
*hw
)
435 BCMLOG(BCMLOG_DBG
, "Deleting IOQs\n");
436 crystalhd_hw_delete_ioq(hw
->adp
, hw
->tx_actq
);
437 crystalhd_hw_delete_ioq(hw
->adp
, hw
->tx_freeq
);
438 crystalhd_hw_delete_ioq(hw
->adp
, hw
->rx_actq
);
439 crystalhd_hw_delete_ioq(hw
->adp
, hw
->rx_freeq
);
440 crystalhd_hw_delete_ioq(hw
->adp
, hw
->rx_rdyq
);
443 #define crystalhd_hw_create_ioq(sts, hw, q, cb) \
445 sts = crystalhd_create_dioq(hw->adp, &q, cb, hw); \
446 if (sts != BC_STS_SUCCESS) \
447 goto hw_create_ioq_err; \
454 * RX - Active, Ready and Free.
456 static enum BC_STATUS
crystalhd_hw_create_ioqs(struct crystalhd_hw
*hw
)
458 enum BC_STATUS sts
= BC_STS_SUCCESS
;
461 BCMLOG_ERR("Invalid Arg!!\n");
462 return BC_STS_INV_ARG
;
465 crystalhd_hw_create_ioq(sts
, hw
, hw
->tx_freeq
,
466 crystalhd_tx_desc_rel_call_back
);
467 crystalhd_hw_create_ioq(sts
, hw
, hw
->tx_actq
,
468 crystalhd_tx_desc_rel_call_back
);
470 crystalhd_hw_create_ioq(sts
, hw
, hw
->rx_freeq
,
471 crystalhd_rx_pkt_rel_call_back
);
472 crystalhd_hw_create_ioq(sts
, hw
, hw
->rx_rdyq
,
473 crystalhd_rx_pkt_rel_call_back
);
474 crystalhd_hw_create_ioq(sts
, hw
, hw
->rx_actq
,
475 crystalhd_rx_pkt_rel_call_back
);
480 crystalhd_hw_delete_ioqs(hw
);
486 static bool crystalhd_code_in_full(struct crystalhd_adp
*adp
, uint32_t needed_sz
,
487 bool b_188_byte_pkts
, uint8_t flags
)
489 uint32_t base
, end
, writep
, readp
;
490 uint32_t cpbSize
, cpbFullness
, fifoSize
;
492 if (flags
& 0x02) { /* ASF Bit is set */
493 base
= bc_dec_reg_rd(adp
, REG_Dec_TsAudCDB2Base
);
494 end
= bc_dec_reg_rd(adp
, REG_Dec_TsAudCDB2End
);
495 writep
= bc_dec_reg_rd(adp
, REG_Dec_TsAudCDB2Wrptr
);
496 readp
= bc_dec_reg_rd(adp
, REG_Dec_TsAudCDB2Rdptr
);
497 } else if (b_188_byte_pkts
) { /*Encrypted 188 byte packets*/
498 base
= bc_dec_reg_rd(adp
, REG_Dec_TsUser0Base
);
499 end
= bc_dec_reg_rd(adp
, REG_Dec_TsUser0End
);
500 writep
= bc_dec_reg_rd(adp
, REG_Dec_TsUser0Wrptr
);
501 readp
= bc_dec_reg_rd(adp
, REG_Dec_TsUser0Rdptr
);
503 base
= bc_dec_reg_rd(adp
, REG_DecCA_RegCinBase
);
504 end
= bc_dec_reg_rd(adp
, REG_DecCA_RegCinEnd
);
505 writep
= bc_dec_reg_rd(adp
, REG_DecCA_RegCinWrPtr
);
506 readp
= bc_dec_reg_rd(adp
, REG_DecCA_RegCinRdPtr
);
509 cpbSize
= end
- base
;
511 cpbFullness
= writep
- readp
;
513 cpbFullness
= (end
- base
) - (readp
- writep
);
515 fifoSize
= cpbSize
- cpbFullness
;
517 if (fifoSize
< BC_INFIFO_THRESHOLD
)
520 if (needed_sz
> (fifoSize
- BC_INFIFO_THRESHOLD
))
526 static enum BC_STATUS
crystalhd_hw_tx_req_complete(struct crystalhd_hw
*hw
,
527 uint32_t list_id
, enum BC_STATUS cs
)
529 struct tx_dma_pkt
*tx_req
;
531 if (!hw
|| !list_id
) {
532 BCMLOG_ERR("Invalid Arg..\n");
533 return BC_STS_INV_ARG
;
538 tx_req
= (struct tx_dma_pkt
*)crystalhd_dioq_find_and_fetch(hw
->tx_actq
, list_id
);
540 if (cs
!= BC_STS_IO_USER_ABORT
)
541 BCMLOG_ERR("Find and Fetch Did not find req\n");
542 return BC_STS_NO_DATA
;
545 if (tx_req
->call_back
) {
546 tx_req
->call_back(tx_req
->dio_req
, tx_req
->cb_event
, cs
);
547 tx_req
->dio_req
= NULL
;
548 tx_req
->cb_event
= NULL
;
549 tx_req
->call_back
= NULL
;
551 BCMLOG(BCMLOG_DBG
, "Missing Tx Callback - %X\n",
555 /* Now put back the tx_list back in FreeQ */
556 tx_req
->list_tag
= 0;
558 return crystalhd_dioq_add(hw
->tx_freeq
, tx_req
, false, 0);
561 static bool crystalhd_tx_list0_handler(struct crystalhd_hw
*hw
, uint32_t err_sts
)
563 uint32_t err_mask
, tmp
;
564 unsigned long flags
= 0;
566 err_mask
= MISC1_TX_DMA_ERROR_STATUS_TX_L0_DESC_TX_ABORT_ERRORS_MASK
|
567 MISC1_TX_DMA_ERROR_STATUS_TX_L0_DMA_DATA_TX_ABORT_ERRORS_MASK
|
568 MISC1_TX_DMA_ERROR_STATUS_TX_L0_FIFO_FULL_ERRORS_MASK
;
570 if (!(err_sts
& err_mask
))
573 BCMLOG_ERR("Error on Tx-L0 %x\n", err_sts
);
577 if (err_sts
& MISC1_TX_DMA_ERROR_STATUS_TX_L0_FIFO_FULL_ERRORS_MASK
)
578 tmp
&= ~MISC1_TX_DMA_ERROR_STATUS_TX_L0_FIFO_FULL_ERRORS_MASK
;
581 spin_lock_irqsave(&hw
->lock
, flags
);
582 /* reset list index.*/
583 hw
->tx_list_post_index
= 0;
584 spin_unlock_irqrestore(&hw
->lock
, flags
);
587 tmp
= err_sts
& err_mask
;
588 crystalhd_reg_wr(hw
->adp
, MISC1_TX_DMA_ERROR_STATUS
, tmp
);
593 static bool crystalhd_tx_list1_handler(struct crystalhd_hw
*hw
, uint32_t err_sts
)
595 uint32_t err_mask
, tmp
;
596 unsigned long flags
= 0;
598 err_mask
= MISC1_TX_DMA_ERROR_STATUS_TX_L1_DESC_TX_ABORT_ERRORS_MASK
|
599 MISC1_TX_DMA_ERROR_STATUS_TX_L1_DMA_DATA_TX_ABORT_ERRORS_MASK
|
600 MISC1_TX_DMA_ERROR_STATUS_TX_L1_FIFO_FULL_ERRORS_MASK
;
602 if (!(err_sts
& err_mask
))
605 BCMLOG_ERR("Error on Tx-L1 %x\n", err_sts
);
609 if (err_sts
& MISC1_TX_DMA_ERROR_STATUS_TX_L1_FIFO_FULL_ERRORS_MASK
)
610 tmp
&= ~MISC1_TX_DMA_ERROR_STATUS_TX_L1_FIFO_FULL_ERRORS_MASK
;
613 spin_lock_irqsave(&hw
->lock
, flags
);
614 /* reset list index.*/
615 hw
->tx_list_post_index
= 0;
616 spin_unlock_irqrestore(&hw
->lock
, flags
);
619 tmp
= err_sts
& err_mask
;
620 crystalhd_reg_wr(hw
->adp
, MISC1_TX_DMA_ERROR_STATUS
, tmp
);
625 static void crystalhd_tx_isr(struct crystalhd_hw
*hw
, uint32_t int_sts
)
629 if (int_sts
& INTR_INTR_STATUS_L0_TX_DMA_DONE_INTR_MASK
)
630 crystalhd_hw_tx_req_complete(hw
, hw
->tx_ioq_tag_seed
+ 0,
633 if (int_sts
& INTR_INTR_STATUS_L1_TX_DMA_DONE_INTR_MASK
)
634 crystalhd_hw_tx_req_complete(hw
, hw
->tx_ioq_tag_seed
+ 1,
637 if (!(int_sts
& (INTR_INTR_STATUS_L0_TX_DMA_ERR_INTR_MASK
|
638 INTR_INTR_STATUS_L1_TX_DMA_ERR_INTR_MASK
))) {
639 /* No error mask set.. */
643 /* Handle Tx errors. */
644 err_sts
= crystalhd_reg_rd(hw
->adp
, MISC1_TX_DMA_ERROR_STATUS
);
646 if (crystalhd_tx_list0_handler(hw
, err_sts
))
647 crystalhd_hw_tx_req_complete(hw
, hw
->tx_ioq_tag_seed
+ 0,
650 if (crystalhd_tx_list1_handler(hw
, err_sts
))
651 crystalhd_hw_tx_req_complete(hw
, hw
->tx_ioq_tag_seed
+ 1,
654 hw
->stats
.tx_errors
++;
657 static void crystalhd_hw_dump_desc(struct dma_descriptor
*p_dma_desc
,
658 uint32_t ul_desc_index
, uint32_t cnt
)
662 if (!p_dma_desc
|| !cnt
)
665 /* FIXME: jarod: perhaps a modparam desc_debug to enable this, rather than
666 * setting ll (log level, I presume) to non-zero? */
670 for (ix
= ul_desc_index
; ix
< (ul_desc_index
+ cnt
); ix
++) {
671 BCMLOG(ll
, "%s[%d] Buff[%x:%x] Next:[%x:%x] XferSz:%x Intr:%x,Last:%x\n",
672 ((p_dma_desc
[ul_desc_index
].dma_dir
) ? "TDesc" : "RDesc"),
674 p_dma_desc
[ul_desc_index
].buff_addr_high
,
675 p_dma_desc
[ul_desc_index
].buff_addr_low
,
676 p_dma_desc
[ul_desc_index
].next_desc_addr_high
,
677 p_dma_desc
[ul_desc_index
].next_desc_addr_low
,
678 p_dma_desc
[ul_desc_index
].xfer_size
,
679 p_dma_desc
[ul_desc_index
].intr_enable
,
680 p_dma_desc
[ul_desc_index
].last_rec_indicator
);
685 static enum BC_STATUS
crystalhd_hw_fill_desc(struct crystalhd_dio_req
*ioreq
,
686 struct dma_descriptor
*desc
,
687 dma_addr_t desc_paddr_base
,
688 uint32_t sg_cnt
, uint32_t sg_st_ix
,
689 uint32_t sg_st_off
, uint32_t xfr_sz
)
691 uint32_t count
= 0, ix
= 0, sg_ix
= 0, len
= 0, last_desc_ix
= 0;
692 dma_addr_t desc_phy_addr
= desc_paddr_base
;
693 union addr_64 addr_temp
;
695 if (!ioreq
|| !desc
|| !desc_paddr_base
|| !xfr_sz
||
696 (!sg_cnt
&& !ioreq
->uinfo
.dir_tx
)) {
697 BCMLOG_ERR("Invalid Args\n");
698 return BC_STS_INV_ARG
;
701 for (ix
= 0; ix
< sg_cnt
; ix
++) {
703 /* Setup SGLE index. */
704 sg_ix
= ix
+ sg_st_ix
;
706 /* Get SGLE length */
707 len
= crystalhd_get_sgle_len(ioreq
, sg_ix
);
709 BCMLOG_ERR(" len in sg %d %d %d\n", len
, sg_ix
, sg_cnt
);
710 return BC_STS_NOT_IMPL
;
712 /* Setup DMA desc with Phy addr & Length at current index. */
713 addr_temp
.full_addr
= crystalhd_get_sgle_paddr(ioreq
, sg_ix
);
714 if (sg_ix
== sg_st_ix
) {
715 addr_temp
.full_addr
+= sg_st_off
;
718 memset(&desc
[ix
], 0, sizeof(desc
[ix
]));
719 desc
[ix
].buff_addr_low
= addr_temp
.low_part
;
720 desc
[ix
].buff_addr_high
= addr_temp
.high_part
;
721 desc
[ix
].dma_dir
= ioreq
->uinfo
.dir_tx
;
723 /* Chain DMA descriptor. */
724 addr_temp
.full_addr
= desc_phy_addr
+ sizeof(struct dma_descriptor
);
725 desc
[ix
].next_desc_addr_low
= addr_temp
.low_part
;
726 desc
[ix
].next_desc_addr_high
= addr_temp
.high_part
;
728 if ((count
+ len
) > xfr_sz
)
729 len
= xfr_sz
- count
;
732 if ((!len
) || (len
> crystalhd_get_sgle_len(ioreq
, sg_ix
))) {
733 BCMLOG_ERR("inv-len(%x) Ix(%d) count:%x xfr_sz:%x sg_cnt:%d\n",
734 len
, ix
, count
, xfr_sz
, sg_cnt
);
737 /* Length expects Multiple of 4 */
738 desc
[ix
].xfer_size
= (len
/ 4);
740 crystalhd_hw_dump_desc(desc
, ix
, 1);
743 desc_phy_addr
+= sizeof(struct dma_descriptor
);
746 last_desc_ix
= ix
- 1;
748 if (ioreq
->fb_size
) {
749 memset(&desc
[ix
], 0, sizeof(desc
[ix
]));
750 addr_temp
.full_addr
= ioreq
->fb_pa
;
751 desc
[ix
].buff_addr_low
= addr_temp
.low_part
;
752 desc
[ix
].buff_addr_high
= addr_temp
.high_part
;
753 desc
[ix
].dma_dir
= ioreq
->uinfo
.dir_tx
;
754 desc
[ix
].xfer_size
= 1;
755 desc
[ix
].fill_bytes
= 4 - ioreq
->fb_size
;
756 count
+= ioreq
->fb_size
;
760 /* setup last descriptor..*/
761 desc
[last_desc_ix
].last_rec_indicator
= 1;
762 desc
[last_desc_ix
].next_desc_addr_low
= 0;
763 desc
[last_desc_ix
].next_desc_addr_high
= 0;
764 desc
[last_desc_ix
].intr_enable
= 1;
766 crystalhd_hw_dump_desc(desc
, last_desc_ix
, 1);
768 if (count
!= xfr_sz
) {
769 BCMLOG_ERR("interal error sz curr:%x exp:%x\n", count
, xfr_sz
);
773 return BC_STS_SUCCESS
;
776 static enum BC_STATUS
crystalhd_xlat_sgl_to_dma_desc(struct crystalhd_dio_req
*ioreq
,
777 struct dma_desc_mem
*pdesc_mem
,
778 uint32_t *uv_desc_index
)
780 struct dma_descriptor
*desc
= NULL
;
781 dma_addr_t desc_paddr_base
= 0;
782 uint32_t sg_cnt
= 0, sg_st_ix
= 0, sg_st_off
= 0;
784 enum BC_STATUS sts
= BC_STS_SUCCESS
;
787 if (!ioreq
|| !pdesc_mem
|| !uv_desc_index
) {
788 BCMLOG_ERR("Invalid Args\n");
789 return BC_STS_INV_ARG
;
792 if (!pdesc_mem
->sz
|| !pdesc_mem
->pdma_desc_start
||
793 !ioreq
->sg
|| (!ioreq
->sg_cnt
&& !ioreq
->uinfo
.dir_tx
)) {
794 BCMLOG_ERR("Invalid Args\n");
795 return BC_STS_INV_ARG
;
798 if ((ioreq
->uinfo
.dir_tx
) && (ioreq
->uinfo
.uv_offset
)) {
799 BCMLOG_ERR("UV offset for TX??\n");
800 return BC_STS_INV_ARG
;
804 desc
= pdesc_mem
->pdma_desc_start
;
805 desc_paddr_base
= pdesc_mem
->phy_addr
;
807 if (ioreq
->uinfo
.dir_tx
|| (ioreq
->uinfo
.uv_offset
== 0)) {
808 sg_cnt
= ioreq
->sg_cnt
;
809 xfr_sz
= ioreq
->uinfo
.xfr_len
;
811 sg_cnt
= ioreq
->uinfo
.uv_sg_ix
+ 1;
812 xfr_sz
= ioreq
->uinfo
.uv_offset
;
815 sts
= crystalhd_hw_fill_desc(ioreq
, desc
, desc_paddr_base
, sg_cnt
,
816 sg_st_ix
, sg_st_off
, xfr_sz
);
818 if ((sts
!= BC_STS_SUCCESS
) || !ioreq
->uinfo
.uv_offset
)
821 /* Prepare for UV mapping.. */
822 desc
= &pdesc_mem
->pdma_desc_start
[sg_cnt
];
823 desc_paddr_base
= pdesc_mem
->phy_addr
+
824 (sg_cnt
* sizeof(struct dma_descriptor
));
826 /* Done with desc addr.. now update sg stuff.*/
827 sg_cnt
= ioreq
->sg_cnt
- ioreq
->uinfo
.uv_sg_ix
;
828 xfr_sz
= ioreq
->uinfo
.xfr_len
- ioreq
->uinfo
.uv_offset
;
829 sg_st_ix
= ioreq
->uinfo
.uv_sg_ix
;
830 sg_st_off
= ioreq
->uinfo
.uv_sg_off
;
832 sts
= crystalhd_hw_fill_desc(ioreq
, desc
, desc_paddr_base
, sg_cnt
,
833 sg_st_ix
, sg_st_off
, xfr_sz
);
834 if (sts
!= BC_STS_SUCCESS
)
837 *uv_desc_index
= sg_st_ix
;
842 static void crystalhd_start_tx_dma_engine(struct crystalhd_hw
*hw
)
846 dma_cntrl
= crystalhd_reg_rd(hw
->adp
, MISC1_TX_SW_DESC_LIST_CTRL_STS
);
847 if (!(dma_cntrl
& DMA_START_BIT
)) {
848 dma_cntrl
|= DMA_START_BIT
;
849 crystalhd_reg_wr(hw
->adp
, MISC1_TX_SW_DESC_LIST_CTRL_STS
,
858 * Verify if the Stop generates a completion interrupt or not.
859 * if it does not generate an interrupt, then add polling here.
861 static enum BC_STATUS
crystalhd_stop_tx_dma_engine(struct crystalhd_hw
*hw
)
863 uint32_t dma_cntrl
, cnt
= 30;
864 uint32_t l1
= 1, l2
= 1;
865 unsigned long flags
= 0;
867 dma_cntrl
= crystalhd_reg_rd(hw
->adp
, MISC1_TX_SW_DESC_LIST_CTRL_STS
);
869 BCMLOG(BCMLOG_DBG
, "Stopping TX DMA Engine..\n");
871 /* FIXME: jarod: invert dma_ctrl and check bit? or are there missing parens? */
872 if (!dma_cntrl
& DMA_START_BIT
) {
873 BCMLOG(BCMLOG_DBG
, "Already Stopped\n");
874 return BC_STS_SUCCESS
;
877 crystalhd_disable_interrupts(hw
->adp
);
879 /* Issue stop to HW */
880 /* This bit when set gave problems. Please check*/
881 dma_cntrl
&= ~DMA_START_BIT
;
882 crystalhd_reg_wr(hw
->adp
, MISC1_TX_SW_DESC_LIST_CTRL_STS
, dma_cntrl
);
884 BCMLOG(BCMLOG_DBG
, "Cleared the DMA Start bit\n");
886 /* Poll for 3seconds (30 * 100ms) on both the lists..*/
887 while ((l1
|| l2
) && cnt
) {
890 l1
= crystalhd_reg_rd(hw
->adp
, MISC1_TX_FIRST_DESC_L_ADDR_LIST0
);
895 l2
= crystalhd_reg_rd(hw
->adp
, MISC1_TX_FIRST_DESC_L_ADDR_LIST1
);
899 msleep_interruptible(100);
905 BCMLOG_ERR("Failed to stop TX DMA.. l1 %d, l2 %d\n", l1
, l2
);
906 crystalhd_enable_interrupts(hw
->adp
);
910 spin_lock_irqsave(&hw
->lock
, flags
);
911 hw
->tx_list_post_index
= 0;
912 spin_unlock_irqrestore(&hw
->lock
, flags
);
913 BCMLOG(BCMLOG_DBG
, "stopped TX DMA..\n");
914 crystalhd_enable_interrupts(hw
->adp
);
916 return BC_STS_SUCCESS
;
919 static uint32_t crystalhd_get_pib_avail_cnt(struct crystalhd_hw
*hw
)
922 * Position of the PIB Entries can be found at
923 * 0th and the 1st location of the Circular list.
926 uint32_t pib_cnt
, r_offset
, w_offset
;
928 Q_addr
= hw
->pib_del_Q_addr
;
930 /* Get the Read Pointer */
931 crystalhd_mem_rd(hw
->adp
, Q_addr
, 1, &r_offset
);
933 /* Get the Write Pointer */
934 crystalhd_mem_rd(hw
->adp
, Q_addr
+ sizeof(uint32_t), 1, &w_offset
);
936 if (r_offset
== w_offset
)
937 return 0; /* Queue is empty */
939 if (w_offset
> r_offset
)
940 pib_cnt
= w_offset
- r_offset
;
942 pib_cnt
= (w_offset
+ MAX_PIB_Q_DEPTH
) -
943 (r_offset
+ MIN_PIB_Q_DEPTH
);
945 if (pib_cnt
> MAX_PIB_Q_DEPTH
) {
946 BCMLOG_ERR("Invalid PIB Count (%u)\n", pib_cnt
);
953 static uint32_t crystalhd_get_addr_from_pib_Q(struct crystalhd_hw
*hw
)
956 uint32_t addr_entry
, r_offset
, w_offset
;
958 Q_addr
= hw
->pib_del_Q_addr
;
960 /* Get the Read Pointer 0Th Location is Read Pointer */
961 crystalhd_mem_rd(hw
->adp
, Q_addr
, 1, &r_offset
);
963 /* Get the Write Pointer 1st Location is Write pointer */
964 crystalhd_mem_rd(hw
->adp
, Q_addr
+ sizeof(uint32_t), 1, &w_offset
);
967 if (r_offset
== w_offset
)
970 if ((r_offset
< MIN_PIB_Q_DEPTH
) || (r_offset
>= MAX_PIB_Q_DEPTH
))
973 /* Get the Actual Address of the PIB */
974 crystalhd_mem_rd(hw
->adp
, Q_addr
+ (r_offset
* sizeof(uint32_t)),
977 /* Increment the Read Pointer */
980 if (MAX_PIB_Q_DEPTH
== r_offset
)
981 r_offset
= MIN_PIB_Q_DEPTH
;
983 /* Write back the read pointer to It's Location */
984 crystalhd_mem_wr(hw
->adp
, Q_addr
, 1, &r_offset
);
989 static bool crystalhd_rel_addr_to_pib_Q(struct crystalhd_hw
*hw
, uint32_t addr_to_rel
)
992 uint32_t r_offset
, w_offset
, n_offset
;
994 Q_addr
= hw
->pib_rel_Q_addr
;
996 /* Get the Read Pointer */
997 crystalhd_mem_rd(hw
->adp
, Q_addr
, 1, &r_offset
);
999 /* Get the Write Pointer */
1000 crystalhd_mem_rd(hw
->adp
, Q_addr
+ sizeof(uint32_t), 1, &w_offset
);
1002 if ((r_offset
< MIN_PIB_Q_DEPTH
) ||
1003 (r_offset
>= MAX_PIB_Q_DEPTH
))
1006 n_offset
= w_offset
+ 1;
1008 if (MAX_PIB_Q_DEPTH
== n_offset
)
1009 n_offset
= MIN_PIB_Q_DEPTH
;
1011 if (r_offset
== n_offset
)
1012 return false; /* should never happen */
1014 /* Write the DRAM ADDR to the Queue at Next Offset */
1015 crystalhd_mem_wr(hw
->adp
, Q_addr
+ (w_offset
* sizeof(uint32_t)),
1018 /* Put the New value of the write pointer in Queue */
1019 crystalhd_mem_wr(hw
->adp
, Q_addr
+ sizeof(uint32_t), 1, &n_offset
);
1024 static void cpy_pib_to_app(struct c011_pib
*src_pib
, struct BC_PIC_INFO_BLOCK
*dst_pib
)
1026 if (!src_pib
|| !dst_pib
) {
1027 BCMLOG_ERR("Invalid Arguments\n");
1031 dst_pib
->timeStamp
= 0;
1032 dst_pib
->picture_number
= src_pib
->ppb
.picture_number
;
1033 dst_pib
->width
= src_pib
->ppb
.width
;
1034 dst_pib
->height
= src_pib
->ppb
.height
;
1035 dst_pib
->chroma_format
= src_pib
->ppb
.chroma_format
;
1036 dst_pib
->pulldown
= src_pib
->ppb
.pulldown
;
1037 dst_pib
->flags
= src_pib
->ppb
.flags
;
1038 dst_pib
->sess_num
= src_pib
->ptsStcOffset
;
1039 dst_pib
->aspect_ratio
= src_pib
->ppb
.aspect_ratio
;
1040 dst_pib
->colour_primaries
= src_pib
->ppb
.colour_primaries
;
1041 dst_pib
->picture_meta_payload
= src_pib
->ppb
.picture_meta_payload
;
1042 dst_pib
->frame_rate
= src_pib
->resolution
;
1046 static void crystalhd_hw_proc_pib(struct crystalhd_hw
*hw
)
1049 struct c011_pib src_pib
;
1050 uint32_t pib_addr
, pib_cnt
;
1051 struct BC_PIC_INFO_BLOCK
*AppPib
;
1052 struct crystalhd_rx_dma_pkt
*rx_pkt
= NULL
;
1054 pib_cnt
= crystalhd_get_pib_avail_cnt(hw
);
1059 for (cnt
= 0; cnt
< pib_cnt
; cnt
++) {
1061 pib_addr
= crystalhd_get_addr_from_pib_Q(hw
);
1062 crystalhd_mem_rd(hw
->adp
, pib_addr
, sizeof(struct c011_pib
) / 4,
1063 (uint32_t *)&src_pib
);
1065 if (src_pib
.bFormatChange
) {
1066 rx_pkt
= (struct crystalhd_rx_dma_pkt
*)crystalhd_dioq_fetch(hw
->rx_freeq
);
1070 rx_pkt
->flags
|= COMP_FLAG_PIB_VALID
| COMP_FLAG_FMT_CHANGE
;
1071 AppPib
= &rx_pkt
->pib
;
1072 cpy_pib_to_app(&src_pib
, AppPib
);
1075 "App PIB:%x %x %x %x %x %x %x %x %x %x\n",
1076 rx_pkt
->pib
.picture_number
,
1077 rx_pkt
->pib
.aspect_ratio
,
1078 rx_pkt
->pib
.chroma_format
,
1079 rx_pkt
->pib
.colour_primaries
,
1080 rx_pkt
->pib
.frame_rate
,
1084 rx_pkt
->pib
.pulldown
,
1087 crystalhd_dioq_add(hw
->rx_rdyq
, (void *)rx_pkt
, true, rx_pkt
->pkt_tag
);
1091 crystalhd_rel_addr_to_pib_Q(hw
, pib_addr
);
1095 static void crystalhd_start_rx_dma_engine(struct crystalhd_hw
*hw
)
1099 dma_cntrl
= crystalhd_reg_rd(hw
->adp
, MISC1_Y_RX_SW_DESC_LIST_CTRL_STS
);
1100 if (!(dma_cntrl
& DMA_START_BIT
)) {
1101 dma_cntrl
|= DMA_START_BIT
;
1102 crystalhd_reg_wr(hw
->adp
, MISC1_Y_RX_SW_DESC_LIST_CTRL_STS
, dma_cntrl
);
1105 dma_cntrl
= crystalhd_reg_rd(hw
->adp
, MISC1_UV_RX_SW_DESC_LIST_CTRL_STS
);
1106 if (!(dma_cntrl
& DMA_START_BIT
)) {
1107 dma_cntrl
|= DMA_START_BIT
;
1108 crystalhd_reg_wr(hw
->adp
, MISC1_UV_RX_SW_DESC_LIST_CTRL_STS
, dma_cntrl
);
1114 static void crystalhd_stop_rx_dma_engine(struct crystalhd_hw
*hw
)
1116 uint32_t dma_cntrl
= 0, count
= 30;
1117 uint32_t l0y
= 1, l0uv
= 1, l1y
= 1, l1uv
= 1;
1119 dma_cntrl
= crystalhd_reg_rd(hw
->adp
, MISC1_Y_RX_SW_DESC_LIST_CTRL_STS
);
1120 if ((dma_cntrl
& DMA_START_BIT
)) {
1121 dma_cntrl
&= ~DMA_START_BIT
;
1122 crystalhd_reg_wr(hw
->adp
, MISC1_Y_RX_SW_DESC_LIST_CTRL_STS
, dma_cntrl
);
1125 dma_cntrl
= crystalhd_reg_rd(hw
->adp
, MISC1_UV_RX_SW_DESC_LIST_CTRL_STS
);
1126 if ((dma_cntrl
& DMA_START_BIT
)) {
1127 dma_cntrl
&= ~DMA_START_BIT
;
1128 crystalhd_reg_wr(hw
->adp
, MISC1_UV_RX_SW_DESC_LIST_CTRL_STS
, dma_cntrl
);
1131 /* Poll for 3seconds (30 * 100ms) on both the lists..*/
1132 while ((l0y
|| l0uv
|| l1y
|| l1uv
) && count
) {
1135 l0y
= crystalhd_reg_rd(hw
->adp
, MISC1_Y_RX_FIRST_DESC_L_ADDR_LIST0
);
1136 l0y
&= DMA_START_BIT
;
1138 hw
->rx_list_sts
[0] &= ~rx_waiting_y_intr
;
1142 l1y
= crystalhd_reg_rd(hw
->adp
, MISC1_Y_RX_FIRST_DESC_L_ADDR_LIST1
);
1143 l1y
&= DMA_START_BIT
;
1145 hw
->rx_list_sts
[1] &= ~rx_waiting_y_intr
;
1149 l0uv
= crystalhd_reg_rd(hw
->adp
, MISC1_UV_RX_FIRST_DESC_L_ADDR_LIST0
);
1150 l0uv
&= DMA_START_BIT
;
1152 hw
->rx_list_sts
[0] &= ~rx_waiting_uv_intr
;
1156 l1uv
= crystalhd_reg_rd(hw
->adp
, MISC1_UV_RX_FIRST_DESC_L_ADDR_LIST1
);
1157 l1uv
&= DMA_START_BIT
;
1159 hw
->rx_list_sts
[1] &= ~rx_waiting_uv_intr
;
1161 msleep_interruptible(100);
1165 hw
->rx_list_post_index
= 0;
1167 BCMLOG(BCMLOG_SSTEP
, "Capture Stop: %d List0:Sts:%x List1:Sts:%x\n",
1168 count
, hw
->rx_list_sts
[0], hw
->rx_list_sts
[1]);
1171 static enum BC_STATUS
crystalhd_hw_prog_rxdma(struct crystalhd_hw
*hw
, struct crystalhd_rx_dma_pkt
*rx_pkt
)
1173 uint32_t y_low_addr_reg
, y_high_addr_reg
;
1174 uint32_t uv_low_addr_reg
, uv_high_addr_reg
;
1175 union addr_64 desc_addr
;
1176 unsigned long flags
;
1178 if (!hw
|| !rx_pkt
) {
1179 BCMLOG_ERR("Invalid Arguments\n");
1180 return BC_STS_INV_ARG
;
1183 if (hw
->rx_list_post_index
>= DMA_ENGINE_CNT
) {
1184 BCMLOG_ERR("List Out Of bounds %x\n", hw
->rx_list_post_index
);
1185 return BC_STS_INV_ARG
;
1188 spin_lock_irqsave(&hw
->rx_lock
, flags
);
1189 /* FIXME: jarod: sts_free is an enum for 0, in crystalhd_hw.h... yuk... */
1190 if (sts_free
!= hw
->rx_list_sts
[hw
->rx_list_post_index
]) {
1191 spin_unlock_irqrestore(&hw
->rx_lock
, flags
);
1195 if (!hw
->rx_list_post_index
) {
1196 y_low_addr_reg
= MISC1_Y_RX_FIRST_DESC_L_ADDR_LIST0
;
1197 y_high_addr_reg
= MISC1_Y_RX_FIRST_DESC_U_ADDR_LIST0
;
1198 uv_low_addr_reg
= MISC1_UV_RX_FIRST_DESC_L_ADDR_LIST0
;
1199 uv_high_addr_reg
= MISC1_UV_RX_FIRST_DESC_U_ADDR_LIST0
;
1201 y_low_addr_reg
= MISC1_Y_RX_FIRST_DESC_L_ADDR_LIST1
;
1202 y_high_addr_reg
= MISC1_Y_RX_FIRST_DESC_U_ADDR_LIST1
;
1203 uv_low_addr_reg
= MISC1_UV_RX_FIRST_DESC_L_ADDR_LIST1
;
1204 uv_high_addr_reg
= MISC1_UV_RX_FIRST_DESC_U_ADDR_LIST1
;
1206 rx_pkt
->pkt_tag
= hw
->rx_pkt_tag_seed
+ hw
->rx_list_post_index
;
1207 hw
->rx_list_sts
[hw
->rx_list_post_index
] |= rx_waiting_y_intr
;
1208 if (rx_pkt
->uv_phy_addr
)
1209 hw
->rx_list_sts
[hw
->rx_list_post_index
] |= rx_waiting_uv_intr
;
1210 hw
->rx_list_post_index
= (hw
->rx_list_post_index
+ 1) % DMA_ENGINE_CNT
;
1211 spin_unlock_irqrestore(&hw
->rx_lock
, flags
);
1213 crystalhd_dioq_add(hw
->rx_actq
, (void *)rx_pkt
, false, rx_pkt
->pkt_tag
);
1215 crystalhd_start_rx_dma_engine(hw
);
1216 /* Program the Y descriptor */
1217 desc_addr
.full_addr
= rx_pkt
->desc_mem
.phy_addr
;
1218 crystalhd_reg_wr(hw
->adp
, y_high_addr_reg
, desc_addr
.high_part
);
1219 crystalhd_reg_wr(hw
->adp
, y_low_addr_reg
, desc_addr
.low_part
| 0x01);
1221 if (rx_pkt
->uv_phy_addr
) {
1222 /* Program the UV descriptor */
1223 desc_addr
.full_addr
= rx_pkt
->uv_phy_addr
;
1224 crystalhd_reg_wr(hw
->adp
, uv_high_addr_reg
, desc_addr
.high_part
);
1225 crystalhd_reg_wr(hw
->adp
, uv_low_addr_reg
, desc_addr
.low_part
| 0x01);
1228 return BC_STS_SUCCESS
;
1231 static enum BC_STATUS
crystalhd_hw_post_cap_buff(struct crystalhd_hw
*hw
,
1232 struct crystalhd_rx_dma_pkt
*rx_pkt
)
1234 enum BC_STATUS sts
= crystalhd_hw_prog_rxdma(hw
, rx_pkt
);
1236 if (sts
== BC_STS_BUSY
)
1237 crystalhd_dioq_add(hw
->rx_freeq
, (void *)rx_pkt
,
1238 false, rx_pkt
->pkt_tag
);
1243 static void crystalhd_get_dnsz(struct crystalhd_hw
*hw
, uint32_t list_index
,
1244 uint32_t *y_dw_dnsz
, uint32_t *uv_dw_dnsz
)
1246 uint32_t y_dn_sz_reg
, uv_dn_sz_reg
;
1249 y_dn_sz_reg
= MISC1_Y_RX_LIST0_CUR_BYTE_CNT
;
1250 uv_dn_sz_reg
= MISC1_UV_RX_LIST0_CUR_BYTE_CNT
;
1252 y_dn_sz_reg
= MISC1_Y_RX_LIST1_CUR_BYTE_CNT
;
1253 uv_dn_sz_reg
= MISC1_UV_RX_LIST1_CUR_BYTE_CNT
;
1256 *y_dw_dnsz
= crystalhd_reg_rd(hw
->adp
, y_dn_sz_reg
);
1257 *uv_dw_dnsz
= crystalhd_reg_rd(hw
->adp
, uv_dn_sz_reg
);
1261 * This function should be called only after making sure that the two DMA
1262 * lists are free. This function does not check if DMA's are active, before
1263 * turning off the DMA.
1265 static void crystalhd_hw_finalize_pause(struct crystalhd_hw
*hw
)
1267 uint32_t dma_cntrl
, aspm
;
1269 hw
->stop_pending
= 0;
1271 dma_cntrl
= crystalhd_reg_rd(hw
->adp
, MISC1_Y_RX_SW_DESC_LIST_CTRL_STS
);
1272 if (dma_cntrl
& DMA_START_BIT
) {
1273 dma_cntrl
&= ~DMA_START_BIT
;
1274 crystalhd_reg_wr(hw
->adp
, MISC1_Y_RX_SW_DESC_LIST_CTRL_STS
, dma_cntrl
);
1277 dma_cntrl
= crystalhd_reg_rd(hw
->adp
, MISC1_UV_RX_SW_DESC_LIST_CTRL_STS
);
1278 if (dma_cntrl
& DMA_START_BIT
) {
1279 dma_cntrl
&= ~DMA_START_BIT
;
1280 crystalhd_reg_wr(hw
->adp
, MISC1_UV_RX_SW_DESC_LIST_CTRL_STS
, dma_cntrl
);
1282 hw
->rx_list_post_index
= 0;
1284 aspm
= crystalhd_reg_rd(hw
->adp
, PCIE_DLL_DATA_LINK_CONTROL
);
1285 aspm
|= ASPM_L1_ENABLE
;
1286 /* NAREN BCMLOG(BCMLOG_INFO, "aspm on\n"); */
1287 crystalhd_reg_wr(hw
->adp
, PCIE_DLL_DATA_LINK_CONTROL
, aspm
);
1290 static enum BC_STATUS
crystalhd_rx_pkt_done(struct crystalhd_hw
*hw
, uint32_t list_index
,
1291 enum BC_STATUS comp_sts
)
1293 struct crystalhd_rx_dma_pkt
*rx_pkt
= NULL
;
1294 uint32_t y_dw_dnsz
, uv_dw_dnsz
;
1295 enum BC_STATUS sts
= BC_STS_SUCCESS
;
1297 if (!hw
|| list_index
>= DMA_ENGINE_CNT
) {
1298 BCMLOG_ERR("Invalid Arguments\n");
1299 return BC_STS_INV_ARG
;
1302 rx_pkt
= crystalhd_dioq_find_and_fetch(hw
->rx_actq
,
1303 hw
->rx_pkt_tag_seed
+ list_index
);
1305 BCMLOG_ERR("Act-Q:PostIx:%x L0Sts:%x L1Sts:%x current L:%x tag:%x comp:%x\n",
1306 hw
->rx_list_post_index
, hw
->rx_list_sts
[0],
1307 hw
->rx_list_sts
[1], list_index
,
1308 hw
->rx_pkt_tag_seed
+ list_index
, comp_sts
);
1309 return BC_STS_INV_ARG
;
1312 if (comp_sts
== BC_STS_SUCCESS
) {
1313 crystalhd_get_dnsz(hw
, list_index
, &y_dw_dnsz
, &uv_dw_dnsz
);
1314 rx_pkt
->dio_req
->uinfo
.y_done_sz
= y_dw_dnsz
;
1315 rx_pkt
->flags
= COMP_FLAG_DATA_VALID
;
1316 if (rx_pkt
->uv_phy_addr
)
1317 rx_pkt
->dio_req
->uinfo
.uv_done_sz
= uv_dw_dnsz
;
1318 crystalhd_dioq_add(hw
->rx_rdyq
, rx_pkt
, true,
1319 hw
->rx_pkt_tag_seed
+ list_index
);
1323 /* Check if we can post this DIO again. */
1324 return crystalhd_hw_post_cap_buff(hw
, rx_pkt
);
1327 static bool crystalhd_rx_list0_handler(struct crystalhd_hw
*hw
, uint32_t int_sts
,
1328 uint32_t y_err_sts
, uint32_t uv_err_sts
)
1331 enum list_sts tmp_lsts
;
1333 if (!(y_err_sts
& GET_Y0_ERR_MSK
) && !(uv_err_sts
& GET_UV0_ERR_MSK
))
1336 tmp_lsts
= hw
->rx_list_sts
[0];
1339 tmp
= y_err_sts
& GET_Y0_ERR_MSK
;
1340 if (int_sts
& INTR_INTR_STATUS_L0_Y_RX_DMA_DONE_INTR_MASK
)
1341 hw
->rx_list_sts
[0] &= ~rx_waiting_y_intr
;
1343 if (y_err_sts
& MISC1_Y_RX_ERROR_STATUS_RX_L0_UNDERRUN_ERROR_MASK
) {
1344 hw
->rx_list_sts
[0] &= ~rx_waiting_y_intr
;
1345 tmp
&= ~MISC1_Y_RX_ERROR_STATUS_RX_L0_UNDERRUN_ERROR_MASK
;
1348 if (y_err_sts
& MISC1_Y_RX_ERROR_STATUS_RX_L0_FIFO_FULL_ERRORS_MASK
) {
1349 hw
->rx_list_sts
[0] &= ~rx_y_mask
;
1350 hw
->rx_list_sts
[0] |= rx_y_error
;
1351 tmp
&= ~MISC1_Y_RX_ERROR_STATUS_RX_L0_FIFO_FULL_ERRORS_MASK
;
1355 hw
->rx_list_sts
[0] &= ~rx_y_mask
;
1356 hw
->rx_list_sts
[0] |= rx_y_error
;
1357 hw
->rx_list_post_index
= 0;
1361 tmp
= uv_err_sts
& GET_UV0_ERR_MSK
;
1362 if (int_sts
& INTR_INTR_STATUS_L0_UV_RX_DMA_DONE_INTR_MASK
)
1363 hw
->rx_list_sts
[0] &= ~rx_waiting_uv_intr
;
1365 if (uv_err_sts
& MISC1_UV_RX_ERROR_STATUS_RX_L0_UNDERRUN_ERROR_MASK
) {
1366 hw
->rx_list_sts
[0] &= ~rx_waiting_uv_intr
;
1367 tmp
&= ~MISC1_UV_RX_ERROR_STATUS_RX_L0_UNDERRUN_ERROR_MASK
;
1370 if (uv_err_sts
& MISC1_UV_RX_ERROR_STATUS_RX_L0_FIFO_FULL_ERRORS_MASK
) {
1371 hw
->rx_list_sts
[0] &= ~rx_uv_mask
;
1372 hw
->rx_list_sts
[0] |= rx_uv_error
;
1373 tmp
&= ~MISC1_UV_RX_ERROR_STATUS_RX_L0_FIFO_FULL_ERRORS_MASK
;
1377 hw
->rx_list_sts
[0] &= ~rx_uv_mask
;
1378 hw
->rx_list_sts
[0] |= rx_uv_error
;
1379 hw
->rx_list_post_index
= 0;
1382 if (y_err_sts
& GET_Y0_ERR_MSK
) {
1383 tmp
= y_err_sts
& GET_Y0_ERR_MSK
;
1384 crystalhd_reg_wr(hw
->adp
, MISC1_Y_RX_ERROR_STATUS
, tmp
);
1387 if (uv_err_sts
& GET_UV0_ERR_MSK
) {
1388 tmp
= uv_err_sts
& GET_UV0_ERR_MSK
;
1389 crystalhd_reg_wr(hw
->adp
, MISC1_UV_RX_ERROR_STATUS
, tmp
);
1392 return (tmp_lsts
!= hw
->rx_list_sts
[0]);
1395 static bool crystalhd_rx_list1_handler(struct crystalhd_hw
*hw
, uint32_t int_sts
,
1396 uint32_t y_err_sts
, uint32_t uv_err_sts
)
1399 enum list_sts tmp_lsts
;
1401 if (!(y_err_sts
& GET_Y1_ERR_MSK
) && !(uv_err_sts
& GET_UV1_ERR_MSK
))
1404 tmp_lsts
= hw
->rx_list_sts
[1];
1407 tmp
= y_err_sts
& GET_Y1_ERR_MSK
;
1408 if (int_sts
& INTR_INTR_STATUS_L1_Y_RX_DMA_DONE_INTR_MASK
)
1409 hw
->rx_list_sts
[1] &= ~rx_waiting_y_intr
;
1411 if (y_err_sts
& MISC1_Y_RX_ERROR_STATUS_RX_L1_UNDERRUN_ERROR_MASK
) {
1412 hw
->rx_list_sts
[1] &= ~rx_waiting_y_intr
;
1413 tmp
&= ~MISC1_Y_RX_ERROR_STATUS_RX_L1_UNDERRUN_ERROR_MASK
;
1416 if (y_err_sts
& MISC1_Y_RX_ERROR_STATUS_RX_L1_FIFO_FULL_ERRORS_MASK
) {
1417 /* Add retry-support..*/
1418 hw
->rx_list_sts
[1] &= ~rx_y_mask
;
1419 hw
->rx_list_sts
[1] |= rx_y_error
;
1420 tmp
&= ~MISC1_Y_RX_ERROR_STATUS_RX_L1_FIFO_FULL_ERRORS_MASK
;
1424 hw
->rx_list_sts
[1] &= ~rx_y_mask
;
1425 hw
->rx_list_sts
[1] |= rx_y_error
;
1426 hw
->rx_list_post_index
= 0;
1430 tmp
= uv_err_sts
& GET_UV1_ERR_MSK
;
1431 if (int_sts
& INTR_INTR_STATUS_L1_UV_RX_DMA_DONE_INTR_MASK
)
1432 hw
->rx_list_sts
[1] &= ~rx_waiting_uv_intr
;
1434 if (uv_err_sts
& MISC1_UV_RX_ERROR_STATUS_RX_L1_UNDERRUN_ERROR_MASK
) {
1435 hw
->rx_list_sts
[1] &= ~rx_waiting_uv_intr
;
1436 tmp
&= ~MISC1_UV_RX_ERROR_STATUS_RX_L1_UNDERRUN_ERROR_MASK
;
1439 if (uv_err_sts
& MISC1_UV_RX_ERROR_STATUS_RX_L1_FIFO_FULL_ERRORS_MASK
) {
1440 /* Add retry-support*/
1441 hw
->rx_list_sts
[1] &= ~rx_uv_mask
;
1442 hw
->rx_list_sts
[1] |= rx_uv_error
;
1443 tmp
&= ~MISC1_UV_RX_ERROR_STATUS_RX_L1_FIFO_FULL_ERRORS_MASK
;
1447 hw
->rx_list_sts
[1] &= ~rx_uv_mask
;
1448 hw
->rx_list_sts
[1] |= rx_uv_error
;
1449 hw
->rx_list_post_index
= 0;
1452 if (y_err_sts
& GET_Y1_ERR_MSK
) {
1453 tmp
= y_err_sts
& GET_Y1_ERR_MSK
;
1454 crystalhd_reg_wr(hw
->adp
, MISC1_Y_RX_ERROR_STATUS
, tmp
);
1457 if (uv_err_sts
& GET_UV1_ERR_MSK
) {
1458 tmp
= uv_err_sts
& GET_UV1_ERR_MSK
;
1459 crystalhd_reg_wr(hw
->adp
, MISC1_UV_RX_ERROR_STATUS
, tmp
);
1462 return (tmp_lsts
!= hw
->rx_list_sts
[1]);
1466 static void crystalhd_rx_isr(struct crystalhd_hw
*hw
, uint32_t intr_sts
)
1468 unsigned long flags
;
1469 uint32_t i
, list_avail
= 0;
1470 enum BC_STATUS comp_sts
= BC_STS_NO_DATA
;
1471 uint32_t y_err_sts
, uv_err_sts
, y_dn_sz
= 0, uv_dn_sz
= 0;
1475 BCMLOG_ERR("Invalid Arguments\n");
1479 if (!(intr_sts
& GET_RX_INTR_MASK
))
1482 y_err_sts
= crystalhd_reg_rd(hw
->adp
, MISC1_Y_RX_ERROR_STATUS
);
1483 uv_err_sts
= crystalhd_reg_rd(hw
->adp
, MISC1_UV_RX_ERROR_STATUS
);
1485 for (i
= 0; i
< DMA_ENGINE_CNT
; i
++) {
1486 /* Update States..*/
1487 spin_lock_irqsave(&hw
->rx_lock
, flags
);
1489 ret
= crystalhd_rx_list0_handler(hw
, intr_sts
, y_err_sts
, uv_err_sts
);
1491 ret
= crystalhd_rx_list1_handler(hw
, intr_sts
, y_err_sts
, uv_err_sts
);
1493 switch (hw
->rx_list_sts
[i
]) {
1495 comp_sts
= BC_STS_SUCCESS
;
1501 /* We got error on both or Y or uv. */
1502 hw
->stats
.rx_errors
++;
1503 crystalhd_get_dnsz(hw
, i
, &y_dn_sz
, &uv_dn_sz
);
1504 /* FIXME: jarod: this is where my mini pci-e card is tripping up */
1505 BCMLOG(BCMLOG_DBG
, "list_index:%x rx[%d] Y:%x "
1506 "UV:%x Int:%x YDnSz:%x UVDnSz:%x\n",
1507 i
, hw
->stats
.rx_errors
, y_err_sts
,
1508 uv_err_sts
, intr_sts
, y_dn_sz
, uv_dn_sz
);
1509 hw
->rx_list_sts
[i
] = sts_free
;
1510 comp_sts
= BC_STS_ERROR
;
1513 /* Wait for completion..*/
1514 comp_sts
= BC_STS_NO_DATA
;
1518 spin_unlock_irqrestore(&hw
->rx_lock
, flags
);
1520 /* handle completion...*/
1521 if (comp_sts
!= BC_STS_NO_DATA
) {
1522 crystalhd_rx_pkt_done(hw
, i
, comp_sts
);
1523 comp_sts
= BC_STS_NO_DATA
;
1528 if (hw
->stop_pending
) {
1529 if ((hw
->rx_list_sts
[0] == sts_free
) &&
1530 (hw
->rx_list_sts
[1] == sts_free
))
1531 crystalhd_hw_finalize_pause(hw
);
1533 crystalhd_hw_start_capture(hw
);
1538 static enum BC_STATUS
crystalhd_fw_cmd_post_proc(struct crystalhd_hw
*hw
,
1539 struct BC_FW_CMD
*fw_cmd
)
1541 enum BC_STATUS sts
= BC_STS_SUCCESS
;
1542 struct dec_rsp_channel_start_video
*st_rsp
= NULL
;
1544 switch (fw_cmd
->cmd
[0]) {
1545 case eCMD_C011_DEC_CHAN_START_VIDEO
:
1546 st_rsp
= (struct dec_rsp_channel_start_video
*)fw_cmd
->rsp
;
1547 hw
->pib_del_Q_addr
= st_rsp
->picInfoDeliveryQ
;
1548 hw
->pib_rel_Q_addr
= st_rsp
->picInfoReleaseQ
;
1549 BCMLOG(BCMLOG_DBG
, "DelQAddr:%x RelQAddr:%x\n",
1550 hw
->pib_del_Q_addr
, hw
->pib_rel_Q_addr
);
1552 case eCMD_C011_INIT
:
1553 if (!(crystalhd_load_firmware_config(hw
->adp
))) {
1554 BCMLOG_ERR("Invalid Params.\n");
1555 sts
= BC_STS_FW_AUTH_FAILED
;
1564 static enum BC_STATUS
crystalhd_put_ddr2sleep(struct crystalhd_hw
*hw
)
1567 union link_misc_perst_decoder_ctrl rst_cntrl_reg
;
1569 /* Pulse reset pin of 7412 (MISC_PERST_DECODER_CTRL) */
1570 rst_cntrl_reg
.whole_reg
= crystalhd_reg_rd(hw
->adp
, MISC_PERST_DECODER_CTRL
);
1572 rst_cntrl_reg
.bcm_7412_rst
= 1;
1573 crystalhd_reg_wr(hw
->adp
, MISC_PERST_DECODER_CTRL
, rst_cntrl_reg
.whole_reg
);
1574 msleep_interruptible(50);
1576 rst_cntrl_reg
.bcm_7412_rst
= 0;
1577 crystalhd_reg_wr(hw
->adp
, MISC_PERST_DECODER_CTRL
, rst_cntrl_reg
.whole_reg
);
1579 /* Close all banks, put DDR in idle */
1580 bc_dec_reg_wr(hw
->adp
, SDRAM_PRECHARGE
, 0);
1582 /* Set bit 25 (drop CKE pin of DDR) */
1583 reg
= bc_dec_reg_rd(hw
->adp
, SDRAM_PARAM
);
1585 bc_dec_reg_wr(hw
->adp
, SDRAM_PARAM
, reg
);
1587 /* Reset the audio block */
1588 bc_dec_reg_wr(hw
->adp
, AUD_DSP_MISC_SOFT_RESET
, 0x1);
1590 /* Power down Raptor PLL */
1591 reg
= bc_dec_reg_rd(hw
->adp
, DecHt_PllCCtl
);
1593 bc_dec_reg_wr(hw
->adp
, DecHt_PllCCtl
, reg
);
1595 /* Power down all Audio PLL */
1596 bc_dec_reg_wr(hw
->adp
, AIO_MISC_PLL_RESET
, 0x1);
1598 /* Power down video clock (75MHz) */
1599 reg
= bc_dec_reg_rd(hw
->adp
, DecHt_PllECtl
);
1601 bc_dec_reg_wr(hw
->adp
, DecHt_PllECtl
, reg
);
1603 /* Power down video clock (75MHz) */
1604 reg
= bc_dec_reg_rd(hw
->adp
, DecHt_PllDCtl
);
1606 bc_dec_reg_wr(hw
->adp
, DecHt_PllDCtl
, reg
);
1608 /* Power down core clock (200MHz) */
1609 reg
= bc_dec_reg_rd(hw
->adp
, DecHt_PllACtl
);
1611 bc_dec_reg_wr(hw
->adp
, DecHt_PllACtl
, reg
);
1613 /* Power down core clock (200MHz) */
1614 reg
= bc_dec_reg_rd(hw
->adp
, DecHt_PllBCtl
);
1616 bc_dec_reg_wr(hw
->adp
, DecHt_PllBCtl
, reg
);
1618 return BC_STS_SUCCESS
;
1621 /************************************************
1623 *************************************************/
1625 enum BC_STATUS
crystalhd_download_fw(struct crystalhd_adp
*adp
, void *buffer
, uint32_t sz
)
1627 uint32_t reg_data
, cnt
, *temp_buff
;
1628 uint32_t fw_sig_len
= 36;
1629 uint32_t dram_offset
= BC_FWIMG_ST_ADDR
, sig_reg
;
1633 if (!adp
|| !buffer
|| !sz
) {
1634 BCMLOG_ERR("Invalid Params.\n");
1635 return BC_STS_INV_ARG
;
1638 reg_data
= crystalhd_reg_rd(adp
, OTP_CMD
);
1639 if (!(reg_data
& 0x02)) {
1640 BCMLOG_ERR("Invalid hw config.. otp not programmed\n");
1641 return BC_STS_ERROR
;
1645 crystalhd_reg_wr(adp
, DCI_CMD
, 0);
1646 reg_data
|= BC_BIT(0);
1647 crystalhd_reg_wr(adp
, DCI_CMD
, reg_data
);
1651 msleep_interruptible(10);
1653 while (reg_data
!= BC_BIT(4)) {
1654 reg_data
= crystalhd_reg_rd(adp
, DCI_STATUS
);
1655 reg_data
&= BC_BIT(4);
1657 BCMLOG_ERR("Firmware Download RDY Timeout.\n");
1658 return BC_STS_TIMEOUT
;
1662 msleep_interruptible(10);
1663 /* Load the FW to the FW_ADDR field in the DCI_FIRMWARE_ADDR */
1664 crystalhd_reg_wr(adp
, DCI_FIRMWARE_ADDR
, dram_offset
);
1665 temp_buff
= (uint32_t *)buffer
;
1666 for (cnt
= 0; cnt
< (sz
- fw_sig_len
); cnt
+= 4) {
1667 crystalhd_reg_wr(adp
, DCI_DRAM_BASE_ADDR
, (dram_offset
>> 19));
1668 crystalhd_reg_wr(adp
, DCI_FIRMWARE_DATA
, *temp_buff
);
1672 msleep_interruptible(10);
1676 sig_reg
= (uint32_t)DCI_SIGNATURE_DATA_7
;
1677 for (cnt
= 0; cnt
< 8; cnt
++) {
1678 uint32_t swapped_data
= *temp_buff
;
1679 swapped_data
= bswap_32_1(swapped_data
);
1680 crystalhd_reg_wr(adp
, sig_reg
, swapped_data
);
1684 msleep_interruptible(10);
1687 reg_data
|= BC_BIT(1);
1688 crystalhd_reg_wr(adp
, DCI_CMD
, reg_data
);
1689 msleep_interruptible(10);
1692 reg_data
= crystalhd_reg_rd(adp
, DCI_STATUS
);
1694 if ((reg_data
& BC_BIT(9)) == BC_BIT(9)) {
1696 while ((reg_data
& BC_BIT(0)) != BC_BIT(0)) {
1697 reg_data
= crystalhd_reg_rd(adp
, DCI_STATUS
);
1698 reg_data
&= BC_BIT(0);
1701 msleep_interruptible(10);
1704 reg_data
= crystalhd_reg_rd(adp
, DCI_CMD
);
1705 reg_data
|= BC_BIT(4);
1706 crystalhd_reg_wr(adp
, DCI_CMD
, reg_data
);
1709 BCMLOG_ERR("F/w Signature mismatch\n");
1710 return BC_STS_FW_AUTH_FAILED
;
1713 BCMLOG(BCMLOG_INFO
, "Firmware Downloaded Successfully\n");
1714 return BC_STS_SUCCESS
;
1717 enum BC_STATUS
crystalhd_do_fw_cmd(struct crystalhd_hw
*hw
,
1718 struct BC_FW_CMD
*fw_cmd
)
1720 uint32_t cnt
= 0, cmd_res_addr
;
1721 uint32_t *cmd_buff
, *res_buff
;
1722 wait_queue_head_t fw_cmd_event
;
1726 crystalhd_create_event(&fw_cmd_event
);
1730 if (!hw
|| !fw_cmd
) {
1731 BCMLOG_ERR("Invalid Arguments\n");
1732 return BC_STS_INV_ARG
;
1735 cmd_buff
= fw_cmd
->cmd
;
1736 res_buff
= fw_cmd
->rsp
;
1738 if (!cmd_buff
|| !res_buff
) {
1739 BCMLOG_ERR("Invalid Parameters for F/W Command\n");
1740 return BC_STS_INV_ARG
;
1745 hw
->fwcmd_evt_sts
= 0;
1746 hw
->pfw_cmd_event
= &fw_cmd_event
;
1748 /*Write the command to the memory*/
1749 crystalhd_mem_wr(hw
->adp
, TS_Host2CpuSnd
, FW_CMD_BUFF_SZ
, cmd_buff
);
1751 /*Memory Read for memory arbitrator flush*/
1752 crystalhd_mem_rd(hw
->adp
, TS_Host2CpuSnd
, 1, &cnt
);
1754 /* Write the command address to mailbox */
1755 bc_dec_reg_wr(hw
->adp
, Hst2CpuMbx1
, TS_Host2CpuSnd
);
1756 msleep_interruptible(50);
1758 crystalhd_wait_on_event(&fw_cmd_event
, hw
->fwcmd_evt_sts
, 20000, rc
, 0);
1761 sts
= BC_STS_SUCCESS
;
1762 } else if (rc
== -EBUSY
) {
1763 BCMLOG_ERR("Firmware command T/O\n");
1764 sts
= BC_STS_TIMEOUT
;
1765 } else if (rc
== -EINTR
) {
1766 BCMLOG(BCMLOG_DBG
, "FwCmd Wait Signal int.\n");
1767 sts
= BC_STS_IO_USER_ABORT
;
1769 BCMLOG_ERR("FwCmd IO Error.\n");
1770 sts
= BC_STS_IO_ERROR
;
1773 if (sts
!= BC_STS_SUCCESS
) {
1774 BCMLOG_ERR("FwCmd Failed.\n");
1779 /*Get the Response Address*/
1780 cmd_res_addr
= bc_dec_reg_rd(hw
->adp
, Cpu2HstMbx1
);
1782 /*Read the Response*/
1783 crystalhd_mem_rd(hw
->adp
, cmd_res_addr
, FW_CMD_BUFF_SZ
, res_buff
);
1787 if (res_buff
[2] != C011_RET_SUCCESS
) {
1788 BCMLOG_ERR("res_buff[2] != C011_RET_SUCCESS\n");
1789 return BC_STS_FW_CMD_ERR
;
1792 sts
= crystalhd_fw_cmd_post_proc(hw
, fw_cmd
);
1793 if (sts
!= BC_STS_SUCCESS
)
1794 BCMLOG_ERR("crystalhd_fw_cmd_post_proc Failed.\n");
1799 bool crystalhd_hw_interrupt(struct crystalhd_adp
*adp
, struct crystalhd_hw
*hw
)
1801 uint32_t intr_sts
= 0;
1802 uint32_t deco_intr
= 0;
1805 if (!adp
|| !hw
->dev_started
)
1808 hw
->stats
.num_interrupts
++;
1811 deco_intr
= bc_dec_reg_rd(adp
, Stream2Host_Intr_Sts
);
1812 intr_sts
= crystalhd_reg_rd(adp
, INTR_INTR_STATUS
);
1815 /* let system know we processed interrupt..*/
1817 hw
->stats
.dev_interrupts
++;
1820 if (deco_intr
&& (deco_intr
!= 0xdeaddead)) {
1822 if (deco_intr
& 0x80000000) {
1823 /*Set the Event and the status flag*/
1824 if (hw
->pfw_cmd_event
) {
1825 hw
->fwcmd_evt_sts
= 1;
1826 crystalhd_set_event(hw
->pfw_cmd_event
);
1830 if (deco_intr
& BC_BIT(1))
1831 crystalhd_hw_proc_pib(hw
);
1833 bc_dec_reg_wr(adp
, Stream2Host_Intr_Sts
, deco_intr
);
1834 /* FIXME: jarod: No udelay? might this be the real reason mini pci-e cards were stalling out? */
1835 bc_dec_reg_wr(adp
, Stream2Host_Intr_Sts
, 0);
1840 crystalhd_rx_isr(hw
, intr_sts
);
1843 crystalhd_tx_isr(hw
, intr_sts
);
1845 /* Clear interrupts */
1848 crystalhd_reg_wr(adp
, INTR_INTR_CLR_REG
, intr_sts
);
1850 crystalhd_reg_wr(adp
, INTR_EOI_CTRL
, 1);
1858 enum BC_STATUS
crystalhd_hw_open(struct crystalhd_hw
*hw
, struct crystalhd_adp
*adp
)
1861 BCMLOG_ERR("Invalid Arguments\n");
1862 return BC_STS_INV_ARG
;
1865 if (hw
->dev_started
)
1866 return BC_STS_SUCCESS
;
1868 memset(hw
, 0, sizeof(struct crystalhd_hw
));
1871 spin_lock_init(&hw
->lock
);
1872 spin_lock_init(&hw
->rx_lock
);
1873 /* FIXME: jarod: what are these magic numbers?!? */
1874 hw
->tx_ioq_tag_seed
= 0x70023070;
1875 hw
->rx_pkt_tag_seed
= 0x70029070;
1877 hw
->stop_pending
= 0;
1878 crystalhd_start_device(hw
->adp
);
1879 hw
->dev_started
= true;
1881 /* set initial core clock */
1882 hw
->core_clock_mhz
= CLOCK_PRESET
;
1885 crystalhd_hw_set_core_clock(hw
);
1887 return BC_STS_SUCCESS
;
1890 enum BC_STATUS
crystalhd_hw_close(struct crystalhd_hw
*hw
)
1893 BCMLOG_ERR("Invalid Arguments\n");
1894 return BC_STS_INV_ARG
;
1897 if (!hw
->dev_started
)
1898 return BC_STS_SUCCESS
;
1900 /* Stop and DDR sleep will happen in here */
1901 crystalhd_hw_suspend(hw
);
1902 hw
->dev_started
= false;
1904 return BC_STS_SUCCESS
;
1907 enum BC_STATUS
crystalhd_hw_setup_dma_rings(struct crystalhd_hw
*hw
)
1912 dma_addr_t phy_addr
;
1913 enum BC_STATUS sts
= BC_STS_SUCCESS
;
1914 struct crystalhd_rx_dma_pkt
*rpkt
;
1916 if (!hw
|| !hw
->adp
) {
1917 BCMLOG_ERR("Invalid Arguments\n");
1918 return BC_STS_INV_ARG
;
1921 sts
= crystalhd_hw_create_ioqs(hw
);
1922 if (sts
!= BC_STS_SUCCESS
) {
1923 BCMLOG_ERR("Failed to create IOQs..\n");
1927 mem_len
= BC_LINK_MAX_SGLS
* sizeof(struct dma_descriptor
);
1929 for (i
= 0; i
< BC_TX_LIST_CNT
; i
++) {
1930 mem
= bc_kern_dma_alloc(hw
->adp
, mem_len
, &phy_addr
);
1932 memset(mem
, 0, mem_len
);
1934 BCMLOG_ERR("Insufficient Memory For TX\n");
1935 crystalhd_hw_free_dma_rings(hw
);
1936 return BC_STS_INSUFF_RES
;
1938 /* rx_pkt_pool -- static memory allocation */
1939 hw
->tx_pkt_pool
[i
].desc_mem
.pdma_desc_start
= mem
;
1940 hw
->tx_pkt_pool
[i
].desc_mem
.phy_addr
= phy_addr
;
1941 hw
->tx_pkt_pool
[i
].desc_mem
.sz
= BC_LINK_MAX_SGLS
*
1942 sizeof(struct dma_descriptor
);
1943 hw
->tx_pkt_pool
[i
].list_tag
= 0;
1945 /* Add TX dma requests to Free Queue..*/
1946 sts
= crystalhd_dioq_add(hw
->tx_freeq
,
1947 &hw
->tx_pkt_pool
[i
], false, 0);
1948 if (sts
!= BC_STS_SUCCESS
) {
1949 crystalhd_hw_free_dma_rings(hw
);
1954 for (i
= 0; i
< BC_RX_LIST_CNT
; i
++) {
1955 rpkt
= kzalloc(sizeof(*rpkt
), GFP_KERNEL
);
1957 BCMLOG_ERR("Insufficient Memory For RX\n");
1958 crystalhd_hw_free_dma_rings(hw
);
1959 return BC_STS_INSUFF_RES
;
1962 mem
= bc_kern_dma_alloc(hw
->adp
, mem_len
, &phy_addr
);
1964 memset(mem
, 0, mem_len
);
1966 BCMLOG_ERR("Insufficient Memory For RX\n");
1967 crystalhd_hw_free_dma_rings(hw
);
1969 return BC_STS_INSUFF_RES
;
1971 rpkt
->desc_mem
.pdma_desc_start
= mem
;
1972 rpkt
->desc_mem
.phy_addr
= phy_addr
;
1973 rpkt
->desc_mem
.sz
= BC_LINK_MAX_SGLS
* sizeof(struct dma_descriptor
);
1974 rpkt
->pkt_tag
= hw
->rx_pkt_tag_seed
+ i
;
1975 crystalhd_hw_free_rx_pkt(hw
, rpkt
);
1978 return BC_STS_SUCCESS
;
1981 enum BC_STATUS
crystalhd_hw_free_dma_rings(struct crystalhd_hw
*hw
)
1984 struct crystalhd_rx_dma_pkt
*rpkt
= NULL
;
1986 if (!hw
|| !hw
->adp
) {
1987 BCMLOG_ERR("Invalid Arguments\n");
1988 return BC_STS_INV_ARG
;
1991 /* Delete all IOQs.. */
1992 crystalhd_hw_delete_ioqs(hw
);
1994 for (i
= 0; i
< BC_TX_LIST_CNT
; i
++) {
1995 if (hw
->tx_pkt_pool
[i
].desc_mem
.pdma_desc_start
) {
1996 bc_kern_dma_free(hw
->adp
,
1997 hw
->tx_pkt_pool
[i
].desc_mem
.sz
,
1998 hw
->tx_pkt_pool
[i
].desc_mem
.pdma_desc_start
,
1999 hw
->tx_pkt_pool
[i
].desc_mem
.phy_addr
);
2001 hw
->tx_pkt_pool
[i
].desc_mem
.pdma_desc_start
= NULL
;
2005 BCMLOG(BCMLOG_DBG
, "Releasing RX Pkt pool\n");
2007 rpkt
= crystalhd_hw_alloc_rx_pkt(hw
);
2010 bc_kern_dma_free(hw
->adp
, rpkt
->desc_mem
.sz
,
2011 rpkt
->desc_mem
.pdma_desc_start
,
2012 rpkt
->desc_mem
.phy_addr
);
2016 return BC_STS_SUCCESS
;
2019 enum BC_STATUS
crystalhd_hw_post_tx(struct crystalhd_hw
*hw
, struct crystalhd_dio_req
*ioreq
,
2020 hw_comp_callback call_back
,
2021 wait_queue_head_t
*cb_event
, uint32_t *list_id
,
2024 struct tx_dma_pkt
*tx_dma_packet
= NULL
;
2025 uint32_t first_desc_u_addr
, first_desc_l_addr
;
2026 uint32_t low_addr
, high_addr
;
2027 union addr_64 desc_addr
;
2028 enum BC_STATUS sts
, add_sts
;
2029 uint32_t dummy_index
= 0;
2030 unsigned long flags
;
2033 if (!hw
|| !ioreq
|| !call_back
|| !cb_event
|| !list_id
) {
2034 BCMLOG_ERR("Invalid Arguments\n");
2035 return BC_STS_INV_ARG
;
2039 * Since we hit code in busy condition very frequently,
2040 * we will check the code in status first before
2041 * checking the availability of free elem.
2043 * This will avoid the Q fetch/add in normal condition.
2045 rc
= crystalhd_code_in_full(hw
->adp
, ioreq
->uinfo
.xfr_len
,
2048 hw
->stats
.cin_busy
++;
2052 /* Get a list from TxFreeQ */
2053 tx_dma_packet
= (struct tx_dma_pkt
*)crystalhd_dioq_fetch(hw
->tx_freeq
);
2054 if (!tx_dma_packet
) {
2055 BCMLOG_ERR("No empty elements..\n");
2056 return BC_STS_ERR_USAGE
;
2059 sts
= crystalhd_xlat_sgl_to_dma_desc(ioreq
,
2060 &tx_dma_packet
->desc_mem
,
2062 if (sts
!= BC_STS_SUCCESS
) {
2063 add_sts
= crystalhd_dioq_add(hw
->tx_freeq
, tx_dma_packet
,
2065 if (add_sts
!= BC_STS_SUCCESS
)
2066 BCMLOG_ERR("double fault..\n");
2073 desc_addr
.full_addr
= tx_dma_packet
->desc_mem
.phy_addr
;
2074 low_addr
= desc_addr
.low_part
;
2075 high_addr
= desc_addr
.high_part
;
2077 tx_dma_packet
->call_back
= call_back
;
2078 tx_dma_packet
->cb_event
= cb_event
;
2079 tx_dma_packet
->dio_req
= ioreq
;
2081 spin_lock_irqsave(&hw
->lock
, flags
);
2083 if (hw
->tx_list_post_index
== 0) {
2084 first_desc_u_addr
= MISC1_TX_FIRST_DESC_U_ADDR_LIST0
;
2085 first_desc_l_addr
= MISC1_TX_FIRST_DESC_L_ADDR_LIST0
;
2087 first_desc_u_addr
= MISC1_TX_FIRST_DESC_U_ADDR_LIST1
;
2088 first_desc_l_addr
= MISC1_TX_FIRST_DESC_L_ADDR_LIST1
;
2091 *list_id
= tx_dma_packet
->list_tag
= hw
->tx_ioq_tag_seed
+
2092 hw
->tx_list_post_index
;
2094 hw
->tx_list_post_index
= (hw
->tx_list_post_index
+ 1) % DMA_ENGINE_CNT
;
2096 spin_unlock_irqrestore(&hw
->lock
, flags
);
2099 /* Insert in Active Q..*/
2100 crystalhd_dioq_add(hw
->tx_actq
, tx_dma_packet
, false,
2101 tx_dma_packet
->list_tag
);
2104 * Interrupt will come as soon as you write
2105 * the valid bit. So be ready for that. All
2106 * the initialization should happen before that.
2108 crystalhd_start_tx_dma_engine(hw
);
2109 crystalhd_reg_wr(hw
->adp
, first_desc_u_addr
, desc_addr
.high_part
);
2111 crystalhd_reg_wr(hw
->adp
, first_desc_l_addr
, desc_addr
.low_part
| 0x01);
2112 /* Be sure we set the valid bit ^^^^ */
2114 return BC_STS_SUCCESS
;
2118 * This is a force cancel and we are racing with ISR.
2120 * Will try to remove the req from ActQ before ISR gets it.
2121 * If ISR gets it first then the completion happens in the
2122 * normal path and we will return _STS_NO_DATA from here.
2124 * FIX_ME: Not Tested the actual condition..
2126 enum BC_STATUS
crystalhd_hw_cancel_tx(struct crystalhd_hw
*hw
, uint32_t list_id
)
2128 if (!hw
|| !list_id
) {
2129 BCMLOG_ERR("Invalid Arguments\n");
2130 return BC_STS_INV_ARG
;
2133 crystalhd_stop_tx_dma_engine(hw
);
2134 crystalhd_hw_tx_req_complete(hw
, list_id
, BC_STS_IO_USER_ABORT
);
2136 return BC_STS_SUCCESS
;
2139 enum BC_STATUS
crystalhd_hw_add_cap_buffer(struct crystalhd_hw
*hw
,
2140 struct crystalhd_dio_req
*ioreq
, bool en_post
)
2142 struct crystalhd_rx_dma_pkt
*rpkt
;
2143 uint32_t tag
, uv_desc_ix
= 0;
2146 if (!hw
|| !ioreq
) {
2147 BCMLOG_ERR("Invalid Arguments\n");
2148 return BC_STS_INV_ARG
;
2151 rpkt
= crystalhd_hw_alloc_rx_pkt(hw
);
2153 BCMLOG_ERR("Insufficient resources\n");
2154 return BC_STS_INSUFF_RES
;
2157 rpkt
->dio_req
= ioreq
;
2158 tag
= rpkt
->pkt_tag
;
2160 sts
= crystalhd_xlat_sgl_to_dma_desc(ioreq
, &rpkt
->desc_mem
, &uv_desc_ix
);
2161 if (sts
!= BC_STS_SUCCESS
)
2164 rpkt
->uv_phy_addr
= 0;
2166 /* Store the address of UV in the rx packet for post*/
2168 rpkt
->uv_phy_addr
= rpkt
->desc_mem
.phy_addr
+
2169 (sizeof(struct dma_descriptor
) * (uv_desc_ix
+ 1));
2172 sts
= crystalhd_hw_post_cap_buff(hw
, rpkt
);
2174 sts
= crystalhd_dioq_add(hw
->rx_freeq
, rpkt
, false, tag
);
2179 enum BC_STATUS
crystalhd_hw_get_cap_buffer(struct crystalhd_hw
*hw
,
2180 struct BC_PIC_INFO_BLOCK
*pib
,
2181 struct crystalhd_dio_req
**ioreq
)
2183 struct crystalhd_rx_dma_pkt
*rpkt
;
2184 uint32_t timeout
= BC_PROC_OUTPUT_TIMEOUT
/ 1000;
2185 uint32_t sig_pending
= 0;
2188 if (!hw
|| !ioreq
|| !pib
) {
2189 BCMLOG_ERR("Invalid Arguments\n");
2190 return BC_STS_INV_ARG
;
2193 rpkt
= crystalhd_dioq_fetch_wait(hw
->rx_rdyq
, timeout
, &sig_pending
);
2196 BCMLOG(BCMLOG_INFO
, "wait on frame time out %d\n", sig_pending
);
2197 return BC_STS_IO_USER_ABORT
;
2199 return BC_STS_TIMEOUT
;
2203 rpkt
->dio_req
->uinfo
.comp_flags
= rpkt
->flags
;
2205 if (rpkt
->flags
& COMP_FLAG_PIB_VALID
)
2206 memcpy(pib
, &rpkt
->pib
, sizeof(*pib
));
2208 *ioreq
= rpkt
->dio_req
;
2210 crystalhd_hw_free_rx_pkt(hw
, rpkt
);
2212 return BC_STS_SUCCESS
;
2215 enum BC_STATUS
crystalhd_hw_start_capture(struct crystalhd_hw
*hw
)
2217 struct crystalhd_rx_dma_pkt
*rx_pkt
;
2222 BCMLOG_ERR("Invalid Arguments\n");
2223 return BC_STS_INV_ARG
;
2226 /* This is start of capture.. Post to both the lists.. */
2227 for (i
= 0; i
< DMA_ENGINE_CNT
; i
++) {
2228 rx_pkt
= crystalhd_dioq_fetch(hw
->rx_freeq
);
2230 return BC_STS_NO_DATA
;
2231 sts
= crystalhd_hw_post_cap_buff(hw
, rx_pkt
);
2232 if (BC_STS_SUCCESS
!= sts
)
2237 return BC_STS_SUCCESS
;
2240 enum BC_STATUS
crystalhd_hw_stop_capture(struct crystalhd_hw
*hw
)
2245 BCMLOG_ERR("Invalid Arguments\n");
2246 return BC_STS_INV_ARG
;
2249 crystalhd_stop_rx_dma_engine(hw
);
2252 temp
= crystalhd_dioq_fetch(hw
->rx_freeq
);
2254 crystalhd_rx_pkt_rel_call_back(hw
, temp
);
2257 return BC_STS_SUCCESS
;
2260 enum BC_STATUS
crystalhd_hw_pause(struct crystalhd_hw
*hw
)
2262 hw
->stats
.pause_cnt
++;
2263 hw
->stop_pending
= 1;
2265 if ((hw
->rx_list_sts
[0] == sts_free
) &&
2266 (hw
->rx_list_sts
[1] == sts_free
))
2267 crystalhd_hw_finalize_pause(hw
);
2269 return BC_STS_SUCCESS
;
2272 enum BC_STATUS
crystalhd_hw_unpause(struct crystalhd_hw
*hw
)
2277 hw
->stop_pending
= 0;
2279 aspm
= crystalhd_reg_rd(hw
->adp
, PCIE_DLL_DATA_LINK_CONTROL
);
2280 aspm
&= ~ASPM_L1_ENABLE
;
2281 /* NAREN BCMLOG(BCMLOG_INFO, "aspm off\n"); */
2282 crystalhd_reg_wr(hw
->adp
, PCIE_DLL_DATA_LINK_CONTROL
, aspm
);
2284 sts
= crystalhd_hw_start_capture(hw
);
2288 enum BC_STATUS
crystalhd_hw_suspend(struct crystalhd_hw
*hw
)
2293 BCMLOG_ERR("Invalid Arguments\n");
2294 return BC_STS_INV_ARG
;
2297 sts
= crystalhd_put_ddr2sleep(hw
);
2298 if (sts
!= BC_STS_SUCCESS
) {
2299 BCMLOG_ERR("Failed to Put DDR To Sleep!!\n");
2300 return BC_STS_ERROR
;
2303 if (!crystalhd_stop_device(hw
->adp
)) {
2304 BCMLOG_ERR("Failed to Stop Device!!\n");
2305 return BC_STS_ERROR
;
2308 return BC_STS_SUCCESS
;
2311 void crystalhd_hw_stats(struct crystalhd_hw
*hw
, struct crystalhd_hw_stats
*stats
)
2314 BCMLOG_ERR("Invalid Arguments\n");
2318 /* if called w/NULL stats, its a req to zero out the stats */
2320 memset(&hw
->stats
, 0, sizeof(hw
->stats
));
2324 hw
->stats
.freeq_count
= crystalhd_dioq_count(hw
->rx_freeq
);
2325 hw
->stats
.rdyq_count
= crystalhd_dioq_count(hw
->rx_rdyq
);
2326 memcpy(stats
, &hw
->stats
, sizeof(*stats
));
2329 enum BC_STATUS
crystalhd_hw_set_core_clock(struct crystalhd_hw
*hw
)
2332 uint32_t vco_mg
, refresh_reg
;
2335 BCMLOG_ERR("Invalid Arguments\n");
2336 return BC_STS_INV_ARG
;
2339 /* FIXME: jarod: wha? */
2340 /*n = (hw->core_clock_mhz * 3) / 20 + 1; */
2341 n
= hw
->core_clock_mhz
/5;
2343 if (n
== hw
->prev_n
)
2344 return BC_STS_CLK_NOCHG
;
2346 if (hw
->pwr_lock
> 0) {
2347 /* BCMLOG(BCMLOG_INFO,"pwr_lock is %u\n", hw->pwr_lock) */
2348 return BC_STS_CLK_NOCHG
;
2361 reg
= bc_dec_reg_rd(hw
->adp
, DecHt_PllACtl
);
2365 reg
|= vco_mg
<< 12;
2367 BCMLOG(BCMLOG_INFO
, "clock is moving to %d with n %d with vco_mg %d\n",
2368 hw
->core_clock_mhz
, n
, vco_mg
);
2370 /* Change the DRAM refresh rate to accommodate the new frequency */
2371 /* refresh reg = ((refresh_rate * clock_rate)/16) - 1; rounding up*/
2372 refresh_reg
= (7 * hw
->core_clock_mhz
/ 16);
2373 bc_dec_reg_wr(hw
->adp
, SDRAM_REF_PARAM
, ((1 << 12) | refresh_reg
));
2375 bc_dec_reg_wr(hw
->adp
, DecHt_PllACtl
, reg
);
2379 for (i
= 0; i
< 10; i
++) {
2380 reg
= bc_dec_reg_rd(hw
->adp
, DecHt_PllACtl
);
2382 if (reg
& 0x00020000) {
2384 /* FIXME: jarod: outputting a random "C" is... confusing... */
2385 BCMLOG(BCMLOG_INFO
, "C");
2386 return BC_STS_SUCCESS
;
2388 msleep_interruptible(10);
2391 BCMLOG(BCMLOG_INFO
, "clk change failed\n");
2392 return BC_STS_CLK_NOCHG
;