SPRUGR9H November   2010  – April 2015 66AK2E05 , 66AK2H06 , 66AK2H12 , 66AK2H14 , 66AK2L06 , AM5K2E02 , AM5K2E04 , SM320C6678-HIREL , TMS320C6652 , TMS320C6654 , TMS320C6655 , TMS320C6657 , TMS320C6670 , TMS320C6671 , TMS320C6672 , TMS320C6674 , TMS320C6678

 

  1.   Preface
    1.     About This Manual
    2.     Trademarks
    3.     Notational Conventions
    4.     Related Documentation from Texas Instruments
  2. 1Introduction
    1. 1.1  Terminology Used in This Document
    2. 1.2  KeyStone I Features
    3. 1.3  KeyStone I Functional Block Diagram
    4. 1.4  KeyStone II Changes to QMSS
    5. 1.5  KeyStone II QMSS Modes of Use
      1. 1.5.1 Shared Mode
      2. 1.5.2 Split Mode
    6. 1.6  Overview
    7. 1.7  Queue Manager
    8. 1.8  Packet DMA (PKTDMA)
    9. 1.9  Navigator Cloud
    10. 1.10 Virtualization
    11. 1.11 ARM-DSP Shared Use
    12. 1.12 PDSP Firmware
  3. 2Operational Concepts
    1. 2.1 Packets
    2. 2.2 Queues
      1. 2.2.1 Packet Queuing
      2. 2.2.2 Packet De-queuing
      3. 2.2.3 Queue Proxy
    3. 2.3 Queue Types
      1. 2.3.1 Transmit Queues
      2. 2.3.2 Transmit Completion Queues
      3. 2.3.3 Receive Queues
      4. 2.3.4 Free Descriptor Queues (FDQ)
        1. 2.3.4.1 Host Packet Free Descriptors
        2. 2.3.4.2 Monolithic Free Descriptors
      5. 2.3.5 Queue Pend Queues
    4. 2.4 Descriptors
      1. 2.4.1 Host Packet
      2. 2.4.2 Host Buffer
      3. 2.4.3 Monolithic Packet
    5. 2.5 Packet DMA
      1. 2.5.1 Channels
      2. 2.5.2 RX Flows
    6. 2.6 Packet Transmission Overview
    7. 2.7 Packet Reception Overview
    8. 2.8 ARM Endianess
  4. 3Descriptor Layouts
    1. 3.1 Host Packet Descriptor
    2. 3.2 Host Buffer Descriptor
    3. 3.3 Monolithic Descriptor
  5. 4Registers
    1. 4.1 Queue Manager
      1. 4.1.1 Queue Configuration Region
        1. 4.1.1.1 Revision Register (0x00000000)
        2. 4.1.1.2 Queue Diversion Register (0x00000008)
        3. 4.1.1.3 Linking RAM Region 0 Base Address Register (0x0000000C)
        4. 4.1.1.4 Linking RAM Region 0 Size Register (0x00000010)
        5. 4.1.1.5 Linking RAM Region 1 Base Address Register (0x00000014)
        6. 4.1.1.6 Free Descriptor/Buffer Starvation Count Register N (0x00000020 + N×4)
      2. 4.1.2 Queue Status RAM
      3. 4.1.3 Descriptor Memory Setup Region
        1. 4.1.3.1 Memory Region R Base Address Register (0x00000000 + 16×R)
        2. 4.1.3.2 Memory Region R Start Index Register (0x00000004 + 16×R)
        3. 4.1.3.3 Memory Region R Descriptor Setup Register (0x00000008 + 16×R)
      4. 4.1.4 Queue Management/Queue Proxy Regions
        1. 4.1.4.1 Queue N Register A (0x00000000 + 16×N)
        2. 4.1.4.2 Queue N Register B (0x00000004 + 16×N)
        3. 4.1.4.3 Queue N Register C (0x00000008 + 16×N)
        4. 4.1.4.4 Queue N Register D (0x0000000C + 16×N)
      5. 4.1.5 Queue Peek Region
        1. 4.1.5.1 Queue N Status and Configuration Register A (0x00000000 + 16×N)
        2. 4.1.5.2 Queue N Status and Configuration Register B (0x00000004 + 16×N)
        3. 4.1.5.3 Queue N Status and Configuration Register C (0x00000008 + 16×N)
        4. 4.1.5.4 Queue N Status and Configuration Register D (0x0000000C + 16×N)
    2. 4.2 Packet DMA
      1. 4.2.1 Global Control Registers Region
        1. 4.2.1.1 Revision Register (0x00)
        2. 4.2.1.2 Performance Control Register (0x04)
        3. 4.2.1.3 Emulation Control Register (0x08)
        4. 4.2.1.4 Priority Control Register (0x0C)
        5. 4.2.1.5 QMn Base Address Register (0x10, 0x14, 0x18, 0x1c)
      2. 4.2.2 TX DMA Channel Configuration Region
        1. 4.2.2.1 TX Channel N Global Configuration Register A (0x000 + 32×N)
        2. 4.2.2.2 TX Channel N Global Configuration Register B (0x004 + 32×N)
      3. 4.2.3 RX DMA Channel Configuration Region
        1. 4.2.3.1 RX Channel N Global Configuration Register A (0x000 + 32×N)
      4. 4.2.4 RX DMA Flow Configuration Region
        1. 4.2.4.1 RX Flow N Configuration Register A (0x000 + 32×N)
        2. 4.2.4.2 RX Flow N Configuration Register B (0x004 + 32×N)
        3. 4.2.4.3 RX Flow N Configuration Register C (0x008 + 32×N)
        4. 4.2.4.4 RX Flow N Configuration Register D (0x00C + 32×N)
        5. 4.2.4.5 RX Flow N Configuration Register E (0x010 + 32×N)
        6. 4.2.4.6 RX Flow N Configuration Register F (0x014 + 32×N)
        7. 4.2.4.7 RX Flow N Configuration Register G (0x018 + 32×N)
        8. 4.2.4.8 RX Flow N Configuration Register H (0x01C + 32×N)
      5. 4.2.5 TX Scheduler Configuration Region
        1. 4.2.5.1 TX Channel N Scheduler Configuration Register (0x000 + 4×N)
    3. 4.3 QMSS PDSPs
      1. 4.3.1 Descriptor Accumulation Firmware
        1. 4.3.1.1 Command Buffer Interface
        2. 4.3.1.2 Global Timer Command Interface
        3. 4.3.1.3 Reclamation Queue Command Interface
        4. 4.3.1.4 Queue Diversion Command Interface
      2. 4.3.2 Quality of Service Firmware
        1. 4.3.2.1 QoS Algorithms
          1. 4.3.2.1.1 Modified Token Bucket Algorithm
        2. 4.3.2.2 Command Buffer Interface
        3. 4.3.2.3 QoS Firmware Commands
        4. 4.3.2.4 QoS Queue Record
        5. 4.3.2.5 QoS Cluster Record
        6. 4.3.2.6 RR-Mode QoS Cluster Record
        7. 4.3.2.7 SRIO Queue Monitoring
          1. 4.3.2.7.1 QoS SRIO Queue Monitoring Record
      3. 4.3.3 Open Event Machine Firmware
      4. 4.3.4 Interrupt Operation
        1. 4.3.4.1 Interrupt Handshaking
        2. 4.3.4.2 Interrupt Processing
        3. 4.3.4.3 Interrupt Generation
        4. 4.3.4.4 Stall Avoidance
      5. 4.3.5 QMSS PDSP Registers
        1. 4.3.5.1 Control Register (0x00000000)
        2. 4.3.5.2 Status Register (0x00000004)
        3. 4.3.5.3 Cycle Count Register (0x0000000C)
        4. 4.3.5.4 Stall Count Register (0x00000010)
    4. 4.4 QMSS Interrupt Distributor
      1. 4.4.1 INTD Register Region
        1. 4.4.1.1  Revision Register (0x00000000)
        2. 4.4.1.2  End Of Interrupt (EOI) Register (0x00000010)
        3. 4.4.1.3  Status Register 0 (0x00000200)
        4. 4.4.1.4  Status Register 1 (0x00000204)
        5. 4.4.1.5  Status Register 2 (0x00000208)
        6. 4.4.1.6  Status Register 3 (0x0000020c)
        7. 4.4.1.7  Status Register 4 (0x00000210)
        8. 4.4.1.8  Status Clear Register 0 (0x00000280)
        9. 4.4.1.9  Status Clear Register 1 (0x00000284)
        10. 4.4.1.10 Status Clear Register 4 (0x00000290)
        11. 4.4.1.11 Interrupt N Count Register (0x00000300 + 4xN)
  6. 5Mapping Information
    1. 5.1 Queue Maps
    2. 5.2 Interrupt Maps
      1. 5.2.1 KeyStone I TCI661x, C6670, C665x devices
      2. 5.2.2 KeyStone I TCI660x, C667x devices
      3. 5.2.3 KeyStone II devices
    3. 5.3 Memory Maps
      1. 5.3.1 QMSS Register Memory Map
      2. 5.3.2 KeyStone I PKTDMA Register Memory Map
      3. 5.3.3 KeyStone II PKTDMA Register Memory Map
    4. 5.4 Packet DMA Channel Map
  7. 6Programming Information
    1. 6.1 Programming Considerations
      1. 6.1.1 System Planning
      2. 6.1.2 Notification of Completed Work
    2. 6.2 Example Code
      1. 6.2.1 QMSS Initialization
      2. 6.2.2 PKTDMA Initialization
      3. 6.2.3 Normal Infrastructure DMA with Accumulation
      4. 6.2.4 Bypass Infrastructure notification with Accumulation
      5. 6.2.5 Channel Teardown
    3. 6.3 Programming Overrides
    4. 6.4 Programming Errors
    5. 6.5 Questions and Answers
  8. AExample Code Utility Functions
  9. BExample Code Types
  10. CExample Code Addresses
    1. C.1 KeyStone I Addresses:
    2. C.2 KeyStone II Addresses:
  11.   Revision History

Example Code Utility Functions

The following functions are simple, low-level utility functions that directly program the necessary Multicore Navigator hardware registers. The addresses and other types are listed in the following appendices.

/* This function programs a QM memory region. */ void set_memory_region(Uint16 regn, Uint32 addr, Uint32 indx, Uint32 setup) { Uint32 *reg; reg = (Uint32 *)(QM_DESC_REGION + QM_REG_MEM_REGION_BASE + (regn * 16)); *reg = addr; reg = (Uint32 *)(QM_DESC_REGION + QM_REG_MEM_REGION_INDEX + (regn * 16)); *reg = indx; /* See register description for programming values. */ reg = (Uint32 *)(QM_DESC_REGION + QM_REG_MEM_REGION_SETUP + (regn * 16)); *reg = setup; } /* This function programs a QM Link RAM. */ void set_link_ram(Uint16 ram, Uint32 addr, Uint32 count) { Uint32 *reg; reg = (Uint32 *)(QM_CTRL_REGION + QM_REG_LINKRAM_0_BASE + (ram * 8)); *reg = addr; if (ram == 0) { reg = (Uint32 *)(QM_CTRL_REGION + QM_REG_LINKRAM_0_SIZE); *reg = count; } } /* This function pushes descriptor info to a queue. * mode parameter: 1 = write reg D only. * 2 = write regs C and D. * * It turns out the VBUSM is more efficient to push to than VBUSP, * and also allows for atomic c+d pushes. */ void push_queue(Uint16 qn, Uint8 mode, Uint32 c_val, Uint32 d_val) { #ifdef USE_VBUSM if (mode == 2) { uint64_t *reg; reg = (uint64_t *)(QM_QMAN_VBUSM_REGION + QM_REG_QUE_REG_C + (qn * 16)); #ifdef _BIG_ENDIAN *reg = ((uint64_t)c_val << 32) | d_val; #else *reg = ((uint64_t)d_val << 32) | c_val; #endif } else { Uint32 *reg; reg = (Uint32 *)(QM_QMAN_VBUSM_REGION + QM_REG_QUE_REG_D + (qn * 16)); *reg = d_val; } #else Uint32 *reg; if (mode == 2) { reg = (Uint32 *)(QM_QMAN_REGION + QM_REG_QUE_REG_C + (qn * 16)); *reg = c_val; } reg = (Uint32 *)(QM_QMAN_REGION + QM_REG_QUE_REG_D + (qn * 16)); *reg = d_val; #endif } /* This function pops a descriptor address from a queue. */ Uint32 pop_queue(Uint16 qn) { Uint32 *reg; Uint32 value; reg = (Uint32 *)(QM_QMAN_REGION + QM_REG_QUE_REG_D + (qn * 16)); value = *reg; return(value); } /* This function moves a source queue to a destination queue. If * headtail = 0, the source queue is appended to the tail of the * dest queue. If 1, it is appended at the head. */ void divert_queue(Uint16 src_qn, Uint16 dest_qn, Uint8 headtail) { Uint32 *reg; Uint32 value; reg = (Uint32 *)(QM_CTRL_REGION + QM_REG_QUE_DIVERSION); value = (headtail << 31) + (dest_qn << 16) + src_qn; *reg = value; return; } /* This function pops a queue until it is empty. If *list is not NULL, * it will return the list of descriptor addresses and the count. */ void empty_queue(Uint16 qn, Uint32 *list, Uint32 *listCount) { Uint32 *reg; Uint32 value; Uint16 idx; Uint32 count; reg = (Uint32 *)(QM_PEEK_REGION + QM_REG_QUE_REG_A + (qn * 16)); count = *reg; //read the descriptor count *listCount = count; reg = (Uint32 *)(QM_QMAN_REGION + QM_REG_QUE_REG_D + (qn * 16)); for (idx = 0; idx < count; idx ++) { value = *reg; if (list != NULL) { list[idx] = value; } } } /* This function returns the byte count of a queue. */ Uint32 get_byte_count(Uint16 qn) { Uint32 *reg; Uint32 count; reg = (Uint32 *)(QM_PEEK_REGION + QM_REG_QUE_REG_B + (qn * 16)); count = *reg; return(count); } /* This function returns the descriptor count of a queue. */ Uint32 get_descriptor_count(Uint16 qn) { Uint32 *reg; Uint32 count; reg = (Uint32 *)(QM_PEEK_REGION + QM_REG_QUE_REG_A + (qn * 16)); count = *reg; return(count); } /* This function sets a queue threshold for queue monitoring purposes. */ void set_queue_threshold(Uint16 qn, Uint32 value) { Uint32 *reg; reg = (Uint32 *)(QM_PEEK_REGION + QM_REG_QUE_STATUS_REG_D + (qn * 16)); *reg = value; } /* This function programs a Hi or Lo Accumulator channel. */ void program_accumulator(Uint16 pdsp, Qmss_AccCmd *cmd) { Uint16 idx; Uint32 *tmplist; Uint32 *reg; if (pdsp == 1) reg = (Uint32 *)(PDSP1_CMD_REGION + 4*4); //point to last word else reg = (Uint32 *)(PDSP2_CMD_REGION + 4*4); //point to last word tmplist = ((uint32_t *) cmd) + 4; //write first word last for (idx = 0; idx < 5; idx ++) { *reg-- = *tmplist--; } /* wait for the command byte to clear. */ reg++; do { result = (*reg & 0x0000ff00) >> 8; } while (result != 0); } /* This function disables a Hi or Lo Accumulator program. */ void disable_accumulator(Uint16 pdsp, Uint16 channel) { Uint16 idx; Uint32 *tmplist; Uint32 *reg; Qmss_AccCmd cmd; memset(&cmd, 0, sizeof(Qmss_AccCmd)); cmd.channel = channel; cmd.command = QMSS_ACC_CMD_DISABLE; if (pdsp == 1) reg = (Uint32 *)(PDSP1_CMD_REGION + 4*4); //point to last word else reg = (Uint32 *)(PDSP2_CMD_REGION + 4*4); //point to last word tmplist = ((uint32_t *) &cmd) + 4; //write first word last for (idx = 0; idx < 5; idx ++) { *reg-- = *tmplist--; } } /* This function writes a new value to a PDSP's firmware * Time is specified in usec, then converted to the hardware * expect value assuming a 350Mhz QMSS sub-system clock. */ void set_firmware_timer(Uint16 pdsp, Uint16 time) { Uint16 idx; Uint32 *tmplist; Uint32 *reg; Qmss_AccCmd cmd; memset(&cmd, 0, sizeof(Qmss_AccCmd)); cmd.queue_mask = (time * 175); //convert usec to hw val cmd.command = QMSS_ACC_CMD_TIMER; if (pdsp == 1) reg = (Uint32 *)(PDSP1_CMD_REGION + 4); //point to 2nd word else reg = (Uint32 *)(PDSP2_CMD_REGION + 4); //point to 2nd word tmplist = ((uint32_t *) &cmd) + 1; //write 2nd word last *reg-- = *tmplist--; *reg = *tmplist; } /* This function programs base addresses for the four logical * queue managers that a PKTDMA may setup. Use a value of 0xffff * if you don't want to set value into QM base addr reg. N. */ void config_pktdma_qm(Uint32 base, Uint16 *physical_qnum) { Uint16 idx; Uint32 qm_base; Uint32 *reg; for (idx = 0; idx < 4; idx ++) { if (physical_qnum[idx] != 0xffff) { qm_base = QM_QMAN_VBUSM_REGION + (physical_qnum[idx] * 16); reg = (Uint32 *)(base + PKTDMA_REG_QM0_BASE_ADDR + (idx * 4)); *reg = qm_base; } } } /* This function enables/disables internal loopback mode for a pktDMA. * By default, it should be enabled for QMSS, disabled for all others. */ void config_pktdma_loopback(Uint32 base, Uint8 enable) { Uint32 *reg; reg = (Uint32 *)(base + PKTDMA_REG_EMULATION_CTRL); if (enable) *reg = 0x80000000; else *reg = 0x0; } /* This function sets the packet retry timeout. * A value of 0 disables the retry feature. */ void config_pktdma_retry_timeout(Uint32 base, Uint16 timeout) { Uint32 *reg; Uint32 val; reg = (Uint32 *)(base + PKTDMA_REG_PERFORMANCE_CTRL); val = *reg & 0xFFFF0000; *reg = val | timeout; } /* This function disables a TX DMA channel, then configures it. */ void config_tx_chan(Uint32 base, Uint16 chan, Uint32 return_q) { Uint32 *reg; reg = (Uint32 *)(base + PKTDMA_REG_TX_CHAN_CFG_A + (chan * 32)); *reg = 0; //disable the channel reg = (Uint32 *)(base + PKTDMA_REG_TX_CHAN_CFG_B + (chan * 32)); *reg = return_q; } /* This function configures priority of a TX DMA channel */ void config_tx_sched(Uint32 base, Uint16 chan, Uint32 priority) { Uint32 *reg; reg = (Uint32 *)(base + PKTDMA_REG_TX_SCHED_CHAN_CFG + (chan * 4)); *reg = priority; } /* This function configures an RX DMA channel flow. */ void config_rx_flow(Uint32 base, Uint16 flow, Uint32 a, Uint32 b, Uint32 c, Uint32 d, Uint32 e, Uint32 f, Uint32 g, Uint32 h) { Uint32 *reg; reg = (Uint32 *)(base + PKTDMA_REG_RX_FLOW_CFG_A + (flow * 32)); *reg = a; reg = (Uint32 *)(base + PKTDMA_REG_RX_FLOW_CFG_B + (flow * 32)); *reg = b; reg = (Uint32 *)(base + PKTDMA_REG_RX_FLOW_CFG_C + (flow * 32)); *reg = c; reg = (Uint32 *)(base + PKTDMA_REG_RX_FLOW_CFG_D + (flow * 32)); *reg = d; reg = (Uint32 *)(base + PKTDMA_REG_RX_FLOW_CFG_E + (flow * 32)); *reg = e; reg = (Uint32 *)(base + PKTDMA_REG_RX_FLOW_CFG_F + (flow * 32)); *reg = f; reg = (Uint32 *)(base + PKTDMA_REG_RX_FLOW_CFG_G + (flow * 32)); *reg = g; reg = (Uint32 *)(base + PKTDMA_REG_RX_FLOW_CFG_H + (flow * 32)); *reg = h; } /* This function writes an RX DMA channel's enable register. */ void enable_rx_chan(Uint32 base, Uint16 chan, Uint32 value) { Uint32 *reg; reg = (Uint32 *)(base + PKTDMA_REG_RX_CHAN_CFG_A + (chan * 32)); *reg = value; } /* This function writes a TX DMA channel's enable register. */ void enable_tx_chan(Uint32 base, Uint16 chan, Uint32 value) { Uint32 *reg; reg = (Uint32 *)(base + PKTDMA_REG_TX_CHAN_CFG_A + (chan * 32)); *reg = value; } /* This function reads a QMSS INTD Status Register. * group parameter: 0 = high priority interrupts. * 1 = low priority interrupts. * 4 = PKTDMA starvation interrupts. * * If the chan parameter = 0xffffffff, the entire register contents * are returned. Otherwise, chan is expected to be a channel number, * and the return value will be a 0 or 1 for that channel's status. */ Uint32 read_status(Uint16 group, Uint32 chan) { Uint32 *reg; Uint32 value; Uint32 mask; reg = (Uint32 *)(QM_INTD_REGION + QM_REG_INTD_STATUS + (group * 4)); value = *reg; if (chan != 0xffffffff) { mask = 1 << (chan & 0x001f); if ((value & mask) == 0) value = 0; else value = 1; } return(value); } /* This function writes a QMSS INTD Status Register. * group parameter: 0 = high priority interrupts. * 1 = low priority interrupts. * 4 = PKTDMA starvation interrupts. */ void set_status(Uint16 group, Uint32 chan) { Uint32 *reg; Uint32 value; Uint32 mask; reg = (Uint32 *)(QM_INTD_REGION + QM_REG_INTD_STATUS + (group * 4)); value = *reg; mask = 1 << (chan & 0x001f); value |= mask; *reg = value; } /* This function writes a QMSS INTD Status Clear Register. * group parameter: 0 = high priority interrupts. * 1 = low priority interrupts. * 4 = PKTDMA starvation interrupts. */ void clear_status(Uint16 group, Uint32 chan) { Uint32 *reg; Uint32 value; Uint32 mask; reg = (Uint32 *)(QM_INTD_REGION + QM_REG_INTD_STATUS_CLEAR + (group * 4)); value = *reg; mask = 1 << (chan & 0x001f); value |= mask; *reg = value; } /* This function reads a QMSS INTD Int Count Register. * Reading has no effect on the register. * "intnum" is: 0..31 for High Pri interrupts * 32..47 for Low Pri interrupts * 48..49 for PKTDMA Starvation interrupts */ Uint32 read_intcount(Uint16 intnum) { Uint32 *reg; Uint32 value; reg = (Uint32 *)(QM_INTD_REGION + QM_REG_INTD_INT_COUNT + (intnum * 4)); value = *reg; return(value); } /* This function reads a QMSS INTD Int Count Register. * Writing will cause the written value to be subtracted from the register. * "intnum" is: 0..31 for High Pri interrupts * 32..47 for Low Pri interrupts * 48..49 for PKTDMA Starvation interrupts */ void write_intcount(Uint16 intnum, Uint32 val) { Uint32 *reg; reg = (Uint32 *)(QM_INTD_REGION + QM_REG_INTD_INT_COUNT + (intnum * 4)); *reg = val; } /* This function writes a QMSS INTD EOI Register. Values to write are: 0 or 1: PKTDMA starvation interrupts, 2 to 33: High Pri interrupts, 34 to 49: Low Pri interrupts. * Writing one of these values will clear the corresponding interrupt. */ void write_eoi(Uint32 val) { Uint32 *reg; reg = (Uint32 *)(QM_INTD_REGION + QM_REG_INTD_EOI); *reg = val; } /* This function writes a QMSS PDSP Control Register. */ void pdsp_control(Uint16 pdsp, Uint32 val) { Uint32 *reg; if (pdsp == 1) reg = (Uint32 *)(PDSP1_REG_REGION + QM_REG_PDSP_CONTROL); else reg = (Uint32 *)(PDSP2_REG_REGION + QM_REG_PDSP_CONTROL); *reg = val; } /* This function enables QMSS PDSP n. */ void pdsp_enable(Uint16 pdsp) { Uint32 *reg; Uint32 tmp; if (pdsp == 1) reg = (Uint32 *)(PDSP1_REG_REGION + QM_REG_PDSP_CONTROL); else reg = (Uint32 *)(PDSP2_REG_REGION + QM_REG_PDSP_CONTROL); tmp = *reg; tmp |= 0x02; *reg = tmp; } /* This function disables QMSS PDSP n. */ void pdsp_disable(Uint16 pdsp) { Uint32 *reg; Uint32 tmp; if (pdsp == 1) reg = (Uint32 *)(PDSP1_REG_REGION + QM_REG_PDSP_CONTROL); else reg = (Uint32 *)(PDSP2_REG_REGION + QM_REG_PDSP_CONTROL); tmp = *reg; tmp &= 0xfffffffd; *reg = tmp; } /* This function returns true if QMSS PDSP n is running. */ Uint8 pdsp_running(Uint16 pdsp) { Uint32 *reg; if (pdsp == 1) reg = (Uint32 *)(PDSP1_REG_REGION + QM_REG_PDSP_CONTROL); else reg = (Uint32 *)(PDSP2_REG_REGION + QM_REG_PDSP_CONTROL); return(*reg & 0x00008000); } /* This function controls the PDSP to load firmware to it. */ void pdsp_download_firmware(Uint16 pdsp, Uint8 *code, Uint32 size) { Uint16 idx; Uint32 value; Uint32 *reg; /* Reset PDSP 1 */ pdsp_disable(pdsp); /* Confirm PDSP has halted */ do { value = pdsp_running(pdsp); } while (value == 1); /* Download the firmware */ if (pdsp == 1) memcpy ((void *)PDSP1_IRAM_REGION, code, size); else memcpy ((void *)PDSP2_IRAM_REGION, code, size); /* Use the command register to sync the PDSP */ if (pdsp == 1) reg = (Uint32 *)(PDSP1_CMD_REGION); else reg = (Uint32 *)(PDSP2_CMD_REGION); *reg = 0xffffffff; /* Wait to the memory write to land */ for (idx = 0; idx < 20000; idx++) { value = *reg; if (value == 0xffffffff) break; } /* Reset program counter to zero, and clear Soft Reset bit. */ if (pdsp == 1) reg = (Uint32 *)(PDSP1_REG_REGION + QM_REG_PDSP_CONTROL); else reg = (Uint32 *)(PDSP2_REG_REGION + QM_REG_PDSP_CONTROL); value = *reg; *reg = value & 0x0000fffe; //PC reset is in upper 16 bits, soft reset in bit 0 /* Enable the PDSP */ pdsp_enable(pdsp); /* Wait for the command register to clear */ if (pdsp == 1) reg = (Uint32 *)(PDSP1_CMD_REGION); else reg = (Uint32 *)(PDSP2_CMD_REGION); do { value = *reg; } while (value != 0); }