source: trunk/tools/bootloader_tsar/boot_hba_driver.c @ 278

Last change on this file since 278 was 6, checked in by alain, 8 years ago

Modify the boot_info_t struct to describe external peripherals in all clusters.

File size: 8.2 KB
Line 
1///////////////////////////////////////////////////////////////////////////////////
2// File     : boot_hba_driver.c
3// Date     : 18/01/2017
4// Author   : Alain Greiner / Vu Son
5// Copyright (c) UPMC-LIP6
6///////////////////////////////////////////////////////////////////////////////////
7
8#include <boot_config.h>
9#include <hard_config.h>
10#include <boot_hba_driver.h>
11#include <boot_mmc_driver.h>
12#include <boot_utils.h>
13
14#ifndef SEG_IOC_BASE
15# error "The SEG_IOC_BASE value should be defined in the 'hard_config.h' file"
16#endif
17
18#ifndef Y_IO
19# error "The Y_IO value should be defined in the 'hard_config.h' file"
20#endif
21
22#ifndef X_IO
23# error "The X_IO value should be defined in the 'hard_config.h' file"
24#endif
25
26#ifndef Y_WIDTH
27# error "The Y_WIDTH value should be defined in the 'hard_config.h' file"
28#endif
29
30
31/****************************************************************************
32 *                              Global variables.                           *
33 ****************************************************************************/
34
35uint32_t    hba_allocated_cmd[32];  /* State of each command slot (0 if
36                                           slot is available for use).      */
37
38hba_cmd_desc_t  hba_cmd_list[32]        /* Command List (up to 32
39                                           commands).                       */
40__attribute__((aligned(0x40)));
41
42hba_cmd_table_t hba_cmd_table[32]       /* Command Tables array (one
43                                           Command Table for each Command
44                                           List entry).                     */
45__attribute__((aligned(0x40)));
46
47/****************************************************************************
48 *                            Internal functions.                           *
49 ****************************************************************************/
50
51/****************************************************************************
52 * This function returns the value of an  HBA register.                     *
53 * @ reg    : HBA register to be read.                                      *
54 * @ returns the value stored in reg.                                     *
55 ****************************************************************************/
56static uint32_t boot_hba_get_register(uint32_t reg)
57{
58    cxy_t      cxy = (X_IO << Y_WIDTH) + Y_IO;
59    uint32_t * ptr = (uint32_t *)SEG_IOC_BASE + reg;
60   
61    return boot_remote_lw( XPTR( cxy , ptr ) ); 
62
63} // boot_hba_get_register()
64
65/****************************************************************************
66 * This function sets a new value to an HBA register.                       *
67 * @ reg    : HBA register to be configured.                                *
68 * @ val    : new value to be written to 'reg'.                             *
69 ****************************************************************************/
70void boot_hba_set_register(uint32_t reg, uint32_t val)
71{
72    cxy_t      cxy = (X_IO << Y_WIDTH) + Y_IO;
73    uint32_t * ptr = (uint32_t *)SEG_IOC_BASE + reg;
74
75    boot_remote_sw( XPTR( cxy , ptr ) , val ); 
76
77} // boot_hba_set_register()
78
79/****************************************************************************
80 * This function allocates an unused command index.                         *
81 * @ returns command index (0 to 31) / returns -1 if not found              *
82 ****************************************************************************/
83static int boot_hba_cmd_alloc()
84{
85    uint32_t i;
86    uint32_t cmd_id;
87
88    // loop on the state array to find an unused slot
89    cmd_id = -1;
90    for (i = 0; i < 32; i++)
91    {
92        if (hba_allocated_cmd[i] == 0)
93        {
94            cmd_id = i;
95            break;
96        }
97    }
98
99    return cmd_id;
100
101} // boot_hba_cmd_alloc()
102
103/****************************************************************************
104 * This function releases the 'cmd_id' command index by resetting its       *
105 * corresponding entry in the state array.                                  *
106 * @ returns 0 on success, -1 on error.                                     *
107 ****************************************************************************/
108static int boot_hba_cmd_release(uint32_t cmd_id)
109{
110    // check slot allocated
111    if (hba_allocated_cmd[cmd_id] == 0)
112    {
113        boot_printf("\n[BOOT ERROR] boot_hba_cmd_release(): "
114                    "Command %d to be released is not allocated\n",
115                    cmd_id
116                   );
117        return -1;
118    }
119
120    // Reset entry in state array
121    hba_allocated_cmd[cmd_id] = 0;
122
123    return 0;
124}
125
126/****************************************************************************
127 *                            Driver API functions.                         *
128 ****************************************************************************/
129
130///////////////////
131int boot_hba_init()
132{
133    uint64_t cmd_table_addr;  // Command Table physical base address
134    uint64_t cmd_list_addr;   // Command List physical base address
135    uint64_t paddr;           // Command Table physical address
136    uint32_t i;               // Iterator for the initialization loop
137
138    /* Getting the Command List and Command Table base addresses. */
139    cmd_table_addr = (uint64_t)(intptr_t)&hba_cmd_table[0];
140    cmd_list_addr  = (uint64_t)(intptr_t)&hba_cmd_list[0];
141
142    /* Initializing the Command List. */
143    for (i = 0; i < 32; i++)
144    {
145        paddr = cmd_table_addr + i * sizeof(hba_cmd_table_t);
146        hba_cmd_list[i].ctba  = (uint32_t)paddr;
147        hba_cmd_list[i].ctbau = (uint32_t)(paddr >> 32);
148        hba_allocated_cmd[i]  = 0;
149    }
150
151    /* Initializing the HBA registers. */
152    boot_hba_set_register( HBA_PXCLB , (uint32_t)cmd_list_addr );
153    boot_hba_set_register( HBA_PXCLBU, (uint32_t)(cmd_list_addr >> 32) );
154    boot_hba_set_register( HBA_PXIS  , 0 );
155    boot_hba_set_register( HBA_PXIE  , 0 );
156    boot_hba_set_register( HBA_PXCI  , 0 );
157    boot_hba_set_register( HBA_PXCMD , 1 );
158
159    return 0;
160
161} // boot_hba_init()
162
163///////////////////////////////////
164int boot_hba_access( uint32_t  lba,
165                     xptr_t    buf_paddr,
166                     uint32_t  count )
167{
168    uint32_t          cmd_id;     
169    uint32_t          pxci; 
170    uint32_t          pxis;
171    hba_cmd_desc_t  * cmd_desc;
172    hba_cmd_table_t * cmd_table; 
173
174    // get target buffer cluster and pointer
175    cxy_t      buf_cxy = GET_CXY( buf_paddr );
176    uint32_t   buf_ptr = (uint32_t)GET_PTR( buf_paddr );
177
178    // Check buffer address alignment
179    if (buf_ptr & 0x3F)
180    {
181        boot_puts("\n[BOOT ERROR] boot_hba_access(): "
182                  "Buffer address is not cache-line-size-aligned\n");
183        return -1;
184    }
185
186    // Get a free slot in the Command List
187    cmd_id = boot_hba_cmd_alloc();
188
189    // Initialize  pointers
190    cmd_desc  = &hba_cmd_list[cmd_id];
191    cmd_table = &hba_cmd_table[cmd_id];
192
193    // Set the buffer descriptor of the Command Table
194    cmd_table->buffer.dba  = buf_ptr;
195    cmd_table->buffer.dbau = buf_cxy;
196    cmd_table->buffer.dbc  = count * 512;
197
198    // Initialize the Command Table header
199    cmd_table->header.lba0 = (char)lba;
200    cmd_table->header.lba1 = (char)(lba >> 8);
201    cmd_table->header.lba2 = (char)(lba >> 16);
202    cmd_table->header.lba3 = (char)(lba >> 24);
203    cmd_table->header.lba4 = 0;
204    cmd_table->header.lba5 = 0;
205   
206    // Initialize the Command Descriptor
207    cmd_desc->prdtl[0] = 1;
208    cmd_desc->prdtl[1] = 0;
209    cmd_desc->flag[0] = 0x00;
210
211#if USE_IOB    // software L2/L3 cache coherence
212    if( boot_mmc_inval( buf_paddr, count<<9 ) ) return -1;
213#endif
214
215    // Launch  data transfer
216    boot_hba_set_register(HBA_PXCI, (1 << cmd_id));
217
218#if DEBUG_BOOT_IOC
219boot_printf("\n[BOOT] boot_hba_access(): Transfer launched at cycle %d\n"
220            "  lba = %d / buf = %l / nblocks = %d\n",
221            boot_get_proctime() , lba , buf_paddr , count );
222#endif
223
224    // Wait transfer completion
225    do
226    {
227        pxci = boot_hba_get_register(HBA_PXCI);
228
229    } while (pxci & (1 << cmd_id));
230
231    // Get error status then reset it
232    pxis = boot_hba_get_register(HBA_PXIS);
233    boot_hba_set_register(HBA_PXIS, 0);
234
235#if DEBUG_BOOT_IOC
236boot_printf("\n[BOOT] boot_hba_access(): Transfer terminated at cycle %d\n",
237                boot_get_proctime());
238#endif
239
240    if (boot_hba_cmd_release(cmd_id))
241        return -1;
242    else if (pxis & 0x40000000)
243        return pxis;
244    else
245        return 0;
246
247} // boot_hba_access()
Note: See TracBrowser for help on using the repository browser.