7743d813f30c4ba3a397ba87aa327539ddcff7c2
[firmerware] / src / driver / tic55x / grandstream-bt20x.c
1 /* Grandstream BT20x driver as an extension to the tic55x driver
2  *
3  * Ideally, all this would be is wiring to the generic functions of
4  * chips connected to the DSP.  And of course a lot of register setup
5  * code.  In practice, it is not as sharply divided, sometimes for
6  * reasons of efficiency, sometimes for other reasons.  The ideal is
7  * the best judgement however, and any debate on where code should go
8  * should be based on this ideal plus the realism that too much
9  * indirection will slow down a program that is going to deal with
10  * static hardware anyway.
11  *
12  * This file is part of 0cpm Firmerware.
13  *
14  * 0cpm Firmerware is Copyright (c)2011 Rick van Rein, OpenFortress.
15  *
16  * 0cpm Firmerware is free software: you can redistribute it and/or
17  * modify it under the terms of the GNU General Public License as
18  * published by the Free Software Foundation, version 3.
19  *
20  * 0cpm Firmerware is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23  * GNU General Public License for more details.
24  *
25  * You should have received a copy of the GNU General Public License
26  * along with 0cpm Firmerware.  If not, see <http://www.gnu.org/licenses/>.
27  */
28
29
30 #include <stdlib.h>
31 #include <stdarg.h>
32 #include <stdbool.h>
33 #include <stdint.h>
34
35 #define BOTTOM
36 #include <config.h>
37
38 #include <0cpm/cpu.h>
39 #include <0cpm/timer.h>
40 #include <0cpm/led.h>
41 #include <0cpm/kbd.h>
42 #include <0cpm/app.h>
43 #include <0cpm/show.h>
44 #include <0cpm/flash.h>
45 #include <0cpm/snd.h>
46 #include <0cpm/cons.h>
47
48 #include <bottom/ht162x.h>
49 #include <bottom/ksz8842.h>
50
51
52
53 /******** EXTERNAL INTERRUPTS SERVICE ROUTINES ********/
54
55
56 interrupt void tic55x_int0_isr (void) {
57         tic55x_top_has_been_interrupted = true;
58         ksz8842_interrupt_handler ();
59 }
60
61 #if 0
62 interrupt void tic55x_int1 (void) {
63         tic55x_top_has_been_interrupted = true;
64         //TODO//
65 }
66
67 interrupt void tic55x_int2 (void) {
68         tic55x_top_has_been_interrupted = true;
69         //TODO//
70 }
71
72 interrupt void tic55x_int3 (void) {
73         tic55x_top_has_been_interrupted = true;
74         //TODO//
75 }
76 #endif
77
78
79
80 /******** FLASH PARTITION ACCESS ********/
81
82
83 /* An external definition (usually in phone-specific code)
84  * contains an array of at least one entry of flashpart
85  * structures.  Only the last will have the FLASHPART_FLAG_LAST
86  * flag set.
87  *
88  * There will usually be one partition with name ALLFLASH.BIN
89  * that covers the entire flash memory, including things that
90  * may not actually be in any partition.  Usually, this is the
91  * last entry in the flash partition table.
92  */
93 struct flashpart bottom_flash_partition_table [] = {
94         { FLASHPART_FLAG_LAST, "ALLFLASH.BIN", 0, 4096 }
95 };
96
97
98 /* Read a 512-byte block from flash.
99  * The return value indicates success.
100  */
101 bool bottom_flash_read (uint16_t blocknr, uint8_t data [512]) {
102         uint32_t flashidx;
103         uint16_t ctr = 0;
104         if (blocknr >= 4096) {
105                 return false;
106         }
107         flashidx = ((uint32_t) blocknr) * 256;
108         while (ctr < 512) {
109                 uint16_t sample = flash_16 [flashidx];
110                 flashidx += 1;
111                 // data [ctr++] = (sample >> 24) & 0xff;
112                 // data [ctr++] = (sample >> 16) & 0xff;
113                 data [ctr++] = (sample >>  8) & 0xff;
114                 data [ctr++] =  sample        & 0xff;
115         }
116         return true;
117 }
118
119
120 /* Write a 512-byte block to flash.  It is assumed that this
121  * is done sequentially; any special treatment for a header
122  * page will be done by the bottom layer, not the top.
123  * The return value indicates success.
124  */
125 bool boot_flash_write (uint16_t blocknr, uint8_t data [512]) {
126         return false;
127 }
128
129
130 /* Retrieve the current phone's MAC address from Flash.
131  */
132 void bottom_flash_get_mac (uint8_t mac [6]) {
133         uint32_t flashidx = flash_offset_mymac;
134         uint16_t ctr = 0;
135         while (ctr < 6) {
136                 uint16_t sample = flash_16 [flashidx];
137                 flashidx++;
138                 mac [ctr++] = (sample >> 8) & 0xff;
139                 mac [ctr++] =  sample       & 0xff;
140         }
141 }
142
143
144
145 /******** TLV320AIC20K PROGRAMMING ACCESS OVER I2C ********/
146
147
148 /* The codec can be programmed over I2C, so the low-level routines
149  * for driving the codec end up passing bytes over I2C.  The
150  * procedure of cycling through subregisters is not performed here.
151  */
152
153 void tlv320aic2x_setreg (uint8_t channel, uint8_t reg, uint8_t val) {
154         // Wait as long as the bus is busy
155 bottom_led_set (LED_IDX_MESSAGE, 1);
156         while (I2CSTR & REGVAL_I2CSTR_BB) {
157                 ;
158         }
159 // bottom_printf ("I2C.pre  = 0x%04x,0x%04x\n", (intptr_t) I2CSTR, (intptr_t) I2CMDR);
160         // Set transmission mode for 2 bytes to "channel"
161         I2CSAR = 0x40 | channel;
162         //TODO// I2CSAR = 0x00; // Broadcast
163         I2CCNT = 2;
164         I2CDXR = reg;
165         // Send the register index
166         // Initiate the transfer by setting STT and STP flags
167         I2CMDR = REGVAL_I2CMDR_TRX | REGVAL_I2CMDR_MST | REGVAL_I2CMDR_STT | REGVAL_I2CMDR_STP | REGVAL_I2CMDR_NORESET | REGVAL_I2CMDR_FREE | REGVAL_I2CMDR_BC_8;
168 // bottom_printf ("I2C.set  = 0x%04x,0x%04x\n", (intptr_t) I2CSTR, (intptr_t) I2CMDR);
169         // Wait for the START condition to occur
170 // bottom_led_set (LED_IDX_HANDSET, 1);
171         while (I2CMDR & REGVAL_I2CMDR_STT) {
172                 ;
173         }
174 // bottom_printf ("I2C.stt  = 0x%04x,0x%04x\n", (intptr_t) I2CSTR, (intptr_t) I2CMDR);
175 // bottom_led_set (LED_IDX_HANDSET, 0);
176         // Wait until the I2C bus is ready, then send the value
177 // bottom_led_set (LED_IDX_SPEAKERPHONE, 1);
178         while (!(I2CSTR & REGVAL_I2CSTR_XRDY)) {
179                 if (I2CSTR & REGVAL_I2CSTR_NACK) {
180                         bottom_printf ("I2C received NACK\n");
181                         I2CSTR = REGVAL_I2CSTR_NACK;
182                         I2CMDR = REGVAL_I2CMDR_MST | REGVAL_I2CMDR_STP | REGVAL_I2CMDR_NORESET | REGVAL_I2CMDR_FREE | REGVAL_I2CMDR_BC_8;
183                         return;
184                 }
185         }
186 // bottom_printf ("I2C.xrdy = 0x%04x,0x%04x\n", (intptr_t) I2CSTR, (intptr_t) I2CMDR);
187 // bottom_led_set (LED_IDX_SPEAKERPHONE, 0);
188         I2CDXR = val;
189         // Wait for the STOP condition to occur
190         while (I2CMDR & REGVAL_I2CMDR_STP) {
191                 ;
192         }
193 // bottom_printf ("I2C.post = 0x%04x,0x%04x\n", (intptr_t) I2CSTR, (intptr_t) I2CMDR);
194 bottom_led_set (LED_IDX_MESSAGE, 0);
195 }
196
197 uint8_t tlv320aic2x_getreg (uint8_t channel, uint8_t reg) {
198         uint8_t val;
199 uint32_t ctr;
200 bottom_led_set (LED_IDX_MESSAGE, 1);
201 // bottom_led_set (LED_IDX_HANDSET, 0);
202         // Wait as long as the bus is busy
203         while (I2CSTR & REGVAL_I2CSTR_BB) {
204                 ;
205         }
206         // Set transmission mode for 1 byte to "channel"
207         I2CSAR = 0x40 | channel;
208         //TODO// I2CSAR = 0x00; // Broadcast
209         I2CCNT = 1;
210         I2CDXR = reg;
211         // Send the register index
212         // Initiate the transfer by setting STT flag, but withhold STP
213         I2CMDR = REGVAL_I2CMDR_TRX | REGVAL_I2CMDR_MST | REGVAL_I2CMDR_STT | /* REGVAL_I2CMDR_STP | */ REGVAL_I2CMDR_NORESET | REGVAL_I2CMDR_FREE | REGVAL_I2CMDR_BC_8;
214         // Wait until the START condition has occurred
215         while (I2CMDR & REGVAL_I2CMDR_STT) {
216                 ;
217         }
218         // ...send address and write mode bit...
219 // bottom_led_set (LED_IDX_HANDSET, 1);
220         // Wait until ready to setup for receiving
221         // while (I2CMDR & REGVAL_I2CMDR_STP) {
222         while (I2CSTR & (REGVAL_I2CSTR_XRDY | REGVAL_I2CSTR_XSMT) != (REGVAL_I2CSTR_XRDY | REGVAL_I2CSTR_XSMT)) {
223                 if (I2CSTR & (REGVAL_I2CSTR_NACK | REGVAL_I2CSTR_AL)) {
224                         I2CSTR = REGVAL_I2CSTR_NACK | REGVAL_I2CSTR_AL;
225                         I2CMDR = REGVAL_I2CMDR_MST | REGVAL_I2CMDR_STP | REGVAL_I2CMDR_NORESET | REGVAL_I2CMDR_FREE | REGVAL_I2CMDR_BC_8;
226                         return 0;
227                 }
228         }
229 // bottom_led_set (LED_IDX_HANDSET, 0);
230         I2CCNT = 1;
231         // Restart with STT flag, also permit stop with STP; do not set TRX
232         I2CMDR = REGVAL_I2CMDR_MST | /* REGVAL_I2CMDR_STT | */ REGVAL_I2CMDR_STP | REGVAL_I2CMDR_NORESET | REGVAL_I2CMDR_FREE | REGVAL_I2CMDR_BC_8;
233         // ...recv val...
234         while (!(I2CSTR & REGVAL_I2CSTR_RRDY)) {
235 #if 0
236                 if (I2CSTR & REGVAL_I2CSTR_NACK) {
237                         I2CSTR = REGVAL_I2CSTR_NACK;
238                         // I2CMDR = REGVAL_I2CMDR_MST | REGVAL_I2CMDR_STP | REGVAL_I2CMDR_NORESET | REGVAL_I2CMDR_FREE | REGVAL_I2CMDR_BC_8;
239                         // return 0;
240                 }
241 #endif
242                 ;
243         }
244         val = I2CDRR;
245 bottom_led_set (LED_IDX_MESSAGE, 0);
246         return val;
247 }
248
249
250 /******** TLV320AIC20K DATA ACCESS OVER MCBSP1 ********/
251
252
253 #define BUFSZ (64*25)
254
255 extern volatile uint16_t samplebuf_play   [BUFSZ];
256 extern volatile uint16_t samplebuf_record [BUFSZ];
257
258 extern volatile uint16_t available_play;
259 extern volatile uint16_t available_record;
260
261 extern volatile uint16_t threshold_play;
262 extern volatile uint16_t threshold_record;
263
264
265 /* Copy encoded samples to plain samples */
266 //TODO// Better to switch once and then loop in a separate routine which may even be .asm -- but that could require a codec-specific state storage structure
267 int16_t codec_decode (codec_t codec, uint8_t *in, uint16_t inlen, uint16_t *out, uint16_t outlen) {
268         while ((inlen > 0) && (outlen > 0)) {
269                 register uint16_t outval;
270                 register uint8_t inval = *in++;
271                 switch (codec) {
272                 case CODEC_L8:
273                         //TODO// *out++ = (inval ^ 0x80) << 8;
274 *out++ = 16384 + 1 + (outlen & 0x01)? 0: 32768;
275                         break;
276                 case CODEC_L16:
277                         *out++ = inval;
278                         break;
279                 case CODEC_G711A:
280                         outval = (inval & 0x0f);
281                         if (inval & 0x70) {
282                                 outval |= 0x10;
283                         }
284                         outval <<= ((inval >> 4) & 0x07);
285                         if (inval & 0x80) {
286                                 outval = -outval;
287                         }
288                         *out++ = outval;
289                         break;
290                 case CODEC_G711MU:
291                         outval = (inval & 0x0f);
292                         outval |= 0x10;
293                         outval <<= ((inval >> 4) & 0x07);
294                         outval -= 32;
295                         if (inval & 0x80) {
296                                 outval = -outval;
297                         }
298                         *out++ = outval;
299                         break;
300                 default:
301                         *out++ = 0;
302                         break;
303                 }
304                 inlen--;
305                 outlen--;
306         }
307         return inlen - outlen;
308 }
309
310 /* Copy plain samples to encoded samples */
311 //TODO// Better to switch once and then loop in a separate routine which may even be .asm -- but that could require a codec-specific state storage structure
312 int16_t codec_encode (codec_t codec, uint16_t *in, uint16_t inlen, uint8_t *out, uint16_t outlen) {
313         while ((inlen > 0) && (outlen > 0)) {
314                 register uint16_t inval = *in++;
315                 bool signbit;
316                 uint8_t exp;
317                 switch (codec) {
318                 case CODEC_L8:
319                         *out++ = (inval >> 8) ^ 0x80;
320                         break;
321                 case CODEC_L16:
322                         *out++ = inval;
323                         break;
324                 case CODEC_G711A:
325                         // Handle sign bit
326                         signbit = inval >> 15;
327                         if (signbit) {
328                                 inval = -inval;
329                         }
330                         // Find exponent part of sample
331                         for (exp = 7; exp >= 0; exp--) {
332                                 if (inval >= (1 << (8 + exp))) {
333                                         break;
334                                 }
335                         }
336                         // Encode is sign/exp/mant
337                         *out++ = 0x55 ^ ( (signbit << 7) | (exp << 4) | ((inval >> (exp + 3)) & 0x0f) );
338                         break;
339                 case CODEC_G711MU:
340                         // Handle sign bit
341                         signbit = inval >> 15;
342                         if (signbit) {
343                                 inval = -inval;
344                         }
345                         // Shift range for uLaw
346                         inval += 32;
347                         // Find exponent part of sample
348                         for (exp = 7; exp >= 0; exp--) {
349                                 if (inval >= (1 << (8 + exp))) {
350                                         break;
351                                 }
352                         }
353                         // Encode in sign/exp/mant
354                         *out++ = 0xff ^ ( (signbit << 7) | (exp << 4) | ((inval >> (exp + 3)) & 0x0f) );
355                         break;
356                 default:
357                         *out++ = 0x00;
358                         break;
359                 }
360                 *out++ = *in++ >> 8;
361                 inlen--;
362                 outlen--;
363         }
364         return outlen - inlen;
365 }
366
367 /* If the chip has not been brought up yet, do it now */
368 void tlv320aic2x_setup_chip (void) {
369         // Now, if not done yet, unreset and setup the TLV320AIC20K codec
370         if ((IODATA & (1 << 7)) == 0) {
371                 volatile uint16_t ctr;
372                 for (ctr=0; ctr < 7 * (600 / 12); ctr++) /* Wait 7x MCLK */ ;
373 for (ctr=0; ctr < 7 * (600 / 12); ctr++) /* Wait 7x MCLK */ ;
374 for (ctr=0; ctr < 7 * (600 / 12); ctr++) /* Wait 7x MCLK */ ;
375 for (ctr=0; ctr < 7 * (600 / 12); ctr++) /* Wait 7x MCLK */ ;
376 for (ctr=0; ctr < 7 * (600 / 12); ctr++) /* Wait 7x MCLK */ ;
377                 IODATA |= (1 << 7);
378                 for (ctr=0; ctr < 132 * (600 / 12); ctr++) /* Wait at least 132 MCLK cycles */ ;
379 for (ctr=0; ctr < 132 * (600 / 12); ctr++) /* Wait at least 132 MCLK cycles */ ;
380 for (ctr=0; ctr < 132 * (600 / 12); ctr++) /* Wait at least 132 MCLK cycles */ ;
381 for (ctr=0; ctr < 132 * (600 / 12); ctr++) /* Wait at least 132 MCLK cycles */ ;
382 for (ctr=0; ctr < 132 * (600 / 12); ctr++) /* Wait at least 132 MCLK cycles */ ;
383         }
384 }
385
386 static int TODO_setratectr = 0;
387
388 /* Set a frequency divisor for the intended sample rate */
389 //TODO// Not all this code is properly split between generic TLV and specific BT200
390 void tlv320aic2x_set_samplerate (uint32_t samplerate) {
391         uint16_t m, n, p;
392 int chan = 0;
393         SPCR2_1 |= REGVAL_SPCR2_GRST_NOTRESET | REGVAL_SPCR2_FRST_NOTRESET;
394 { uint32_t ctr = 100; while (ctr-- > 0) ; }
395         SPCR1_1 |= REGVAL_SPCR1_RRST_NOTRESET;
396         SPCR2_1 |= REGVAL_SPCR2_XRST_NOTRESET;
397 { uint32_t ctr = 10000; while (ctr-- > 0) ; }
398         DXR1_1 = DXR1_1;        // Flag down XEMPTY
399 tlv320aic2x_setreg (chan, 3, 0x31);     // Channel offline
400 { uint32_t ctr = 1000; while (ctr-- > 0) ; }
401         (void) DRR1_1;          // Flag down RFULL
402         (void) DRR1_1;
403         // Determine the dividors m, n and p
404         n = 1;
405         p = 2;
406         m = ( 30720000 / 16 ) / ( n * p * samplerate );
407 // #ifdef TODO_OPTIMISE_PLL_AWAY
408         if (m % 8 == 0) {
409                 // Save PLL energy without compromising accuracy
410                 p = 8;          // Factor 2 -> 8 so multiplied by 8
411                 m >>= 2;        // Divide by 4
412         }
413 // #endif
414         while (m > 128) {
415                 m >>= 1;
416                 n <<= 1;
417         }
418 { uint8_t ip4 [4]; ip4 [0] = m; ip4 [1] = n; ip4 [2] = p; ip4 [3] = ++TODO_setratectr; bottom_show_ip4 (APP_LEVEL_CONNECTING, ip4); }
419 bottom_printf ("TLV320AIC20K setting: M=%d, N=%d, P=%d\n", (intptr_t) m, (intptr_t) n, (intptr_t) p);
420         m &= 0x7f;
421         n &= 0x0f;      // Ignore range problems?
422         p &= 0x07;
423         // With the codec up and running, configure the sample rate
424         tlv320aic2x_setreg (chan, 4, 0x00 | (n << 3) | p);
425         tlv320aic2x_setreg (chan, 4, 0x80 | m);
426 { uint32_t ctr = 1000; while (ctr-- > 0) ; }
427 // #ifndef TODO_FS_ONLY_DURING_SOUND_IO
428         // SPCR2_1 |= REGVAL_SPCR2_GRST_NOTRESET | REGVAL_SPCR2_FRST_NOTRESET;
429         // SPCR1_1 |= REGVAL_SPCR1_RRST_NOTRESET;
430         // SPCR2_1 |= REGVAL_SPCR2_XRST_NOTRESET;
431         SPCR1_1 &= ~REGVAL_SPCR1_RRST_NOTRESET;
432         SPCR2_1 &= ~REGVAL_SPCR2_XRST_NOTRESET;
433 { uint32_t ctr = 10000; while (ctr-- > 0) ; }
434         SPCR2_1 &= ~ ( REGVAL_SPCR2_GRST_NOTRESET | REGVAL_SPCR2_FRST_NOTRESET );
435 { uint32_t ctr = 10000; while (ctr-- > 0) ; }
436         // SPCR2_1 &= ~ ( REGVAL_SPCR2_FRST_NOTRESET );
437 { uint32_t ctr = 10000; while (ctr-- > 0) ; }
438 // #endif
439         samplerate = 12288000 / samplerate;
440         if (samplerate >= 4096) {
441                 samplerate = 4096;
442         } else if (samplerate == 0) {
443                 samplerate = 1;
444         }
445         SRGR2_1 = REGVAL_SRGR2_CLKSM | REGVAL_SRGR2_FSGM | (samplerate - 1);
446 // #ifndef TODO_FS_ONLY_DURING_SOUND_IO
447         // SPCR2_1 |= REGVAL_SPCR2_GRST_NOTRESET | REGVAL_SPCR2_FRST_NOTRESET;
448         SPCR2_1 |= REGVAL_SPCR2_GRST_NOTRESET;
449 tlv320aic2x_setreg (chan, 3, 0x01);     // Channel online
450 { uint32_t ctr = 1000; while (ctr-- > 0) ; }
451         // tlv320aic2x_setreg (chan, 4, 0x00 | (n << 3) | p);
452         // tlv320aic2x_setreg (chan, 4, 0x80 | m);
453 // { uint32_t ctr = 10000; while (ctr-- > 0) ; }
454         SPCR1_1 |= REGVAL_SPCR1_RRST_NOTRESET;
455         SPCR2_1 |= REGVAL_SPCR2_XRST_NOTRESET;
456 { uint32_t ctr = 1000; while (ctr-- > 0) ; }
457         SPCR2_1 |= REGVAL_SPCR2_FRST_NOTRESET;
458 { uint32_t ctr = 10000; while (ctr-- > 0) ; }
459         DXR1_1 = DXR1_1;        // Flag down XEMPTY
460         (void) DRR1_1;  // Flag down RFULL
461         (void) DRR1_1;
462 { uint32_t ctr = 10000; while (ctr-- > 0) ; }
463 // #endif
464 }
465
466 /* A full frame of 64 samples has been recorded.  See if space exists for
467  * another, otherwise disable DMA until a dmahint_play() restarts it.
468  */
469 interrupt void tic55x_dmac0_isr (void) {
470         uint16_t irq = DMACSR_0;        // Note causes and clear
471         tic55x_top_has_been_interrupted = true;
472         if ((available_record += 64) > (BUFSZ - 64)) {
473                 SPCR2_1 &= ~REGVAL_SPCR2_XRST_NOTRESET;
474                 SPCR2_1 |=  REGVAL_SPCR2_XRST_NOTRESET;
475                 DMACCR_0 &= ~REGVAL_DMACCR_EN;
476 // #ifdef TODO_FS_ONLY_DURING_SOUND_IO
477                 // SPCR1_1 &= ~REGVAL_SPCR1_RRST_NOTRESET;
478                 // if ((SPCR2_1 & REGVAL_SPCR2_XRST_NOTRESET) == 0) {
479                         // SPCR2_1 &= ~ (REGVAL_SPCR2_GRST_NOTRESET | REGVAL_SPCR2_FRST_NOTRESET);
480                 // }
481 // #endif
482         }
483         if (available_record >= threshold_record) {
484                 top_can_record (available_record);
485         }
486 }
487
488 /* A full frame of 64 samples has been played.  See if another is availabe,
489  * otherwise disable DMA until a dmahint_record() restarts it.
490  */
491 interrupt void tic55x_dmac1_isr (void) {
492         uint16_t irq = DMACSR_1;        // Note causes and clear
493         uint16_t toplay;
494         tic55x_top_has_been_interrupted = true;
495         if ((available_play -= 64) < 64) {
496 // #ifdef TODO_FS_ONLY_DURING_SOUND_IO
497                 // SPCR2_1 &= ~REGVAL_SPCR2_XRST_NOTRESET;
498                 // if ((SPCR1_1 & REGVAL_SPCR1_RRST_NOTRESET) == 0) {
499                         // SPCR2_1 &= ~ (REGVAL_SPCR2_GRST_NOTRESET | REGVAL_SPCR2_FRST_NOTRESET);
500                 // }
501 // #endif
502                 DMACCR_1 &= ~REGVAL_DMACCR_EN;
503         }
504         toplay = BUFSZ - available_play;
505         if (BUFSZ - available_play >= threshold_play) {
506                 top_can_play (available_play);
507         }
508 }
509
510 /* Data has been removed from what was recorded.  As a result,
511  * it may be possible to restart DMA channel 1 if it was disabled.
512  */
513 void dmahint_record (void) {
514 return; //TODO// TMP-DISABLE DMAHINTS
515         if (! (DMACCR_0 & REGVAL_DMACCR_EN)) {
516                 if (available_record <= (BUFSZ - 64)) {
517                         if (!(DMACCR_0 & REGVAL_DMACCR_EN)) {
518                                 (void) DRR1_1;  // Flag down RFULL
519                                 (void) DRR1_1;
520                                 DMACCR_0 |= REGVAL_DMACCR_EN;
521 // #ifdef TODO_FS_ONLY_DURING_SOUND_IO
522                                 // SPCR1_1 |= REGVAL_SPCR1_RRST_NOTRESET;
523                                 // SPCR2_1 |= REGVAL_SPCR2_GRST_NOTRESET | REGVAL_SPCR2_FRST_NOTRESET;
524 // #endif
525                         }
526 // bottom_printf ("dmahint_record() enabled DMA from %d bytes out of %d\n", (intptr_t) available_record, (intptr_t) BUFSZ);
527                 }
528         }
529 }
530
531 /* New data has been written for playback.  As a result, it may
532  * be possible to restart DMA channel 0 if it was disabled.
533  */
534 void dmahint_play (void) {
535 return; //TODO// TMP-DISABLE DMAHINTS
536         if ((available_play >= 64) && ! (DMACCR_1 & REGVAL_DMACCR_EN)) {
537                 DXR1_1 = DXR1_1;        // Flag down XEMPTY
538                 DMACCR_1 |= REGVAL_DMACCR_EN;
539 bottom_printf ("dmahint_play() started playing DMA\n");
540 // #ifdef TODO_FS_ONLY_DURING_SOUND_IO
541                 // SPCR2_1 |= REGVAL_SPCR2_XRST_NOTRESET | REGVAL_SPCR2_GRST_NOTRESET | REGVAL_SPCR2_FRST_NOTRESET;
542 // #endif
543         }
544 //TODO:DEBUG// else bottom_printf ("dmahint_play() did not start playing -- available_play = %d\n", (intptr_t) available_play);
545 }
546
547
548
549 /******** HT162x LCD DRIVER LOW-LEVEL FUNCTIONS ********/
550
551
552 /* The program defines an array of LCDCMD_xxx to
553  * initialise the HT162x chip.  The array should be
554  * terminated with HT162x_LCDCMD_DONE.
555  */
556 extern uint16_t ht162x_setup_cmdseq [] = {
557         HT162x_LCDPREFIX_CMD,
558         HT162x_LCDCMD_LCDOFF,
559         HT162x_LCDCMD_NORMAL,
560         HT162x_LCDCMD_RC256K,
561         HT162x_LCDCMD_SYSEN,
562         HT162x_LCDCMD_LCDON,
563         HT162x_LCDCMD_TIMERDIS,
564         HT162x_LCDCMD_WDTDIS,
565         HT162x_LCDCMD_TONEOFF,
566         HT162x_LCDCMD_BIAS3_4,
567         HT162x_LCDCMD_TONE2K,
568         // Terminate the sequence:
569         HT162x_LCDCMD_DONE
570 };
571
572
573 /* Chip-enable or -disable the LCD driver */
574 void ht162x_chipselect (bool selected) {
575         if (selected) {
576                 IODATA &= ~ (1 << 1);
577         } else {
578                 IODATA |=   (1 << 1);
579         }
580 }
581
582
583 /* Send out a databit for the LCD driver, but do not clock it in */
584 static uint16_t kbdisp_outbuf = 0x0000;
585 void ht162x_databit_prepare (bool databit) {
586         if (databit) {
587                 kbdisp_outbuf &= ~0x4040;
588                 kbdisp_outbuf |=  0x8080;
589         } else {
590                 kbdisp_outbuf &= ~0xc0c0;
591         }
592         kbdisp = kbdisp_outbuf;
593 }
594
595 /* Clock in the database that was prepared for the LCD driver */
596 void ht162x_databit_commit (void) {
597         kbdisp_outbuf |= 0x4040;
598         kbdisp = kbdisp_outbuf;
599 }
600
601
602 /******** LCD-SPECIFIC FORM PAINTING ROUTINES ********/
603
604
605 /* Digit notations on the LCD's 7 segment displays */
606 uint8_t lcd7seg_digits [10] = {
607         0xaf, 0xa0, 0xcb, 0xe9, 0xe4,   // 01234
608         0x6d, 0x6f, 0xa8, 0xef, 0xed    // 56789
609 };
610
611 /* Alphabetic notations on the LCD's 7 segment displays */
612 uint8_t lcd7seg_alpha [26] = {
613         0xee, 0x67, 0x0f, 0xe3, 0x4f,   // AbCdE
614         0x4e, 0x2f, 0xe6, 0x06, 0xa1,   // FGHIJ
615         0x6e, 0x07, 0x6a, 0x62, 0x63,   // kLMno
616         0xce, 0xec, 0x42, 0x6d, 0x47,   // PQRST
617         0xa7, 0x23, 0x2b,               // Uvw
618         0x49, 0xe5, 0xc2
619 };
620
621 /* Put a character into display byte idx, with ASCII code ch */
622 void ht162x_putchar (uint8_t idx, uint8_t ch, bool notify) {
623         uint8_t chup = ch & 0xdf;
624         uint8_t lcd7seg;
625         if ((ch >= '0') && (ch <= '9')) {
626                 lcd7seg = lcd7seg_digits [ch - '0'];
627         } else if ((chup >= 'A') && (chup <= 'Z')) {
628                 lcd7seg = lcd7seg_alpha [chup - 'A'];
629         } else if (chup == 0x00) {
630                 lcd7seg = 0x00;  // space for chup one of 0x00 and 0x20
631         } else {
632                 lcd7seg = 0x40;  // dash
633         }
634         ht162x_dispdata [idx] = (ht162x_dispdata [idx] & 0x10) | lcd7seg;
635         if (notify) {
636                 ht162x_dispdata_notify (idx, idx);
637         }
638 }
639
640 uint8_t lcd_bars [8] = {
641         0x00, 0x20, 0x60, 0xe0, 0xe8, 0xec, 0xee, 0xef
642 };
643
644 /* Level indication for volume, showing the upper 3 bits of "level" */
645 void ht162x_audiolevel (uint8_t level) {
646         uint8_t bars = lcd_bars [level >> 5];
647         ht162x_dispdata [15] = (ht162x_dispdata [15] & 0x10) | bars;
648         ht162x_dispdata_notify (15, 15);
649 }
650
651 #define LCDSYM_NETWORK  14
652 #define LCDSYM_HANDSET  13
653 #define LCDSYM_SPEAKER  11
654 #define LCDSYM_FORWARD  10
655 #define LCDSYM_CLOCK    8
656 #define LCDSYM_LOCK     7
657 #define LCDSYM_BINARY   15
658 #define LCDSYM_CN1      4
659 #define LCDSYM_CN2      5
660 #define LCDSYM_HOUR10   0
661 #define LCDSYM_HMSEP    1
662 #define LCDSYM_AM       2
663 #define LCDSYM_PM       3
664 #define LCDSYM_DOT12    12
665 #define LCDSYM_DOT9     9
666 #define LCDSYM_DOT6     6
667
668 /* Special flag setting on the LCD, to flag conditions */
669 void ht162x_led_set (uint8_t lcdidx, led_colour_t col, bool notify) {
670         if (col) {
671                 ht162x_dispdata [lcdidx] |=  0x10;
672         } else {
673                 ht162x_dispdata [lcdidx] &= ~0x10;
674         }
675         if (notify) {
676                 ht162x_dispdata_notify (lcdidx, lcdidx);
677         }
678 }
679
680
681 /******** BOTTOM FUNCTIONS FOR LEDS AND BUTTONS ********/
682
683
684 /* Bottom-half operations to manipulate LED states */
685 void bottom_led_set (led_idx_t ledidx, led_colour_t col) {
686         switch (ledidx) {
687         case LED_IDX_HANDSET:
688                 ht162x_led_set (13, col, true);
689                 break;
690         case LED_IDX_SPEAKERPHONE:
691                 ht162x_led_set (11, col, true);
692                 break;
693         case LED_IDX_MESSAGE:
694                 if (col != 0) {
695                         asm (" bset xf");
696                 } else {
697                         asm (" bclr xf");
698                 }
699                 break;
700         case LED_IDX_BACKLIGHT:
701                 // Set bit DXSTAT=5 in PCR=0x2812 to 1/0
702                 if (col != 0) {
703                         PCR0 |=     1 << REGBIT_PCR_DXSTAT  ;
704                 } else {
705                         PCR0 &= ~ ( 1 << REGBIT_PCR_DXSTAT );
706                 }
707                 break;
708         default:
709                 break;
710         }
711 }
712
713
714 /* See if the phone (actually, the horn) is offhook */
715 bool bottom_phone_is_offhook (void) {
716         // The hook switch is attached to GPIO pin 5
717         return (IODATA & 0x20) != 0;
718 }
719
720
721 /* Scan to see if the top_hook_update() function must be called */
722 #if !defined NEED_HOOK_SCANNER_WHEN_ONHOOK || !defined NEED_HOOK_SCANNER_WHEN_OFFHOOK
723 #  error "The BT200 does not generate an interrupt on hook contact changes"
724 #endif
725 static bool bt200_offhook = false;
726 void bottom_hook_scan (void) {
727         if (bt200_offhook != bottom_phone_is_offhook ()) {
728                 bt200_offhook = !bt200_offhook;
729                 top_hook_update (bt200_offhook);
730         }
731 }
732
733 /* Scan to see if the top_button_press() or top_button_release()
734  * functions must be called.
735  *
736  * The following bits are written to activate one or more keyboard rows:
737  * D0..D4 are sent to the variable "kbdisp" which has the proper address.
738  * The intermediate variable "kbdisp_outbuf" stores a copy of the bits,
739  * and is shared with the LCD routines so unused bits must be retained.
740  *
741  * The following bits of McBSP0 are read from PCR0 as keyboard columns:
742  * C0=CLKRP, C1=CLKXP, C2=FSRP, C3=FSXP, C4=DRSTAT
743  *
744  * The following routine is designed from the assumption that the keyboard
745  * is operated a single key at a time; if not, then any response could be
746  * valid.  Note that we do not suppress multiple keys by sending an error
747  * code, or behaving like with key release.
748  */
749 #if !defined NEED_KBD_SCANNER_BETWEEN_KEYS || !defined NEED_KBD_SCANNER_DURING_KEYPRESS
750 #  error "The BT200 does not generate an interrupt on key changes"
751 #endif
752 #define KBD_COLUMNS_MASK ( REGVAL_PCR_CLKRP | REGVAL_PCR_CLKXP | REGVAL_PCR_FSRP | REGVAL_PCR_FSXP | REGVAL_PCR_DRSTAT )
753 static bool bt200_kbd_pressed = false;
754 static const buttoncode_t keynum2code  [25] = {
755         '1',            '2',            '3',            HAVE_BUTTON_MESSAGE,    HAVE_BUTTON_HOLD,
756         '4',            '5',            '6',            HAVE_BUTTON_TRANSFER,   HAVE_BUTTON_CONFERENCE,
757         '7',            '8',            '9',            HAVE_BUTTON_FLASH,      HAVE_BUTTON_MUTE,
758         '*',            '0',            '#',            HAVE_BUTTON_SEND,       HAVE_BUTTON_SPEAKER,
759         HAVE_BUTTON_DOWN, HAVE_BUTTON_UP, HAVE_BUTTON_CALLERS, HAVE_BUTTON_CALLED, HAVE_BUTTON_MENU
760 };
761 void bottom_keyboard_scan (void) {
762         uint16_t scan;
763         scan = PCR0 & KBD_COLUMNS_MASK;
764         if (bt200_kbd_pressed) {
765                 // Respond if the key is released
766                 if (scan == KBD_COLUMNS_MASK) {
767                         bt200_kbd_pressed = false;
768                         kbdisp_outbuf &= 0xe0e0;                // Make D0..D4 low
769                         kbdisp = kbdisp_outbuf;
770                         top_button_release ();
771                 }
772         } else {
773                 // Respond if a key is being pressed
774                 if (scan != KBD_COLUMNS_MASK) {
775                         uint16_t row;
776                         for (row = 0; row < 5; row++) {
777                                 kbdisp_outbuf |=   0x1f1f;      // Make D0..D4 high
778                                 kbdisp_outbuf &= ~(0x0101 << row); // Set D$row low
779                                 kbdisp = kbdisp_outbuf;
780                                 { volatile int pause = 5; while (pause > 0) pause--; }
781                                 scan = PCR0 & KBD_COLUMNS_MASK;
782                                 if (scan != KBD_COLUMNS_MASK) {
783                                         uint16_t col;
784                                         for (col = 0; col < 5; col++) {
785                                                 if (! (scan & (0x01 << col))) {
786                                                         uint16_t keynum = row * 5 + col;
787                                                         buttonclass_t bcl = ((row <= 3) && (col <= 2))? BUTCLS_DTMF: BUTCLS_FIXED_FUNCTION;
788                                                         buttoncode_t  cde = keynum2code  [keynum];
789                                                         bt200_kbd_pressed = true;
790                                                         top_button_press (bcl, cde);
791                                                         return;
792                                                 }
793                                         }
794                                 }
795                         }
796                         // Failed, usually due to an I/O glitch
797                         kbdisp_outbuf &= 0xe0e0;                // Make D0..D4 low
798                         kbdisp = kbdisp_outbuf;
799                 }
800         }
801 }
802
803
804 /******** BOTTOM FUNCTIONS FOR FORMATTING / PRINTING INFORMATION ********/
805
806
807 /* Send an elapsed period (not a wallclock time) to the display.
808  * For BT200, this is shown in the top digits as MM:SS or as HH:MM.
809  * Note that there are 2 positions, and the first digit can only show a 1.
810  */
811 static app_level_t bt200_period_level = APP_LEVEL_ZERO;
812 void bottom_show_period (app_level_t level, uint8_t h, uint8_t m, uint8_t s) {
813         if (bt200_period_level > level) {
814                 // Ignore those lower values, as this is highly time-dependent
815                 return;
816         }
817         bt200_period_level = level;
818         if ((h == 0) && (m <= 19)) {
819                 h = m;
820                 m = s;
821         }
822         ht162x_led_set (2, false,   false); // "AM" off
823         ht162x_led_set (3, false,   false); // "PM" off
824         ht162x_led_set (1, true,    false); // ":" in "xx:xx"
825         ht162x_led_set (0, h >= 10, false); // "1" in "1x:xx"
826         ht162x_putchar (0, (h %  10) + '0', false);
827         ht162x_putchar (1, (m /  10) + '0', false);
828         ht162x_putchar (2, (m %  10) + '0', false);
829         ht162x_dispdata_notify (0, 3);
830 }
831
832 /* The level of the main portion of the display, along with an array
833  * with the contents at each level
834  */
835 static bt200_displine_level = APP_LEVEL_ZERO;
836 static bool    bt200_level_active [APP_LEVEL_COUNT];
837 static uint8_t bt200_level_maintext [APP_LEVEL_COUNT] [12];
838 static uint8_t bt200_level_dotbits  [APP_LEVEL_COUNT];
839
840 /* Internal routine to move a display level to the display.
841  * Note that no "led" style bits other than the dots in the main
842  * line are influenced.
843  */
844 static void bt200_displine_showlevel (app_level_t level) {
845         uint8_t i;
846         for (i = 0; i < 12; i++) {
847                 ht162x_putchar (14 - i, bt200_level_maintext [level] [i], false);
848         }
849         ht162x_led_set (12, (bt200_level_dotbits [level] & 0x01), false);
850         ht162x_led_set ( 9, (bt200_level_dotbits [level] & 0x02), false);
851         ht162x_led_set ( 6, (bt200_level_dotbits [level] & 0x04), false);
852         ht162x_dispdata_notify (3, 14);
853 }
854
855 /* Internal routine to send a string to the display, either with or
856  * without setting the various dots.  The dots are coded in bits
857  * 0, 1 and 2 of the dotbits parameter, from left to right.
858  */
859 static void bt200_display_showtxt (app_level_t level, char *txt, uint8_t dotbits) {
860         // 1. Print text to the proper level
861         int idx = 0;
862         while ((idx < 12) && *txt) {
863                 bt200_level_maintext [level] [idx++] = *txt++;
864         }
865         while (idx < 12) {
866                 bt200_level_maintext [level] [idx++] = ' ';
867         }
868         bt200_level_dotbits [level] = dotbits;
869         bt200_level_active [level] = true;
870         // 2. If the level is not exceeded by the current, reveal it
871         if (bt200_displine_level <= level) {
872                 bt200_displine_showlevel (level);
873                 bt200_displine_level = level;
874         }
875 }
876
877
878 /* Stop displaying content at the specified level.  In some cases, older
879  * content may now pop up, in others the display could get cleared.
880  */
881 void bottom_show_close_level (app_level_t level) {
882         if (bt200_period_level == level) {
883                 bt200_period_level = APP_LEVEL_ZERO;
884                 ht162x_led_set (0, false, false);
885                 ht162x_led_set (1, false, false);
886                 ht162x_dispdata [0] = 0x00;
887                 ht162x_dispdata [1] = 0x00;
888                 ht162x_dispdata [2] = 0x00;
889                 ht162x_dispdata_notify (0, 2);
890         }
891         if (bt200_displine_level == level) {
892                 bt200_level_active [level] = false;
893                 memset (bt200_level_maintext [level], ' ', 12);
894                 while ((bt200_displine_level > APP_LEVEL_ZERO)
895                                 && !bt200_level_active [bt200_displine_level]) {
896                         bt200_displine_level--;
897                 }
898                 bt200_displine_showlevel (bt200_displine_level);
899         }
900 }
901
902 /* Print an IPv4 address on the display */
903 void bottom_show_ip4 (app_level_t level, uint8_t bytes [4]) {
904         uint8_t idx;
905         char ip [12];
906         char *ipptr = ip;
907         for (idx = 0; idx < 4; idx++) {
908                 *ipptr++ = '0' +  (bytes [idx] / 100);
909                 *ipptr++ = '0' + ((bytes [idx] % 100) / 10);
910                 *ipptr++ = '0' +  (bytes [idx] % 10);
911         }
912         bt200_display_showtxt (level, ip, 0x07);
913 }
914
915 /* Print an IPv6 address, as far as this is possible, on the display
916  *  - Remove the prefix /64 as it is widely known
917  *  -TODO- If middle word is 0xfffe, remove it, display the rest, set dot #2
918  *  -TODO- If first word is 0x0000, remove it, display the rest, set dot #1
919  *  -TODO- If last word is 0x0001, remove it, display the rest, set dot #3
920  *  - If nothing else is possible, use 6 bits per digit, dots and last digit blanc
921 void bottom_show_ip6 (app_level_t level, uint16_t words [8]) {
922         // TODO: Extra cases; for now, just dump 6 bits per 7-segment display
923         uint8_t idxi;
924         uint8_t idxo;
925         uint8_t shfi;
926         uint8_t shfo;
927         ht162x_led_set (12, 0, false);
928         ht162x_led_set ( 9, 0, false);
929         ht162x_led_set ( 6, 0, false);
930         for (idxo = 14; idxo >= 3; idxo--) {
931                 ht162x_dispdata [idxo] &= 0x10;
932         }
933         shfi = 6;
934         shfo = 4;
935         idxi = 4;
936         idxo = 14;
937         while (idxi < 8) {
938                 uint8_t twobits = (words [idxi] >> shfi) & 0x03;
939                 twobits << shfo;
940                 if (twobits & 0x10) {
941                         twobits += 0x80 - 0x10; // bit 7 replaces bit 4
942                 }
943                 ht162x_dispdata [idxo] |= (twobits << shfo);
944                 if (shfi > 0) {
945                         shfi -= 2;
946                 } else {
947                         shfi = 6;
948                         idxi++;
949                 }
950                 if (shfo > 0) {
951                         shfo -= 2;
952                 } else {
953                         shfo = 5;
954                         idxo--;
955                 }
956         }
957         ht162x_dispdata_notify (14, 3);
958 }
959
960 /* A list of fixed messages, matching the fixed_msg_t values */
961
962 static char *bt200_fixed_messages [FIXMSG_COUNT] = {
963         "offline",
964         "registering",
965         "ready",
966         "bootload",
967         "sending call",
968         "ringing",
969         "call ended",
970 };
971
972 /* Print a fixed message on the main line of the display */
973 void bottom_show_fixed_msg (app_level_t level, fixed_msg_t msg) {
974         if (msg < FIXMSG_COUNT) {
975                 bt200_display_showtxt (level, bt200_fixed_messages [msg], 0x00);
976         }
977 }
978
979 /* Print a notification of the number of new / old voicemails */
980 void bottom_show_voicemail (app_level_t level, uint16_t new, uint16_t old) {
981         char msg [12];
982         if (new > 999) {
983                 new = 999;
984         }
985         memcpy (msg, "xxx messages", 12);
986         msg [0] =  new / 100;
987         msg [1] = (new % 100) / 10;
988         msg [2] =  new        % 10;
989         bt200_display_showtxt (level, msg, 0x00);
990 }
991
992 /******** BOTTOM LEVEL MAIN PROGRAM ********/
993
994 /* Setup the connectivity of the TIC55x as used on Grandstream BT20x */
995 void main (void) {
996         uint16_t idx;
997         led_colour_t led = LED_STABLE_ON;
998         //
999         // PLL setup: Crystal is 16.384 MHz, increase that 15x
1000         // 1. Switch to bypass mode by setting the PLLEN bit to 0.
1001         PLLCSR &= ~REGVAL_PLLCSR_PLLEN;
1002         // 2. Set the PLL to its reset state by setting the PLLRST bit to 1.
1003         PLLCSR |= REGVAL_PLLCSR_PLLRST;
1004         // 3. Change the PLL setting through the PLLM and PLLDIV0 bits.
1005         PLLM = REGVAL_PLLM_TIMES_15;
1006         PLLDIV0 = REGVAL_PLLDIVx_DxEN | REGVAL_PLLDIVx_PLLDIVx_1;
1007         // 4. Wait for 1 µs.
1008         { int ctr = 1000; while (ctr--) ; }
1009         // 5. Release the PLL from its reset state by setting PLLRST to 0.
1010         PLLCSR &= ~REGVAL_PLLCSR_PLLRST;
1011         // 6. Wait for the PLL to relock by polling the LOCK bit or by setting up a LOCK interrupt.
1012         while ((PLLCSR & REGVAL_PLLCSR_LOCK) == 0) {
1013                 /* wait */ ;
1014         }
1015         // 7. Switch back to PLL mode by setting the PLLEN bit to 1.
1016         PLLCSR |= REGVAL_PLLCSR_PLLEN;
1017         PLLDIV1 = REGVAL_PLLDIVx_DxEN | REGVAL_PLLDIVx_PLLDIVx_2;
1018         PLLDIV2 = REGVAL_PLLDIVx_DxEN | REGVAL_PLLDIVx_PLLDIVx_4;
1019         PLLDIV3 = REGVAL_PLLDIVx_DxEN | REGVAL_PLLDIVx_PLLDIVx_4;
1020         //TODO// PLLDIV3 = REGVAL_PLLDIVx_DxEN | REGVAL_PLLDIVx_PLLDIVx_2;
1021         //TODO// PLLCSR |= REGVAL_PLLCSR_PLLEN;
1022         // Now we have:
1023         //      CPU clock is 245.76 MHz
1024         //      SYSCLK1   is 122.88 MHz
1025         //      SYSCLK2   is  61.44 MHz
1026         //
1027         // EMIF settings, see SPRU621F, section 2.12 on "EMIF Registers"
1028         //
1029         EGCR1 = 0xff7f;
1030         // EGCR2 = 0x0009; // ECLKOUT2-DIV-4
1031 // EGCR2 = 0x0001;      //ECLKOUT2-DIV-1//
1032 EGCR2 = 0x0005; //ECLKOUT2-DIV-2//
1033         // EGCR1 = ...;   // (defaults)
1034         // EGCR2 = ...;   // (defaults)
1035         // CESCR1 = ...;   // (defaults)
1036         // CESCR2 = ...;   // (defaults)
1037         //
1038         // CE0 selects the network interface
1039         // CE0_1 = 0xff03;   // DEFAULT 8-bit async (and defaults)
1040         // Fail: CE0_1 = 0xc112;   // 16-bit async, rd setup 2, rd strobe 1, rd hold 2
1041         // Fail: CE0_2 = 0x20a2;          // wr setup 2, wr strobe 2, wr hold 2, rd setup 2
1042         CE0_1 = 0x3f2f;
1043         CE0_2 = 0xffff;
1044         // CE0_2 = ...;   // (defaults)
1045         // CE0_SC1 = ...;   // (defaults)
1046         // CE0_SC2 = ...;   // (defaults)
1047         //
1048         // CE1 selects the flash chip
1049         //WORKED?// CE1_1 = 0xff13;   // 16-bit async (and defaults)
1050         CE1_1 = 0x0922;
1051         CE1_2 = 0x31f2;
1052         // CE1_2 = ...;   // (defaults)
1053         // CE1_SC1 = ...;   // (defaults)
1054         // CE1_SC2 = ...;   // (defaults)
1055         //
1056         // CE2 selects the SDRAM chips
1057         //WORKS?// CE2_1 = 0xff33;   // 32-bit SDRAM (and defaults)
1058         CE2_1 = 0xff37;
1059         //TEST// CE2_1 = 0xff13;   // 16-bit async (and defaults)
1060         // CE2_2 = ...;   // (defaults)
1061         // CE2_SC1 = ...;   // (defaults)
1062         // CE2_SC2 = ...;   // (defaults)
1063         // Possible: SDC1, SDC2, SDRC1, SDRC2, SDX1, SDX2
1064         SDC1 = 0x6ffe;
1065         SDC2 = 0x8712;
1066         SDRC1 = 0xf5dc;
1067         SDRC2 = 0xffff;
1068         SDX1 = 0xb809;
1069         CESCR1 = 0xfffc;
1070         //
1071         // CE3 selects the D-flipflops for keyboard and LCD
1072         CE3_1 = 0xff13;   // 16-bit async (and defaults)
1073         //BT200ORIG// CE3_1 = 0x0220;
1074         //BT200ORIG// CE3_2 = 0x0270;
1075         // CE3_2 = ...;   // (defaults)
1076         // CE3_SC1 = ...;   // (defaults)
1077         // CE3_SC2 = ...;   // (defaults)
1078         //
1079         // Setup McBSP1 for linking to TLV320AIC20K
1080         // Generate a CLKG at 12.288 MHz, and FS at 8 kHz
1081         // following the procedure of spru592e section 3.5
1082         //
1083         DXR1_1 = 0x0000;
1084         SPCR1_1 = 0x0000;       // Disable/reset receiver, required in spru592e
1085         SPCR2_1 = 0x0000;       // Disable/reset sample rate generator
1086         SRGR1_1 = REGVAL_SRGR1_FWID_1 | REGVAL_SRGR1_CLKGDIV_4;
1087         SRGR2_1 = REGVAL_SRGR2_CLKSM | REGVAL_SRGR2_FSGM | REGVAL_SRGR2_FPER_1535;
1088         //COPIED_BELOW// PCR1 = /*TODO: (1 << REGBIT_PCR_IDLEEN) | */ (1 << REGBIT_PCR_FSXM) /* | (1 << REGBIT_PCR_FSRM) */ | (1 << REGBIT_PCR_CLKXM) /* | (1 << REGBIT_PCR_CLKRM) */ /* receive on falling, xmit on rising edge -- | (1 << REGBIT_PCR_CLKXP) | (1 << REGBIT_PCR_CLKRP) */ ;
1089         PCR1 = (1 << REGBIT_PCR_FSXM) | (1 << REGBIT_PCR_CLKXM);
1090 { uint32_t ctr = 10000; while (ctr-- > 0) ; }
1091 // SPCR2_1 |= REGVAL_SPCR2_GRST_NOTRESET | REGVAL_SPCR2_FRST_NOTRESET;
1092         RCR1_1 = (0 << 8) | (2 << 5);   // Read  1 frame of 16 bits per FS
1093         XCR1_1 = (0 << 8) | (2 << 5);   // Write 1 frame of 16 bits per FS
1094         RCR2_1 = 0x0001;                // Read  with 1 clockcycle delay
1095         XCR2_1 = 0x0001;                // Write with 1 clockcycle delay
1096         //TODO:NOT-SPI-BUT-CONTINUOUS-CLOCK// SPCR1_1 |= REGVAL_SPCR1_CLKSTP_NODELAY;
1097         //
1098         // Setup I2C for communication with the TLV320AIC20K codec
1099         // Prescale SYSCLK2 down from 61.44 MHz to 10.24 MHz so it falls
1100         // in the required 7 Mhz to 12 MHz range; support a 100 kHz I2C bus
1101         // by setting low/high period to 51 such periods.
1102         // Note: The only peripheral TLV320AIC20K could go up to 900 kHz
1103         I2CMDR = REGVAL_I2CMDR_MST | /* reset to set PSC */  REGVAL_I2CMDR_FREE | REGVAL_I2CMDR_BC_8;
1104         I2CPSC = 5;
1105         I2CCLKH = 51 - 5;       /* TODO: 900 kHz is possible on TLV320AIC20K */
1106         I2CCLKL = 51 - 5;
1107         I2COAR = REGVAL_I2COAR;
1108         I2CMDR = REGVAL_I2CMDR_MST | REGVAL_I2CMDR_NORESET | REGVAL_I2CMDR_FREE | REGVAL_I2CMDR_BC_8;
1109         //
1110         // Setup DMA channel 0 for playing from DSP to TLV320AIC2x
1111         // Setup DMA channel 1 for recording from TLV320AIC2x to DSP
1112         //
1113         // Both channels have a block (their entire RAM buffer) comprising
1114         // of 25 frames, which each are 64 samples of 16 bits in size.
1115         // At 8 kHz sample rate, frames cause 125 interrupts per second;
1116         // at 48 kHz this rises to 750 (per channel), still comfortable.
1117         // The total buffer is 1600 samples of 16 bits long.  Each time a
1118         // frame send finishes, an interrupt checks if there is another
1119         // frame of 64 samples ready to go; if not, it will disable the
1120         // DMA channel.  Hint routines serve to restart DMA after that.
1121         // Conversely, the DMA interrupt handlers can make top-calls to
1122         // indicate that data is ready for reading or that space is
1123         // available for writing.
1124         // The settings below prepare DMA for continuous playing and
1125         // recording, but with the setup disabled until hinted.
1126         //
1127         DMAGCR = REGVAL_DMAGCR_FREE;
1128         DMAGTCR = 0x00;         // No timeout support
1129 #ifdef TODO_DMA_CONFIGUREREN_BIJ_OPSTART
1130         DMACCR_0 = REGVAL_DMACCR_SRCAMODE_CONST | REGVAL_DMACCR_DSTAMODE_POSTINC | REGVAL_DMACCR_PRIO | REGVAL_DMACCR_SYNC_MCBSP1_REV | REGVAL_DMACCR_REPEAT | REGVAL_DMACCR_AUTOINIT;
1131         DMACCR_1 = REGVAL_DMACCR_SRCAMODE_POSTINC | REGVAL_DMACCR_DSTAMODE_CONST | REGVAL_DMACCR_PRIO | REGVAL_DMACCR_SYNC_MCBSP1_TEV | REGVAL_DMACCR_REPEAT | REGVAL_DMACCR_AUTOINIT;
1132         DMACICR_0 = REGVAL_DMACICR_FRAMEIE;
1133         DMACICR_1 = REGVAL_DMACICR_FRAMEIE;
1134         //TODO// DMACSDP_0 = REGVAL_DMACSDP_SRC_PERIPH | REGVAL_DMACSDP_DST_DARAM1 | REGVAL_DMACSDP_DATATYPE_16BIT;
1135         //TODO// DMACSDP_1 = REGVAL_DMACSDP_SRC_DARAM0 | REGVAL_DMACSDP_DST_PERIPH | REGVAL_DMACSDP_DATATYPE_16BIT;
1136         DMACSDP_0 = REGVAL_DMACSDP_SRC_PERIPH | REGVAL_DMACSDP_DST_EMIF | REGVAL_DMACSDP_DATATYPE_16BIT;
1137         DMACSDP_1 = REGVAL_DMACSDP_SRC_EMIF | REGVAL_DMACSDP_DST_PERIPH | REGVAL_DMACSDP_DATATYPE_16BIT;
1138         DMACSSAL_0 = ((intptr_t) &DRR1_1) <<  1;
1139         DMACSSAU_0 = ((intptr_t) &DRR1_1) >> 15;
1140         DMACDSAL_0 = (uint16_t) (((intptr_t) samplebuf_record) <<  1);
1141         DMACDSAU_0 = (uint16_t) (((intptr_t) samplebuf_record) >> 15);
1142         DMACSSAL_1 = (uint16_t) (((intptr_t) samplebuf_play)   <<  1);
1143         DMACSSAU_1 = (uint16_t) (((intptr_t) samplebuf_play)   >> 15);
1144         DMACDSAL_1 = ((intptr_t) &DXR1_1) <<  1;
1145         DMACDSAU_1 = ((intptr_t) &DXR1_1) >> 15;
1146 #if TRY_SOMETHING_ELSE_TO_GET_INTERRUPTS
1147         DMACEN_0 = 64;           /* 64 elements (samples) per frame (continue-checks) */
1148         DMACEN_1 = 64;
1149         DMACFN_0 = (BUFSZ / 64); /* 25 frames (continue-checks) per block (buffer) */
1150         DMACFN_1 = (BUFSZ / 64);
1151 #else
1152         DMACEN_0 = 64;
1153         DMACEN_1 = 64;
1154         DMACFN_0 = 1;
1155         DMACFN_1 = 1;
1156 #endif
1157 #endif
1158         /* TODO? */
1159         //
1160         // Further initiation follows
1161         //
1162         IODIR  |= (1 << 7) | (1 << 1);
1163         IODATA  =            (1 << 1);  // Updated below small delay
1164         for (idx = 0; idx < APP_LEVEL_COUNT; idx++) {
1165                 bt200_level_active [idx] = false;
1166         }
1167         IODATA |= (1 << 7) | (1 << 1);  // See above small delay
1168         asm (" bclr xf");  // Switch off MESSAGE LED
1169 { uint16_t ctr = 250; while (ctr > 0) { ctr--; } }      
1170         bottom_critical_region_begin (); // _disable_interrupts ();
1171         IER0 = IER1 = 0x0000;
1172         tic55x_setup_timers ();
1173         tic55x_setup_interrupts ();
1174         ht162x_setup_lcd ();
1175         // tlv320aic2x_set_samplerate (8000);
1176         tlv320aic2x_setup_sound ();
1177         ksz8842_setup_network ();
1178         // Enable INT0..INT3
1179         //TODO:TEST// IER0 |= 0x0a0c;
1180         //TODO:TEST// IER1 |= 0x0005;
1181         IER0 |= (1 << REGBIT_IER0_DMAC1) | (1 << REGBIT_IER0_INT0) | (1 << REGBIT_IER0_TINT0); // 0x0214;
1182         IER1 |= (1 << REGBIT_IER1_DMAC0); // 0x0004;
1183         PCR0 = (1 << REGBIT_PCR_XIOEN) | (1 << REGBIT_PCR_RIOEN);
1184
1185 #if 0
1186 {uint8_t idx, dig, bar;
1187 idx=0; dig=0; bar=0;
1188 memset (ht162x_dispdata, 0x00, sizeof (ht162x_dispdata));
1189 while (true) {
1190 uint32_t ctr;
1191 ht162x_putchar (14 - idx, (dig < 10)? (dig + '0'): (dig + 'A' - 11));
1192 ht162x_audiolevel ((bar < 8)? (bar << 5): ((14-bar) << 5));
1193 // bottom_led_set (LED_IDX_MESSAGE, LED_STABLE_OFF);
1194 ht162x_dispdata_notify (14 - idx, 14 - idx);
1195 ht162x_dispdata_notify (15, 15);
1196 // bottom_led_set (LED_IDX_MESSAGE, LED_STABLE_ON );
1197 idx = (idx + 1) % 12;
1198 dig = (dig + 1) % 38;
1199 bar = (bar + 1) % 14;
1200 ctr = 650000; while (ctr>0) ctr--;
1201 }
1202 }
1203 #endif
1204
1205         //TODO// IER0 = 0xdefc;
1206         //TODO// IER1 = 0x00ff;
1207 /* TODO: Iterate over flash partitions that can boot, running each in turn: */
1208         top_main ();
1209 }
1210