target/fw/dsp: Implement section loading with bootloader
[osmocom-bb.git] / src / target / firmware / calypso / dsp.c
1 #define DEBUG
2 /* Driver for the Calypso integrated DSP */
3
4 /* (C) 2010 by Harald Welte <laforge@gnumonks.org>
5  *
6  * All Rights Reserved
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License along
19  * with this program; if not, write to the Free Software Foundation, Inc.,
20  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21  *
22  */
23
24 #include <stdint.h>
25 #include <stdio.h>
26
27 #include <debug.h>
28 #include <delay.h>
29 #include <memory.h>
30 #include <calypso/clock.h>
31 #include <calypso/dsp.h>
32 #include <calypso/dsp_api.h>
33 #include <calypso/tpu.h>
34
35 #include <abb/twl3025.h>
36
37 #include <osmocore/gsm_utils.h>
38
39
40 #define REG_API_CONTROL         0xfffe0000
41 #define APIC_R_SMODE_HOM        (1 << 1)        /* API is configured in HOM mode */
42 #define APIC_R_HINT             (1 << 3)        /* Host processor interrupt (DSP->MCU) */
43 #define APIC_W_DSPINT           (1 << 2)        /* ARM issues interrupt to DSP */
44
45 #define REG_API_WS              0xfffff902      /* Number of wait states for ARM access to API memory */
46 #define REG_ARM_RHEA_CTL        0xfffff904      /* Write buffer bypassing */
47 #define REG_EXT_RHEA_CTL        0xfffff906      /* Some timeout */
48
49 #define API_SIZE                0x2000U         /* in words */
50
51 #define BASE_API_RAM            0xffd00000      /* Base address of API RAM form ARM point of view */
52
53 #define DSP_BASE_API            0x0800          /* Base address of API RAM for DSP */
54 #define DSP_BASE_API_MIRROR     0xe000          /* Base address of API RAM for DSP (API boot mirrot */
55 #define DSP_START               0x7000          /* DSP Start address */
56
57 /* Boot loader */
58 #define BL_CMD_STATUS           (BASE_API_RAM + 0x0ffe) /* Status / Command var    */
59 #define BL_ADDR_LO              (BASE_API_RAM + 0x0ffc) /* Address (16 lsbs)       */
60 #define BL_ADDR_HI              (BASE_API_RAM + 0x0ff8) /* Address (ext page bits) */
61 #define BL_SIZE                 (BASE_API_RAM + 0x0ffa) /* Size                    */
62
63 #define BL_MAX_BLOCK_SIZE       0x7F0                   /* Maximum size of copied block */
64
65         /* Possible values for the download status */
66 #define BL_STATUS_NA            0
67 #define BL_STATUS_IDLE          1
68 #define BL_CMD_COPY_BLOCK       2
69 #define BL_CMD_COPY_MODE        4
70
71 #define BL_MODE_PROG_WRITE      0
72 #define BL_MODE_DATA_WRITE      1
73 #define BL_MODE_PROG_READ       2
74 #define BL_MODE_DATA_READ       3
75 #define BL_MODE_PROM_READ       4
76 #define BL_MODE_DROM_READ       5
77
78
79 struct dsp_section {
80         uint32_t addr;          /* addr for DSP  */
81         uint32_t size;          /* size in words */
82         const uint16_t *data;
83 };
84
85 #include "dsp_params.c"
86 #include "dsp_bootcode.c"
87 #include "dsp_dumpcode.c"
88
89 struct dsp_api dsp_api = {
90         .ndb    = (T_NDB_MCU_DSP *) BASE_API_NDB,
91         .db_r   = (T_DB_DSP_TO_MCU *) BASE_API_R_PAGE_0,
92         .db_w   = (T_DB_MCU_TO_DSP *) BASE_API_W_PAGE_0,
93         .param  = (T_PARAM_MCU_DSP *) BASE_API_PARAM,
94         .r_page = 0,
95         .w_page = 0,
96 };
97
98
99 void dsp_dump_version(void)
100 {
101         printf("DSP Download Status: 0x%04x\n", readw(BL_CMD_STATUS));
102         printf("DSP API Version: 0x%04x 0x%04x\n",
103                 dsp_api.ndb->d_version_number1, dsp_api.ndb->d_version_number2);
104 }
105
106 static void dsp_bl_wait_ready(void)
107 {
108         while (readw(BL_CMD_STATUS) != BL_STATUS_IDLE);
109 }
110
111 static void dsp_bl_start_at(uint16_t addr)
112 {
113         writew(0, BL_ADDR_HI);
114         writew(addr, BL_ADDR_LO);
115         writew(0, BL_SIZE);
116         writew(BL_CMD_COPY_BLOCK, BL_CMD_STATUS);
117 }
118
119 static int dsp_bl_upload_sections(const struct dsp_section *sec)
120 {
121         /* Make sure the bootloader is ready */
122         dsp_bl_wait_ready();
123
124         /* Set mode */
125         writew(BL_MODE_DATA_WRITE, BASE_API_RAM);
126         writew(BL_CMD_COPY_MODE, BL_CMD_STATUS);
127         dsp_bl_wait_ready();
128
129         /* Scan all sections */
130         for (; sec->data; sec++) {
131                 volatile uint16_t *api = (volatile uint16_t *)BASE_API_RAM;
132                 unsigned int i;
133
134                 if (sec->size > BL_MAX_BLOCK_SIZE)
135                         return -1; /* not supported for now */
136
137                 /* Copy data to API */
138                 for (i=0; i<sec->size; i++)
139                         api[i] = sec->data[i];
140
141                 /* Issue DRAM write */
142                 writew(sec->addr >> 16, BL_ADDR_HI);
143                 writew(sec->addr & 0xffff, BL_ADDR_LO);
144                 writew(sec->size, BL_SIZE);
145                 writew(BL_CMD_COPY_BLOCK, BL_CMD_STATUS);
146
147                 /* Wait for completion */
148                 dsp_bl_wait_ready();
149         }
150
151         return 0;
152 }
153
154 static int dsp_upload_sections_api(const struct dsp_section *sec, uint16_t dsp_base_api)
155 {
156         for (; sec->data; sec++) {
157                 unsigned int i;
158                 volatile uint16_t *dptr;
159
160                 if (sec->addr & ~((1<<16)-1))   /* 64k max addr */
161                         return -1;
162                 if (sec->addr < dsp_base_api)
163                         return -1;
164                 if ((sec->addr + sec->size) > (dsp_base_api + API_SIZE))
165                         return -1;
166
167                 dptr = (volatile uint16_t *)(BASE_API_RAM + ((sec->addr - dsp_base_api) * sizeof(uint16_t)));
168                 for (i=0; i<sec->size; i++)
169                         *dptr++ = sec->data[i];
170         }
171
172         /* FIXME need eioio or wb ? */
173
174         return 0;
175 }
176
177 static void dsp_pre_boot(const struct dsp_section *bootcode)
178 {
179         dputs("Assert DSP into Reset\n");
180         calypso_reset_set(RESET_DSP, 1);
181
182         if (bootcode) {
183                 dputs("Loading initial DSP bootcode (API boot mode)\n");
184                 dsp_upload_sections_api(dsp_bootcode, DSP_BASE_API_MIRROR);
185
186                 writew(BL_STATUS_NA, BL_CMD_STATUS);
187         } else
188                 delay_ms(10);
189
190         dputs("Releasing DSP from Reset\n");
191         calypso_reset_set(RESET_DSP, 0);
192
193         /* Wait 10 us */
194         delay_ms(100);
195
196         dsp_bl_wait_ready();
197 }
198
199 static void dsp_set_params(int16_t *param_tab, int param_size)
200 {
201         int i;
202         int16_t *param_ptr = (int16_t *) BASE_API_PARAM;
203
204         /* Start DSP up to bootloader */
205         dsp_pre_boot(dsp_bootcode);
206
207         /* FIXME: Implement Patch download, if any */
208
209         dputs("Setting some dsp_api.ndb values\n");
210         dsp_api.ndb->d_background_enable = 0;
211         dsp_api.ndb->d_background_abort = 0;
212         dsp_api.ndb->d_background_state = 0;
213         dsp_api.ndb->d_debug_ptr = 0x0074;
214         dsp_api.ndb->d_debug_bk = 0x0001;
215         dsp_api.ndb->d_pll_config = 0x154; //C_PLL_CONFIG;
216         dsp_api.ndb->p_debug_buffer = 0x17ff; //C_DEBUG_BUFFER_ADD;
217         dsp_api.ndb->d_debug_buffer_size = 7; //C_DEBUG_BUFFER_SIZE;
218         dsp_api.ndb->d_debug_trace_type = 0; //C_DEBUG_TRACE_TYPE;
219         dsp_api.ndb->d_dsp_state = 3; //C_DSP_IDLE3;
220         dsp_api.ndb->d_audio_gain_ul = 0;
221         dsp_api.ndb->d_audio_gain_dl = 0;
222         dsp_api.ndb->d_es_level_api = 0x5213;
223         dsp_api.ndb->d_mu_api = 0x5000;
224
225         dputs("Setting API NDB parameters\n");
226         for (i = 0; i < param_size; i ++)
227                 *param_ptr++ = param_tab[i];
228         
229         dsp_dump_version();
230
231         dputs("Finishing download phase\n");
232         dsp_bl_start_at(DSP_START);
233
234         dsp_dump_version();
235 }
236
237 void dsp_api_memset(uint16_t *ptr, int octets)
238 {
239         uint16_t i;
240         for (i = 0; i < octets / sizeof(uint16_t); i++)
241                 *ptr++ = 0;
242 }
243
244 /* memcpy from RAM to DSP API, 16 bits by 16 bits. If odd byte count, last word will
245  * be zero filled */
246 void dsp_memcpy_to_api(volatile uint16_t *dsp_buf, const uint8_t *mcu_buf, int n, int be)
247 {
248         int odd, i;
249
250         odd = n & 1;
251         n >>= 1;
252
253         if (be) {
254                 for (i=0; i<n; i++) {
255                         uint16_t w;
256                         w  = *(mcu_buf++) << 8;
257                         w |= *(mcu_buf++);
258                         *(dsp_buf++) = w;
259                 }
260                 if (odd)
261                         *dsp_buf = *mcu_buf << 8;
262         } else {
263                 for (i=0; i<n; i++) {
264                         uint16_t w;
265                         w  = *(mcu_buf++);
266                         w |= *(mcu_buf++) << 8;
267                         *(dsp_buf++) = w;
268                 }
269                 if (odd)
270                         *dsp_buf = *mcu_buf;
271         }
272 }
273
274 /* memcpy from DSP API to RAM, accessing API 16 bits word at a time */
275 void dsp_memcpy_from_api(uint8_t *mcu_buf, const volatile uint16_t *dsp_buf, int n, int be)
276 {
277         int odd, i;
278
279         odd = n & 1;
280         n >>= 1;
281
282         if (be) {
283                 for (i=0; i<n; i++) {
284                         uint16_t w = *(dsp_buf++);
285                         *(mcu_buf++) = w >> 8;
286                         *(mcu_buf++) = w;
287                 }
288                 if (odd)
289                         *mcu_buf = *(dsp_buf++) >> 8;
290         } else {
291                 for (i=0; i<n; i++) {
292                         uint16_t w = *(dsp_buf++);
293                         *(mcu_buf++) = w;
294                         *(mcu_buf++) = w >> 8;
295                 }
296                 if (odd)
297                         *mcu_buf = *(dsp_buf++);
298         }
299 }
300
301 static void dsp_audio_init(void)
302 {
303         T_NDB_MCU_DSP *ndb = dsp_api.ndb;
304         uint8_t i;
305
306         ndb->d_vbctrl1  = ABB_VAL_T(VBCTRL1, 0x00B);    /* VULSWITCH=0, VDLAUX=1, VDLEAR=1 */
307         ndb->d_vbctrl2  = ABB_VAL_T(VBCTRL2, 0x000);    /* MICBIASEL=0, VDLHSO=0, MICAUX=0 */
308
309         /*
310          * TODO: the following two settings are used to control
311          * the volume and uplink/downlink/sidetone gain. Make them
312          * adjustable by the user.
313          */
314
315         ndb->d_vbuctrl  = ABB_VAL_T(VBUCTRL, 0x009);    /* Uplink gain amp 3dB, Sidetone gain -5dB */
316         ndb->d_vbdctrl  = ABB_VAL_T(VBDCTRL, 0x066);    /* Downlink gain amp 0dB, Volume control -6 dB */
317
318         ndb->d_toneskb_init = 0;                        /* MCU/DSP audio task com. register */
319         ndb->d_toneskb_status = 0;                      /* MCU/DSP audio task com. register */
320
321         ndb->d_shiftul = 0x100;
322         ndb->d_shiftdl = 0x100;
323
324         ndb->d_melo_osc_used    = 0;
325         ndb->d_melo_osc_active  = 0;
326
327 #define SC_END_OSCILLATOR_MASK        0xfffe
328
329         ndb->a_melo_note0[0] = SC_END_OSCILLATOR_MASK;
330         ndb->a_melo_note1[0] = SC_END_OSCILLATOR_MASK;
331         ndb->a_melo_note2[0] = SC_END_OSCILLATOR_MASK;
332         ndb->a_melo_note3[0] = SC_END_OSCILLATOR_MASK;
333         ndb->a_melo_note4[0] = SC_END_OSCILLATOR_MASK;
334         ndb->a_melo_note5[0] = SC_END_OSCILLATOR_MASK;
335         ndb->a_melo_note6[0] = SC_END_OSCILLATOR_MASK;
336         ndb->a_melo_note7[0] = SC_END_OSCILLATOR_MASK;
337
338 #define MAX_FIR_COEF  31
339
340         /* Initialize the FIR as an all band pass */
341         dsp_api.param->a_fir31_downlink[0] = 0x4000;
342         dsp_api.param->a_fir31_uplink[0]   = 0x4000;
343         for (i = 1; i < MAX_FIR_COEF; i++)
344         {
345                 dsp_api.param->a_fir31_downlink[i]  = 0;
346                 dsp_api.param->a_fir31_uplink[i]    = 0;
347         }
348
349 #define B_GSM_ONLY      ((1L <<  13) | (1L <<  11))     /* GSM normal mode */
350 #define B_BT_CORDLESS   (1L <<  12)                     /* Bluetooth cordless mode */
351 #define B_BT_HEADSET    (1L <<  14)                     /* Bluetooth headset mode */
352
353                 /* Bit set by the MCU to close the loop between the audio UL and DL path. */
354                 /* This features is used to find the FIR coefficient. */
355 #define B_FIR_LOOP      (1L <<  1)
356
357         /* Reset the FIR loopback and the audio mode */
358         ndb->d_audio_init &= ~(B_FIR_LOOP | B_GSM_ONLY | B_BT_HEADSET | B_BT_CORDLESS);
359
360         /* Set the GSM mode  */
361         ndb->d_audio_init |= (B_GSM_ONLY);
362
363         ndb->d_aec_ctrl = 0;
364
365         /* DSP background task through pending task queue */
366         dsp_api.param->d_gsm_bgd_mgt = 0;
367
368         ndb->d_audio_compressor_ctrl = 0x0401;
369
370 #define NO_MELODY_SELECTED    (0)
371
372         ndb->d_melody_selection = NO_MELODY_SELECTED;
373 }
374
375 static void dsp_ndb_init(void)
376 {
377         T_NDB_MCU_DSP *ndb = dsp_api.ndb;
378         uint8_t i;
379
380         #define APCDEL_DOWN     (2+0)   // minimum value: 2
381         #define APCDEL_UP       (6+3+1) // minimum value: 6
382
383         /* load APC ramp: set to "no ramp" so that there will be no output if
384          * not properly initialised at some other place. */
385         for (i = 0; i < 16; i++)
386                 dsp_api.ndb->a_ramp[i] = ABB_VAL(APCRAM, ABB_RAMP_VAL(0, 0));
387
388         /* Iota registers values will be programmed at 1st DSP communication interrupt */
389
390         /* Enable f_tx delay of 400000 cyc DEBUG */
391         ndb->d_debug1   = ABB_VAL_T(0, 0x000);
392         ndb->d_afcctladd= ABB_VAL_T(AFCCTLADD, 0x000);  // Value at reset
393         ndb->d_vbuctrl  = ABB_VAL_T(VBUCTRL, 0x0C9);    // Uplink gain amp 0dB, Sidetone gain to mute
394         ndb->d_vbdctrl  = ABB_VAL_T(VBDCTRL, 0x006);    // Downlink gain amp 0dB, Volume control 0 dB
395         ndb->d_bbctrl   = ABB_VAL_T(BBCTRL,  0x2C1);    // value at reset
396         ndb->d_bulgcal  = ABB_VAL_T(BULGCAL, 0x000);    // value at reset
397         ndb->d_apcoff   = ABB_VAL_T(APCOFF,  0x040);    // value at reset
398         ndb->d_bulioff  = ABB_VAL_T(BULIOFF, 0x0FF);    // value at reset
399         ndb->d_bulqoff  = ABB_VAL_T(BULQOFF, 0x0FF);    // value at reset
400         ndb->d_dai_onoff= ABB_VAL_T(APCOFF,  0x000);    // value at reset
401         ndb->d_auxdac   = ABB_VAL_T(AUXDAC,  0x000);    // value at reset
402         ndb->d_vbctrl1  = ABB_VAL_T(VBCTRL1, 0x00B);    // VULSWITCH=0, VDLAUX=1, VDLEAR=1.
403         ndb->d_vbctrl2  = ABB_VAL_T(VBCTRL2, 0x000);    // MICBIASEL=0, VDLHSO=0, MICAUX=0
404
405         /* APCDEL will be initialized on rach only */
406         ndb->d_apcdel1  = ABB_VAL_T(APCDEL1, ((APCDEL_DOWN-2) << 5) | (APCDEL_UP-6));
407         ndb->d_apcdel2  = ABB_VAL_T(APCDEL2, 0x000);
408
409         ndb->d_fb_mode  = 1;            /* mode 1 FCCH burst detection */
410         ndb->d_fb_det   = 0;            /* we have not yet detected a FB */
411         ndb->a_cd[0]    = (1<<B_FIRE1); /* CCCH/SACCH downlink */
412         ndb->a_dd_0[0]  = 0;
413         ndb->a_dd_0[2]  = 0xffff;
414         ndb->a_dd_1[0]  = 0;
415         ndb->a_dd_1[2]  = 0xffff;
416         ndb->a_du_0[0]  = 0;
417         ndb->a_du_0[2]  = 0xffff;
418         ndb->a_du_1[0]  = 0;
419         ndb->a_du_1[2]  = 0xffff;
420         ndb->a_fd[0]    = (1<<B_FIRE1);
421         ndb->a_fd[2]    = 0xffff;
422         ndb->d_a5mode   = 0;
423         ndb->d_tch_mode = 0x0800;
424
425         #define GUARD_BITS 8 // 11 or 9 for TSM30, 7 for Freerunner
426         ndb->d_tch_mode |= (((GUARD_BITS - 4) & 0x000F) << 7); //Bit 7..10: guard bits
427
428         ndb->a_sch26[0] = (1<<B_SCH_CRC);
429
430         /* Interrupt RIF transmit if FIFO <= threshold with threshold == 0 */
431         /* MCM = 1, XRST = 0, CLKX_AUTO=1, TXM=1, NCLK_EN=1, NCLK13_EN=1,
432          * THRESHOLD = 0, DIV_CLK = 0 (13MHz) */
433         ndb->d_spcx_rif = 0x179;
434
435         /* Init audio related parameters */
436         dsp_audio_init();
437 }
438
439 static void dsp_db_init(void)
440 {
441         dsp_api_memset((uint16_t *)BASE_API_W_PAGE_0, sizeof(T_DB_MCU_TO_DSP));
442         dsp_api_memset((uint16_t *)BASE_API_W_PAGE_1, sizeof(T_DB_MCU_TO_DSP));
443         dsp_api_memset((uint16_t *)BASE_API_R_PAGE_0, sizeof(T_DB_DSP_TO_MCU));
444         dsp_api_memset((uint16_t *)BASE_API_R_PAGE_1, sizeof(T_DB_DSP_TO_MCU));
445 }
446
447 void dsp_power_on(void)
448 {
449         /* proabaly a good idea to initialize the whole API area to a know value */
450         dsp_api_memset((uint16_t *)BASE_API_RAM, API_SIZE * 2); // size is in words
451
452         dsp_set_params((int16_t *)&dsp_params, sizeof(dsp_params)/2);
453         dsp_ndb_init();
454         dsp_db_init();
455         dsp_api.frame_ctr = 0;
456         dsp_api.r_page = dsp_api.w_page = dsp_api.r_page_used = 0;
457 }
458
459 /* test for frequency burst detection */
460 #define REG_INT_STAT 0xffff1004
461 static void wait_for_frame_irq(void)
462 {
463         //puts("Waiting for Frame Interrupt");
464         //while (readb(REG_INT_STAT) & 1)
465         while (readb((void *)0xffff1000) & (1<<4))
466         ;//     putchar('.');
467         //puts("Done!\n");
468 }
469
470 void dsp_end_scenario(void)
471 {
472         /* FIXME: we don't yet deal with the MISC_TASK */
473
474         /* End the DSP Scenario */
475         dsp_api.ndb->d_dsp_page = B_GSM_TASK | dsp_api.w_page;
476         dsp_api.w_page ^= 1;
477
478         /* Tell TPU to generate a FRAME interrupt to the DSP */
479         tpu_dsp_frameirq_enable();
480         tpu_frame_irq_en(1, 1);
481 }
482
483 void dsp_load_rx_task(uint16_t task, uint8_t burst_id, uint8_t tsc)
484 {
485         dsp_api.db_w->d_task_d = task;
486         dsp_api.db_w->d_burst_d = burst_id;
487         dsp_api.db_w->d_ctrl_system |= tsc & 0x7;
488 }
489
490 void dsp_load_tx_task(uint16_t task, uint8_t burst_id, uint8_t tsc)
491 {
492         dsp_api.db_w->d_task_u = task;
493         dsp_api.db_w->d_burst_u = burst_id;
494         dsp_api.db_w->d_ctrl_system |= tsc & 0x7;
495 }
496
497 /* no AMR yet */
498 void dsp_load_tch_param(struct gsm_time *next_time,
499                         uint8_t chan_mode, uint8_t chan_type, uint8_t chan_sub,
500                         uint8_t tch_loop, uint8_t sync_tch, uint8_t tn)
501 {
502         uint16_t d_ctrl_tch;
503         uint16_t fn, a5fn0, a5fn1;
504
505         /* d_ctrl_tch
506            ----------
507             bit [0..3]   -> b_chan_mode
508             bit [4..7]   -> b_chan_type
509             bit [8]      -> b_sync_tch_ul
510             bit [9]      -> b_sync_tch_dl
511             bit [10]     -> b_stop_tch_ul
512             bit [11]     -> b_stop_tch_dl
513             bit [12..14] -> b_tch_loop
514             bit [15]     -> b_subchannel */
515         d_ctrl_tch = (chan_mode  << B_CHAN_MODE) |
516                      (chan_type  << B_CHAN_TYPE)  |
517                      (chan_sub   << B_SUBCHANNEL) |
518                      (sync_tch   << B_SYNC_TCH_UL) |
519                      (sync_tch   << B_SYNC_TCH_DL) |
520                      (tch_loop   << B_TCH_LOOP);
521
522         /* used for ciphering and TCH traffic */
523
524         /* d_fn
525            ----
526
527            for TCH_F:
528              bit [0..7]  -> b_fn_report = (fn - (tn * 13) + 104) % 104)
529              bit [8..15] -> b_fn_sid    = (fn % 104)
530
531            for TCH_H:
532                             tn_report = (tn & ~1) | subchannel
533              bit [0..7]  -> b_fn_report = (fn - tn_report * 13) + 104) % 104)
534              bit [8..15] -> b_fn_sid    = (fn % 104)
535
536            for other: irrelevant
537          */
538
539         if (chan_type == TCH_F) {
540                 fn = ((next_time->fn - (tn * 13) + 104) % 104) |
541                      ((next_time->fn % 104) << 8);
542         } else if (chan_type == TCH_H) {
543                 uint8_t tn_report = (tn & ~1) | chan_sub;
544                 fn = ((next_time->fn - (tn_report * 13) + 104) % 104) |
545                      ((next_time->fn % 104) << 8);
546         } else {
547                 /* irrelevant */
548                 fn = 0;
549         }
550
551         /* a_a5fn
552            ------
553              byte[0] bit [0..4]  -> T2
554              byte[0] bit [5..10] -> T3
555              byte[1] bit [0..10] -> T1 */
556
557         a5fn0 = ((uint16_t)next_time->t3 << 5) |
558                  (uint16_t)next_time->t2;
559         a5fn1 =  (uint16_t)next_time->t1;
560
561         dsp_api.db_w->d_fn        = fn;         /* Fn_sid & Fn_report  */
562         dsp_api.db_w->a_a5fn[0]   = a5fn0;      /* cyphering FN part 1 */
563         dsp_api.db_w->a_a5fn[1]   = a5fn1;      /* cyphering FN part 2 */
564         dsp_api.db_w->d_ctrl_tch  = d_ctrl_tch; /* Channel config.     */
565 }
566
567 void dsp_load_ciph_param(int mode, uint8_t *key)
568 {
569         dsp_api.ndb->d_a5mode = mode;
570
571         if (!mode || !key)
572                 return;
573
574                 /* key is expected in the same format as in RSL
575                  * Encryption information IE. So we need to load the
576                  * bytes backward in A5 unit */
577         dsp_api.ndb->a_kc[0] = (uint16_t)key[7] | ((uint16_t)key[6] << 8);
578         dsp_api.ndb->a_kc[1] = (uint16_t)key[5] | ((uint16_t)key[4] << 8);
579         dsp_api.ndb->a_kc[2] = (uint16_t)key[3] | ((uint16_t)key[2] << 8);
580         dsp_api.ndb->a_kc[3] = (uint16_t)key[1] | ((uint16_t)key[0] << 8);
581 }
582
583 #define SC_CHKSUM_VER     (BASE_API_W_PAGE_0 + (2 * (0x08DB - 0x800)))
584 static void dsp_dump_csum(void)
585 {
586         printf("dsp page          : %u\n", dsp_api.ndb->d_dsp_page);
587         printf("dsp code version  : 0x%04x\n", dsp_api.db_r->a_pm[0]);
588         printf("dsp checksum      : 0x%04x\n", dsp_api.db_r->a_pm[1]);
589         printf("dsp patch version : 0x%04x\n", readw(SC_CHKSUM_VER));
590 }
591
592 void dsp_checksum_task(void)
593 {
594         dsp_dump_csum();
595         dsp_api.db_w->d_task_md = CHECKSUM_DSP_TASK;
596         dsp_api.ndb->d_fb_mode = 1;
597
598         dsp_end_scenario();
599
600         wait_for_frame_irq();
601
602         dsp_dump_csum();
603 }
604
605 #define L1D_AUXAPC              0x0012
606 #define L1D_APCRAM              0x0014
607
608 void dsp_load_apc_dac(uint16_t apc)
609 {
610         dsp_api.db_w->d_power_ctl = (apc << 6) | L1D_AUXAPC;
611 }
612
613
614 static void _dsp_dump_range(uint32_t addr, uint32_t size, int mode)
615 {
616         uint32_t bs;
617
618         /* Mode selection */
619         writew(mode, BASE_API_RAM);
620         writew(BL_CMD_COPY_MODE, BL_CMD_STATUS);
621         dsp_bl_wait_ready();
622
623         /* Block by block dump */
624         while (size) {
625                 volatile uint16_t *api = (volatile uint16_t *)BASE_API_RAM;
626
627                 bs = (size > BL_MAX_BLOCK_SIZE) ? BL_MAX_BLOCK_SIZE : size;
628                 size -= bs;
629
630                 writew(addr >> 16, BL_ADDR_HI);
631                 writew(addr & 0xffff, BL_ADDR_LO);
632                 writew(bs, BL_SIZE);
633                 writew(BL_CMD_COPY_BLOCK, BL_CMD_STATUS);
634
635                 dsp_bl_wait_ready();
636
637                 while (bs--) {
638                         if ((addr&15)==0)
639                                 printf("%05x : ", addr);
640                         printf("%04hx%c", *api++, ((addr&15)==15)?'\n':' ');
641                         addr++;
642                 }
643         };
644         puts("\n");
645 }
646
647 void dsp_dump(void)
648 {
649         static const struct {
650                 const char *name;
651                 uint32_t addr;
652                 uint32_t size;
653                 int mode;
654         } dr[] = {
655                 { "Registers",  0x00000, 0x0060, BL_MODE_DATA_READ },
656                 { "DROM",       0x09000, 0x5000, BL_MODE_DROM_READ },
657                 { "PDROM",      0x0e000, 0x2000, BL_MODE_DROM_READ },
658                 { "PROM0",      0x07000, 0x7000, BL_MODE_PROM_READ },
659                 { "PROM1",      0x18000, 0x8000, BL_MODE_PROM_READ },
660                 { "PROM2",      0x28000, 0x8000, BL_MODE_PROM_READ },
661                 { "PROM3",      0x38000, 0x2000, BL_MODE_PROM_READ },
662                 { NULL, 0, 0, -1 }
663         };
664
665         int i;
666
667         /* Start DSP up to bootloader */
668         dsp_pre_boot(dsp_bootcode);
669
670         /* Load and execute our dump code in the DSP */
671         dsp_upload_sections_api(dsp_dumpcode, DSP_BASE_API);
672         dsp_bl_start_at(DSP_DUMPCODE_START);
673
674                 /* our dump code actually simulates the boot loaded
675                  * but with added read commands */
676         dsp_bl_wait_ready();
677
678         /* Test the 'version' command */
679         writew(0xffff, BL_CMD_STATUS);
680         dsp_bl_wait_ready();
681         printf("DSP bootloader version 0x%04x\n", readw(BASE_API_RAM));
682
683         /* Dump each range */
684         for (i=0; dr[i].name; i++) {
685                 printf("DSP dump: %s [%05x-%05x]\n", dr[i].name,
686                         dr[i].addr, dr[i].addr+dr[i].size-1);
687                 _dsp_dump_range(dr[i].addr, dr[i].size, dr[i].mode);
688         }
689 }
690