Merge pull request #3 in PROCESSOR-SDK/ibl from PRSDK-5675 to master
[keystone-rtos/ibl.git] / src / hw / qm / qm.c
1 /******************************************************************************************
2  * FILE PURPOSE: Boot queue manager driver
3  ******************************************************************************************
4  * FILE NAME: qm.c
5  *
6  * DESCRIPTION: The boot loader queue manager driver. This driver uses a very simple
7  *                              setup on the queue manager, with a single link ram and a single
8  *                              memory region. The descriptors are configured as host descriptors
9  *                              and have the minimum 32 byte size.
10  *
11  *              For the boot driver queue register C is not written. It is important
12  *              to the boot loader if packets are pushed/popped from the head or
13  *              tail of a queue.
14  *
15  ******************************************************************************************/
16 #include "types.h"
17 #include "qm_loc.h"
18 #include "qm_api.h"
19 #include "device.h"
20 #include <string.h>
22 /*******************************************************************************************
23  * FUNCTION PURPOSE: Pop a descriptor off of a queue
24  *******************************************************************************************
25  * DESCRIPTION: The descriptor is read from queue register D.
26  *******************************************************************************************/
27 qmHostDesc_t *hwQmQueuePop (UINT32 qnum)
28 {
29     qmHostDesc_t *hd;
30     UINT32        uhd;
32     /* Strip the descriptor size info */
33     uhd = DEVICE_REG32_R (DEVICE_QM_MANAGER_QUEUES_BASE + QM_REG_QUEUE_REGD(qnum));
34     uhd = uhd & ~0xf;
35     hd  = (qmHostDesc_t *)uhd;
37     return (hd);
38 } /* hwQmQueuePop */
40 /*******************************************************************************************
41  * FUNCTION PURPOSE: Return the number of descriptors on a queue
42  *******************************************************************************************
43  * DESCRIPTION: The queue count is returned
44  *******************************************************************************************/
45 UINT32  hwQmQueueCount (UINT32 qnum)
46 {
47     UINT32 rega;
49     rega = DEVICE_REG32_R (DEVICE_QM_QUEUE_STATUS_BASE + QM_REG_QUEUE_REGA(qnum));
50     rega = BOOT_READ_BITFIELD (rega, QM_QA_ENTRY_COUNT_MSB, QM_QA_ENTRY_COUNT_LSB);
51     return (rega);
53 } /* hwQmQueueCount */
55 /*******************************************************************************************
56  * FUNCTION PURPOSE: Set a queue threshold
57  *******************************************************************************************
58  * DESCRIPTION: The queue threshold is enabled. Only high threshold is set, with a threshold
59  *                              value of 1.
60  *******************************************************************************************/
61 SINT16 hwQmInitThreshold (UINT32 qnum)
62 {
63         DEVICE_REG32_W (DEVICE_QM_QUEUE_STATUS_BASE + QM_REG_STAT_CFG_REGD(qnum), 0x81);
64         
65         return (0);
66         
67 } /* hwQmInitThreshold */       
70 /*******************************************************************************************
71  * FUNCTION PURPOSE: Push a descriptor onto a queue
72  *******************************************************************************************
73  * DESCRIPTION: The descriptor is written to queue register D. No check is made to see
74  *              if the queue number is valid.
75  *******************************************************************************************/
76 void hwQmQueuePush (qmHostDesc_t *hd, UINT32 qnum, UINT32 descrSize)
77 {
78         UINT32 regd;
79         
80         regd = ((UINT32) hd | ((descrSize >> 4) - 1));
81         
82     /* Push the descriptor onto the queue */
83     DEVICE_REG32_W (DEVICE_QM_MANAGER_QUEUES_BASE + QM_REG_QUEUE_REGD(qnum), regd);
85 } /* hwQmQueuePush */
87 /*******************************************************************************************
88  * FILE PURPOSE: Setup the queue manager
89  *******************************************************************************************
90  * DESCRIPTION: The queue manager is setup using a single linking ram and memory region,
91  *              with fixed descriptor initialization.
92  *
93  *              Since the linking ram and descriptor regions are configured, it is assumed
94  *              that all queues are currently empty.
95  *
96  ********************************************************************************************/
97 SINT16 hwQmSetup (qmConfig_t *cfg)
98 {
99     UINT32 v;
100     UINT32 w;
101     UINT32 x;
102     UINT32 i;
103     qmHostDesc_t *hd;
105     /* Verify that alignment requirements */
106     if ( (cfg->linkRamBase & (QM_LINKRAM_ALIGN-1))  !=  0 )
107         return (QM_INVALID_LINKRAM_ALIGNMENT);
109     if ( (cfg->memRegionBase & (QM_MEMR_ALIGN-1))   !=  0 )
110         return (QM_INVALID_MEMREGION_ALIGNMENT);
112     /* Verify linkram sizing is in range */
113     if ( (cfg->linkRamSize & ~QM_REG_LINKRAM_SIZE_MAX_MASK)  != 0 )
114         return (QM_INVALID_LINKRAM_SIZE);
116     /* Verify there is enough linkram to cover the single memory region */ 
117     if (cfg->linkRamSize < cfg->memRegNumDescriptors)
118         return (QM_INVALID_LINKRAM_RAM_SIZE);
121     /* Linking RAM info */
122     DEVICE_REG32_W (DEVICE_QM_MANAGER_BASE + QM_REG_LINKRAM_BASE(0), cfg->linkRamBase);
123     DEVICE_REG32_W (DEVICE_QM_MANAGER_BASE + QM_REG_LINKRAM_SIZE(0), cfg->linkRamSize);
124     DEVICE_REG32_W (DEVICE_QM_MANAGER_BASE + QM_REG_LINKRAM_BASE(1), 0);
126     /* Memory region 0 info */
127     DEVICE_REG32_W (DEVICE_QM_DESC_SETUP_BASE + QM_REG_MEMR_BASE_ADDR(0), cfg->memRegionBase);
128     DEVICE_REG32_W (DEVICE_QM_DESC_SETUP_BASE + QM_REG_MEMR_START_IDX(0), 0);
130     /* Calculate the 2 fields in the descriptor setup register. Bits 0-3 specifiy
131      * the total memory size rounded up to the next higher power of two, and
132      * is expresses as 2^(n - 5). So for example if you have 20 descriptors
133      * The next higher power of 2 that exceeds this is 32, which is 2^5, so the value 0 (5-5)
134      * is placed in this field */
135     v = (31 - chipLmbd (1, cfg->memRegNumDescriptors));
136     if (v >= 4)
137       v = v - 4;
138     else
139       v = 0;
141     /* Add the descriptor size field */
142     QM_REG_VAL_DESC_SETUP_SET_DESC_SIZE(v, QM_DESC_SIZE_BYTES);
144     DEVICE_REG32_W (DEVICE_QM_DESC_SETUP_BASE + QM_REG_MEMR_DESC_SETUP(0), v);
147     /* Now format the descriptors and put them in a queue */
148     for (i = 0, v = cfg->memRegionBase; i < cfg->memRegNumDescriptors; i++, v += QM_DESC_SIZE_BYTES)  {
150         hd = (qmHostDesc_t *)v;
151         memset (hd, 0, sizeof(qmHostDesc_t));
153         hd->descInfo   = QM_DESC_DEFAULT_DESCINFO;
154         hd->packetInfo = QM_DESC_DEFAULT_PINFO;
155         
156         if (QM_DESC_INFO_GET_PSINFO_LOC(hd->descInfo) == QM_DESC_PSINFO_IN_DESCR)  {
157                 if (QM_PKT_INFO_GET_EPIB(hd->packetInfo) == QM_DESC_PINFO_EPIB)
158                         w = QM_DESC_SIZE_BYTES - 32 - 16;  /* 32 bytes min descriptor size, 16 bytes extended info */
159                 else
160                         w = QM_DESC_SIZE_BYTES - 32;
161         }  else
162                 w = 0;
163                 
164         QM_PKT_INFO_SET_PSINFO_SIZE(hd->packetInfo, (w >> 2));
165  
167         /* Push the descriptor onto the queue */
168         x = deviceLocalAddrToGlobal (v);
170         DEVICE_REG32_W (DEVICE_QM_MANAGER_QUEUES_BASE + QM_REG_QUEUE_REGD(cfg->destQ), x);
172     }
174     return (QM_OK);
176 } /* hwQmSetup */
179 /****************************************************************************************
180  * FUNCTION PURPOSE: Disable the QM
181  ****************************************************************************************
182  * DESCRIPTION: The QM is reset by clearing the linking ram and region 0 information
183  ****************************************************************************************/
184 void hwQmTeardown (void)
186     UINT32 i;
188     /* Linking RAM info */
189     for (i = 0; i < DEVICE_QM_NUM_LINKRAMS; i++)  {
190         DEVICE_REG32_W (DEVICE_QM_MANAGER_BASE + QM_REG_LINKRAM_BASE(i), 0);
191         DEVICE_REG32_W (DEVICE_QM_MANAGER_BASE + QM_REG_LINKRAM_SIZE(i), 0);
192     }
194     /* Memory region info */
195     for (i = 0; i < DEVICE_QM_NUM_MEMREGIONS; i++)  {
196         DEVICE_REG32_W (DEVICE_QM_DESC_SETUP_BASE + QM_REG_MEMR_BASE_ADDR(i),  0);
197         DEVICE_REG32_W (DEVICE_QM_DESC_SETUP_BASE + QM_REG_MEMR_START_IDX(i),  0);
198         DEVICE_REG32_W (DEVICE_QM_DESC_SETUP_BASE + QM_REG_MEMR_DESC_SETUP(i), 0);
199     }
201 } /* hwQmTeardown */