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

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

First import

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