root/trunk/libffado/src/rme/fireface_flash.cpp

Revision 1589, 11.2 kB (checked in by jwoithe, 14 years ago)

RME: tidied up software settings structure and removed unused fields.
RME: map configuration flash contents into software settings structure after flash is read.
RME: rename some methods to better reflect their function.
RME: documentation update to reflect the information embodied in these changes.

Line 
1 /*
2  * Copyright (C) 2009 by Jonathan Woithe
3  *
4  * This file is part of FFADO
5  * FFADO = Free Firewire (pro-)audio drivers for linux
6  *
7  * FFADO is based upon FreeBoB.
8  *
9  * This program is free software: you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation, either version 2 of the License, or
12  * (at your option) version 3 of the License.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
21  *
22  */
23
24 /* This file implements the flash memory methods of the Device object */
25
26 #include "rme/rme_avdevice.h"
27 #include "rme/fireface_def.h"
28
29 #include "debugmodule/debugmodule.h"
30
31 #define MAX_FLASH_BUSY_RETRIES    25
32
33 namespace Rme {
34
35 signed int
36 Device::wait_while_busy(unsigned int init_delay_ms)
37 {
38     signed int i;
39     quadlet_t status;
40
41     // Wait for the device to become available for a new command.  A delay
42     // of init_delay_ms is executed prior to each test of the device status.
43     for (i=0; i<MAX_FLASH_BUSY_RETRIES; i++) {
44         usleep(init_delay_ms*1000);
45         if (m_rme_model == RME_MODEL_FIREFACE400) {
46             status = readRegister(RME_FF400_FLASH_STAT_REG);
47             if (status == 0)
48                 break;
49         } else {
50             status = readRegister(RME_FF_STATUS_REG1);
51             if (status & 0x40000000)
52                 break;
53         }
54     }
55
56     if (i == MAX_FLASH_BUSY_RETRIES)
57         return -1;
58     return 0;
59 }
60
61 signed int
62 Device::get_revision(unsigned int *revision)
63 {
64     signed int err = 0;
65
66     if (m_rme_model == RME_MODEL_FIREFACE800) {
67         *revision = readRegister(RME_FF800_REVISION_REG);
68         return 0;
69     }
70
71     err = writeRegister(RME_FF400_FLASH_CMD_REG, RME_FF400_FLASH_CMD_GET_REVISION);
72     err |= wait_while_busy(2);
73     if (!err)
74       *revision = readRegister(RME_FF400_FLASH_READ_BUFFER);
75
76     return err?-1:0;
77 }
78
79 signed int
80 Device::read_flash(fb_nodeaddr_t addr, quadlet_t *buf, unsigned int n_quads)
81 {
82     // Read "n_quads" quadlets from the Fireface Flash starting at address
83     // addr.  The result is written to "buf" which is assumed big enough to
84     // hold the result.  Return 0 on success, -1 on error.  The caller must ensure
85     // that the flash source address makes sense for the device in use.
86
87     unsigned int xfer_size;
88     unsigned int err = 0;
89     quadlet_t block_desc[2];
90     quadlet_t ff400_addr = (addr & 0xffffffff);
91
92     if (m_rme_model == RME_MODEL_FIREFACE800) {
93         return readBlock(addr, buf, n_quads);
94     }
95     // FF400 case follows
96     do {
97         xfer_size = (n_quads > 32)?32:n_quads;
98         block_desc[0] = ff400_addr;
99         block_desc[1] = xfer_size * sizeof(quadlet_t);
100         // Program the read address and size
101         err |= writeBlock(RME_FF400_FLASH_BLOCK_ADDR_REG, block_desc, 2);
102         // Execute the read and wait for its completion
103         err |= writeRegister(RME_FF400_FLASH_CMD_REG, RME_FF400_FLASH_CMD_READ);
104         if (!err)
105             wait_while_busy(2);
106         // Read from bounce buffer into final destination
107         err |= readBlock(RME_FF400_FLASH_READ_BUFFER, buf, xfer_size);
108
109         n_quads -= xfer_size;
110         ff400_addr += xfer_size*sizeof(quadlet_t);
111         buf += xfer_size;
112     } while (n_quads>0 && !err);
113
114     return err?-1:0;
115 }
116
117 signed int
118 Device::erase_flash(unsigned int flags)
119 {
120     // Erase the requested flash block.  "flags" should be one of the
121     // RME_FF_FLASH_ERASE_* flags.  Return 0 on success, -1 on error.
122
123     fb_nodeaddr_t addr;
124     quadlet_t data;
125     unsigned int err = 0;
126
127     if (m_rme_model == RME_MODEL_FIREFACE800) {
128         switch (flags) {
129             case RME_FF_FLASH_ERASE_VOLUME:
130                 addr = RME_FF800_FLASH_ERASE_VOLUME_REG; break;
131             case RME_FF_FLASH_ERASE_SETTINGS:
132                 addr = RME_FF800_FLASH_ERASE_SETTINGS_REG; break;
133             case RME_FF_FLASH_ERASE_CONFIG:
134                 addr = RME_FF800_FLASH_ERASE_CONFIG_REG; break;
135             default:
136                 debugOutput(DEBUG_LEVEL_WARNING, "unknown flag %d\n", flags);
137                 return -1;
138         }
139         data = 0;
140     } else {
141         addr = RME_FF400_FLASH_CMD_REG;
142         switch (flags) {
143             case RME_FF_FLASH_ERASE_VOLUME:
144                 data = RME_FF400_FLASH_CMD_ERASE_VOLUME; break;
145             case RME_FF_FLASH_ERASE_SETTINGS:
146                 data = RME_FF400_FLASH_CMD_ERASE_SETTINGS; break;
147             case RME_FF_FLASH_ERASE_CONFIG:
148                 data = RME_FF400_FLASH_CMD_ERASE_CONFIG; break;
149             default:
150                 debugOutput(DEBUG_LEVEL_WARNING, "unknown flag %d\n", flags);
151                 return -1;
152         }
153     }
154
155     err |= writeRegister(addr, data);
156     if (!err) {
157         wait_while_busy(500);
158         // After the device is ready, wait a further 20 milliseconds.  The purpose
159         // of this is unclear.  Drivers from other OSes do it, so we should too.
160         usleep(20000);
161     }
162
163     return err?-1:0;
164 }
165
166 signed int
167 Device::write_flash(fb_nodeaddr_t addr, quadlet_t *buf, unsigned int n_quads)
168 {
169     // Write "n_quads" quadlets to the Fireface Flash starting at address
170     // addr.  Return 0 on success, -1 on error.  The caller must ensure the
171     // supplied address is appropriate for the device in use.
172
173     unsigned int xfer_size;
174     unsigned int err = 0;
175     quadlet_t block_desc[2];
176     quadlet_t ff400_addr = (addr & 0xffffffff);
177
178     if (m_rme_model == RME_MODEL_FIREFACE800) {
179         err |= readBlock(addr, buf, n_quads);
180         if (!err)
181             wait_while_busy(5);
182     }
183     // FF400 case follows
184     do {
185         xfer_size = (n_quads > 32)?32:n_quads;
186         // Send data to flash buffer
187         err |= writeBlock(RME_FF400_FLASH_WRITE_BUFFER, buf, xfer_size);
188         // Program the destination address and size
189         block_desc[0] = ff400_addr;
190         block_desc[1] = xfer_size * sizeof(quadlet_t);
191         err |= writeBlock(RME_FF400_FLASH_BLOCK_ADDR_REG, block_desc, 2);
192         // Execute the write and wait for its completion
193         err |= writeRegister(RME_FF400_FLASH_CMD_REG, RME_FF400_FLASH_CMD_WRITE);
194         if (!err)
195             wait_while_busy(2);
196
197         n_quads -= xfer_size;
198         ff400_addr += xfer_size*sizeof(quadlet_t);
199         buf += xfer_size;
200     } while (n_quads>0 && !err);
201
202     return err?-1:0;
203 }
204
205
206 signed int
207 Device::read_device_flash_settings(FF_software_settings_t *settings)
208 {
209     // Read the device's configuration flash RAM and use this to set up
210     // the given settings structure.
211
212     FF_device_flash_settings_t hw_settings;
213     signed int i, err = 0;
214     unsigned int rev;
215
216     // FIXME: this is mostly for testing at present.  Still need to interface from
217     // hw_settings to the object's "settings" field.
218
219     i = get_revision(&rev);
220     if (i != 0) {
221         debugOutput(DEBUG_LEVEL_WARNING, "Error reading hardware revision: %d\n", i);
222     } else {
223         debugOutput(DEBUG_LEVEL_VERBOSE, "Hardware revision: 0x%08x\n", rev);
224     }
225
226     // Read settings flash ram block
227     err = read_flash(m_rme_model==RME_MODEL_FIREFACE800?
228       RME_FF800_FLASH_SETTINGS_ADDR:RME_FF400_FLASH_SETTINGS_ADDR,
229         (quadlet_t *)&hw_settings, sizeof(hw_settings)/sizeof(uint32_t));
230     if (err != 0) {
231         debugOutput(DEBUG_LEVEL_WARNING, "Error reading device flash settings: %d\n", i);
232     } else {
233         debugOutput(DEBUG_LEVEL_VERBOSE, "Device flash settings:\n");
234         if (hw_settings.clock_mode == FF_DEV_FLASH_INVALID) {
235             debugOutput(DEBUG_LEVEL_VERBOSE, "  Clock mode: not set in device flash\n");
236         } else {
237             debugOutput(DEBUG_LEVEL_VERBOSE, "  Clock mode: %s\n",
238               hw_settings.clock_mode==FF_DEV_FLASH_CLOCK_MODE_MASTER?"Master":"Slave");
239         }
240         if (hw_settings.sample_rate == FF_DEV_FLASH_INVALID) {
241             debugOutput(DEBUG_LEVEL_VERBOSE, "  Sample rate: not set in device flash\n");
242         } else
243         if (hw_settings.sample_rate == 0) {
244             debugOutput(DEBUG_LEVEL_VERBOSE, "  Sample rate: DDS not active\n");
245         } else {
246             debugOutput(DEBUG_LEVEL_VERBOSE, "  Sample rate: %d Hz (DDS active)\n", hw_settings.sample_rate);
247         }
248     }
249
250     if (settings != NULL) {
251         memset(settings, 0, sizeof(settings));
252         // Copy hardware details to the software settings structure as
253         // appropriate.
254         for (i=0; i<4; i++)
255             settings->mic_phantom[i] = hw_settings.mic_phantom[i];
256         settings->spdif_input_mode = hw_settings.spdif_input_mode;
257         settings->spdif_output_emphasis = hw_settings.spdif_output_emphasis;
258         settings->spdif_output_pro = hw_settings.spdif_output_pro;
259         settings->spdif_output_nonaudio = hw_settings.spdif_output_nonaudio;
260         settings->spdif_output_mode = hw_settings.spdif_output_mode;
261         settings->clock_mode = hw_settings.clock_mode;
262         settings->sync_ref = hw_settings.sync_ref;
263         settings->tms = hw_settings.tms;
264         settings->limit_bandwidth = hw_settings.limit_bandwidth;
265         settings->stop_on_dropout = hw_settings.stop_on_dropout;
266         settings->input_level = hw_settings.input_level;
267         settings->output_level = hw_settings.output_level;
268         settings->filter = hw_settings.filter;
269         settings->fuzz = hw_settings.fuzz;
270         settings->limiter_disable = (hw_settings.p12db_an[0] == 0)?1:0;
271         settings->sample_rate = hw_settings.sample_rate;
272         settings->word_clock_single_speed = hw_settings.word_clock_single_speed;
273
274         // The FF800 has front/rear selectors for the "instrument" input
275         // (aka channel 1) and the two "mic" channels (aka channels 7 and 8).
276         // The FF400 does not.  The FF400 borrows the mic0 selector field
277         // in the flash configuration structure to use for the "phones"
278         // level which the FF800 doesn't have.
279         // The offset of 1 here is to maintain consistency with the values
280         // used in the flash by other operating systems.
281         if (m_rme_model == RME_MODEL_FIREFACE400)
282             settings->phones_level = hw_settings.mic_plug_select[0] + 1;
283         else {
284             settings->input_opt[0] = hw_settings.instrument_plug_select + 1;
285             settings->input_opt[1] = hw_settings.mic_plug_select[0] + 1;
286             settings->input_opt[2] = hw_settings.mic_plug_select[1] + 1;
287         }
288     }
289
290 {
291 quadlet_t buf[4];
292 signed int i;
293   i = readBlock(RME_FF_STATUS_REG0, buf, 4);
294   fprintf(stderr, "Status read: %d\n", i);
295   for (i=0; i<4; i++)
296     fprintf(stderr,"0x%08x ", buf[i]);
297   fprintf(stderr,"\n");
298 }
299
300 #if 0
301 {
302 // Read mixer volume flash ram block
303 quadlet_t buf[0x800];
304   memset(buf, 0xdb, sizeof(buf));
305   i = read_flash(m_rme_model==RME_MODEL_FIREFACE800?
306         RME_FF800_FLASH_MIXER_VOLUME_ADDR:RME_FF400_FLASH_MIXER_VOLUME_ADDR, buf, 32);
307 fprintf(stderr,"result=%d\n", i);
308 for (i=0; i<32; i++) {
309   fprintf(stderr, "%d: 0x%08x\n", i, buf[i]);
310 }
311 }
312 #endif
313
314     return err!=0?-1:0;
315 }
316
317 signed int
318 Device::write_device_flash_settings(FF_software_settings_t *settings)
319 {
320     // Write the given device settings to the device's configuration flash.
321
322     // FIXME: fairly obviously the detail needs to be filled in here.
323     return 0;
324 }
325
326 }
Note: See TracBrowser for help on using the browser.