Rockbox open source high quality audio player as a Music Player Daemon
mpris rockbox mpd libadwaita audio rust zig deno
2
fork

Configure Feed

Select the types of activity you want to include in your feed.

Sansa Connect: Refactor AVR command handling

Add defines for all commands handled by AVR, including the unknown
opcodes (0xC5, 0xD3, 0xD4, 0xD5, 0xD6).

Properly synchronize with AVR and keep repeating command until it looks
like AVR has accepted it.

Change-Id: I3d42e973f135e33092c71c9887421906a900ab58

+232 -101
+232 -99
firmware/target/arm/tms320dm320/sansa-connect/avr-sansaconnect.c
··· 24 24 #include "system.h" 25 25 #include "power.h" 26 26 #include "kernel.h" 27 + #include "panic.h" 28 + /*#define LOGF_ENABLE*/ 27 29 #include "logf.h" 28 30 #include "avr-sansaconnect.h" 29 31 #include "uart-target.h" ··· 48 50 #define dbgprintf(...) 49 51 #endif 50 52 51 - #define CMD_SYNC 0xAA 52 - #define CMD_CLOSE 0xCC 53 - #define CMD_LCM_POWER 0xC9 54 - #define LCM_POWER_OFF 0x00 55 - #define LCM_POWER_ON 0x01 56 - #define LCM_POWER_SLEEP 0x02 57 - #define LCM_POWER_WAKE 0x03 58 - #define LCM_REPOWER_ON 0x04 53 + #define AVR_DELAY_US 100 54 + 55 + #define CMD_SYNC 0xAA 56 + #define CMD_CLOSE 0xCC 57 + #define CMD_FILL 0xFF 58 + 59 + /* Actual command opcodes handled by AVR */ 60 + #define CMD_STATE 0xBB 61 + #define CMD_VER 0xBC 62 + #define CMD_MONOTIME 0xBD 63 + #define CMD_PGMWAKE 0xBF 64 + #define CMD_HDQ_READ 0xC0 65 + #define CMD_HDQ_WRITE 0xC1 66 + #define CMD_HDQ_STATUS 0xC2 67 + #define CMD_GET_LAST_RESET_TYPE 0xC4 68 + #define CMD_UNKNOWN_C5 0xC5 69 + #define CMD_GET_BATTERY_TEMP 0xC8 70 + #define CMD_LCM_POWER 0xC9 71 + #define CMD_AMP_ENABLE 0xCA 72 + #define CMD_WHEEL_EN 0xD0 73 + #define CMD_SET_INTCHRG 0xD1 74 + #define CMD_GET_INTCHRG 0xD2 75 + #define CMD_UNKNOWN_D3 0xD3 76 + #define CMD_UNKNOWN_D4 0xD4 77 + #define CMD_UNKNOWN_D5 0xD5 78 + #define CMD_UNKNOWN_D6 0xD6 79 + #define CMD_CODEC_RESET 0xD7 80 + #define CMD_ADC_START 0xD8 81 + #define CMD_ADC_RESULT 0xD9 82 + #define CMD_SYS_CTRL 0xDA 83 + #define CMD_SET_USBCHRG 0xE2 84 + #define CMD_GET_USBCHRG 0xE3 85 + #define CMD_MONORSTCNT 0xE4 59 86 60 - #define CMD_STATE 0xBB 61 - #define CMD_VER 0xBC 62 - #define CMD_WHEEL_EN 0xD0 63 - #define CMD_SET_INTCHRG 0xD1 64 - #define CMD_CODEC_RESET 0xD7 65 - #define CMD_AMP_ENABLE 0xCA 66 - #define CMD_FILL 0xFF 87 + /* CMD_LCM_POWER parameters */ 88 + #define LCM_POWER_OFF 0x00 89 + #define LCM_POWER_ON 0x01 90 + #define LCM_POWER_SLEEP 0x02 91 + #define LCM_POWER_WAKE 0x03 92 + #define LCM_REPOWER_ON 0x04 67 93 68 - #define CMD_SYS_CTRL 0xDA 69 - #define SYS_CTRL_POWEROFF 0x00 94 + /* CMD_SYS_CTRL parameters */ 95 + #define SYS_CTRL_POWEROFF 0x00 96 + #define SYS_CTRL_RESET 0x01 97 + #define SYS_CTRL_SLEEP 0x02 98 + #define SYS_CTRL_DISABLE_WD 0x03 99 + #define SYS_CTRL_KICK_WD 0x04 100 + #define SYS_CTRL_EN_HDQ_THERM 0x05 101 + #define SYS_CTRL_EN_TS_THERM 0x06 102 + #define SYS_CTRL_FRESET 0x80 70 103 71 104 /* protects spi avr commands from concurrent access */ 72 105 static struct mutex avr_mtx; ··· 93 126 #define BATTERY_LEVEL_PERCENTAGE_MASK 0x7F 94 127 static uint8_t avr_battery_level = 100; 95 128 96 - static inline unsigned short be2short(unsigned char* buf) 129 + static inline uint16_t be2short(uint8_t *buf) 97 130 { 98 - return (unsigned short)((buf[0] << 8) | buf[1]); 131 + return (uint16_t)((buf[0] << 8) | buf[1]); 99 132 } 100 133 101 134 #define BUTTON_DIRECT_MASK (BUTTON_LEFT | BUTTON_UP | BUTTON_RIGHT | BUTTON_DOWN | BUTTON_SELECT | BUTTON_VOL_UP | BUTTON_VOL_DOWN | BUTTON_NEXT | BUTTON_PREV) 102 135 103 136 #ifndef BOOTLOADER 104 - static void handle_wheel(unsigned char wheel) 137 + static void handle_wheel(uint8_t wheel) 105 138 { 106 139 static int key = 0; 107 - static unsigned char velocity = 0; 108 - static unsigned long wheel_delta = 1ul << 24; 109 - static unsigned char wheel_prev = 0; 110 - static long nextbacklight_hw_on = 0; 140 + static uint8_t velocity = 0; 141 + static uint32_t wheel_delta = 1ul << 24; 142 + static uint8_t wheel_prev = 0; 143 + static unsigned long nextbacklight_hw_on = 0; 111 144 static int prev_key = -1; 112 145 static int prev_key_post = 0; 113 146 ··· 168 201 } 169 202 #endif 170 203 171 - /* buf must be 11-byte array of byte (reply from avr_hid_get_state() */ 172 - static void parse_button_state(unsigned char *buf) 204 + /* buf must be 8-byte state array (reply from avr_hid_get_state() */ 205 + static void parse_button_state(uint8_t *state) 173 206 { 174 - unsigned short main_btns_state = be2short(&buf[4]); 207 + uint16_t main_btns_state = be2short(&state[2]); 175 208 #ifdef BUTTON_DEBUG 176 - unsigned short main_btns_changed = be2short(&buf[6]); 209 + uint16_t main_btns_changed = be2short(&state[4]); 177 210 #endif 178 211 179 212 /* make sure other bits doesn't conflict with our "free bits" buttons */ 180 213 main_btns_state &= BUTTON_DIRECT_MASK; 181 214 182 - if (buf[3] & 0x01) /* is power button pressed? */ 215 + if (state[1] & 0x01) /* is power button pressed? */ 183 216 { 184 217 main_btns_state |= BUTTON_POWER; 185 218 } ··· 188 221 189 222 #ifndef BOOTLOADER 190 223 /* check if stored hold_switch state changed (prevents lost changes) */ 191 - if ((buf[3] & 0x20) /* hold change notification */ || 192 - (hold_switch != ((buf[3] & 0x02) >> 1))) 224 + if ((state[1] & 0x20) /* hold change notification */ || 225 + (hold_switch != ((state[1] & 0x02) >> 1))) 193 226 { 194 227 #endif 195 - hold_switch = (buf[3] & 0x02) >> 1; 228 + hold_switch = (state[1] & 0x02) >> 1; 196 229 #ifdef BUTTON_DEBUG 197 230 dbgprintf("HOLD changed (%d)", hold_switch); 198 231 #endif ··· 201 234 } 202 235 #endif 203 236 #ifndef BOOTLOADER 204 - if ((hold_switch == false) && (buf[3] & 0x80)) /* scrollwheel change */ 237 + if ((hold_switch == false) && (state[1] & 0x80)) /* scrollwheel change */ 205 238 { 206 - handle_wheel(buf[2]); 239 + handle_wheel(state[0]); 207 240 } 208 241 #endif 209 242 210 243 #ifdef BUTTON_DEBUG 211 - if (buf[3] & 0x10) /* power button change */ 244 + if (state[1] & 0x10) /* power button change */ 212 245 { 213 246 /* power button state has changed */ 214 247 main_btns_changed |= BUTTON_POWER; ··· 230 263 #endif 231 264 } 232 265 233 - static void spi_txrx(unsigned char *buf_tx, unsigned char *buf_rx, int n) 266 + static bool avr_command_reads_data(uint8_t opcode) 267 + { 268 + switch (opcode) 269 + { 270 + case CMD_STATE: 271 + case CMD_VER: 272 + case CMD_GET_LAST_RESET_TYPE: 273 + case CMD_GET_INTCHRG: 274 + case CMD_MONOTIME: 275 + case CMD_UNKNOWN_C5: 276 + case CMD_MONORSTCNT: 277 + case CMD_HDQ_STATUS: 278 + case CMD_GET_BATTERY_TEMP: 279 + case CMD_GET_USBCHRG: 280 + case CMD_ADC_RESULT: 281 + return true; 282 + default: 283 + return false; 284 + } 285 + } 286 + 287 + static size_t avr_command_data_size(uint8_t opcode) 288 + { 289 + switch (opcode) 290 + { 291 + case CMD_STATE: return 8; 292 + case CMD_VER: return 1; 293 + case CMD_MONOTIME: return 4; 294 + case CMD_PGMWAKE: return 4; 295 + case CMD_HDQ_READ: return 1; 296 + case CMD_HDQ_WRITE: return 2; 297 + case CMD_HDQ_STATUS: return 2; 298 + case CMD_GET_LAST_RESET_TYPE: return 1; 299 + case CMD_UNKNOWN_C5: return 1; 300 + case CMD_GET_BATTERY_TEMP: return 2; 301 + case CMD_LCM_POWER: return 1; 302 + case CMD_AMP_ENABLE: return 1; 303 + case CMD_WHEEL_EN: return 1; 304 + case CMD_SET_INTCHRG: return 1; 305 + case CMD_GET_INTCHRG: return 1; 306 + case CMD_UNKNOWN_D3: return 1; 307 + case CMD_UNKNOWN_D4: return 1; 308 + case CMD_UNKNOWN_D5: return 2; 309 + case CMD_UNKNOWN_D6: return 2; 310 + case CMD_CODEC_RESET: return 0; 311 + case CMD_ADC_START: return 1; 312 + case CMD_ADC_RESULT: return 2; 313 + case CMD_SYS_CTRL: return 1; 314 + case CMD_SET_USBCHRG: return 1; 315 + case CMD_GET_USBCHRG: return 1; 316 + case CMD_MONORSTCNT: return 2; 317 + default: 318 + panicf("Invalid AVR opcode %02X", opcode); 319 + return 0; 320 + } 321 + } 322 + 323 + static uint8_t spi_read_byte(void) 324 + { 325 + uint16_t rxdata; 326 + 327 + do 328 + { 329 + rxdata = IO_SERIAL1_RX_DATA; 330 + } 331 + while (rxdata & (1<<8)); 332 + 333 + return rxdata & 0xFF; 334 + } 335 + 336 + static bool avr_run_command(uint8_t opcode, uint8_t *data, size_t data_length) 234 337 { 235 - int i; 236 - unsigned short rxdata; 338 + bool success = true; 339 + const bool is_read = avr_command_reads_data(opcode); 340 + size_t i; 341 + uint8_t rx; 342 + 343 + /* Verify command data size and also make sure command is valid */ 344 + if (avr_command_data_size(opcode) != data_length) 345 + { 346 + panicf("AVR %02x invalid data length", opcode); 347 + } 237 348 238 349 mutex_lock(&avr_mtx); 239 350 240 351 bitset16(&IO_CLK_MOD2, CLK_MOD2_SIF1); 241 352 IO_SERIAL1_TX_ENABLE = 0x0001; 242 353 243 - for (i = 0; i<n; i++) 354 + IO_SERIAL1_TX_DATA = CMD_SYNC; 355 + spi_read_byte(); 356 + /* Allow AVR to process CMD_SYNC */ 357 + udelay(AVR_DELAY_US); 358 + 359 + IO_SERIAL1_TX_DATA = opcode; 360 + rx = spi_read_byte(); 361 + if (rx != CMD_SYNC) 244 362 { 245 - IO_SERIAL1_TX_DATA = buf_tx[i]; 363 + /* AVR failed to register CMD_SYNC */ 364 + success = false; 365 + } 366 + /* Allow AVR to process opcode */ 367 + udelay(AVR_DELAY_US); 246 368 247 - /* 100 us wait for AVR */ 248 - udelay(100); 249 - 250 - do 369 + if (is_read) 370 + { 371 + for (i = 0; i < data_length; i++) 372 + { 373 + IO_SERIAL1_TX_DATA = CMD_FILL; 374 + data[i] = spi_read_byte(); 375 + udelay(AVR_DELAY_US); 376 + } 377 + } 378 + else 379 + { 380 + for (i = 0; i < data_length; i++) 251 381 { 252 - rxdata = IO_SERIAL1_RX_DATA; 253 - } while (rxdata & (1<<8)); 382 + IO_SERIAL1_TX_DATA = data[i]; 383 + spi_read_byte(); 384 + udelay(AVR_DELAY_US); 385 + } 386 + } 254 387 255 - if (buf_rx != NULL) 256 - buf_rx[i] = rxdata & 0xFF; 257 - 258 - /* 100 us wait to give AVR time to process data */ 259 - udelay(100); 388 + IO_SERIAL1_TX_DATA = CMD_CLOSE; 389 + rx = spi_read_byte(); 390 + udelay(AVR_DELAY_US); 391 + if (is_read) 392 + { 393 + success = success && (rx == CMD_CLOSE); 260 394 } 261 395 262 396 IO_SERIAL1_TX_ENABLE = 0; 263 397 bitclr16(&IO_CLK_MOD2, CLK_MOD2_SIF1); 264 398 265 399 mutex_unlock(&avr_mtx); 400 + 401 + return success; 266 402 } 267 403 268 - void avr_hid_sync(void) 404 + 405 + static void avr_hid_sync(void) 269 406 { 270 - int i; 271 - unsigned char prg[4] = {CMD_SYNC, CMD_VER, CMD_FILL, CMD_CLOSE}; 407 + uint8_t data; 408 + while (!avr_run_command(CMD_VER, &data, sizeof(data))) 409 + { 410 + /* TODO: Program HID if failing for long time. 411 + * To do so, unfortunately, AVR firmware would have to be written 412 + * from scratch as OF blob cannot be used due to licensing. 413 + */ 414 + } 272 415 273 - /* Send SYNC three times */ 274 - for (i = 0; i<3; i++) 416 + } 417 + 418 + static void avr_execute_command(uint8_t opcode, uint8_t *data, size_t data_length) 419 + { 420 + while (!avr_run_command(opcode, data, data_length)) 275 421 { 276 - spi_txrx(prg, NULL, sizeof(prg)); 422 + /* Resync and try again */ 423 + avr_hid_sync(); 277 424 } 278 425 } 279 426 ··· 324 471 325 472 static void avr_hid_get_state(void) 326 473 { 327 - static unsigned char cmd[11] = {CMD_SYNC, CMD_STATE, 328 - CMD_FILL, CMD_FILL, CMD_FILL, CMD_FILL, CMD_FILL, CMD_FILL, CMD_FILL, CMD_FILL, 329 - CMD_CLOSE}; 474 + uint8_t state[8]; 475 + avr_execute_command(CMD_STATE, state, sizeof(state)); 330 476 331 - static unsigned char buf[11]; 332 - 333 - /* In very unlikely case the command has to be repeated */ 334 - do 335 - { 336 - spi_txrx(cmd, buf, sizeof(cmd)); 337 - } 338 - while ((buf[1] != CMD_SYNC) || (buf[10] != CMD_CLOSE)); 339 - 340 - avr_battery_status = buf[8]; 341 - avr_battery_level = buf[9]; 342 - parse_button_state(buf); 477 + avr_battery_status = state[6]; 478 + avr_battery_level = state[7]; 479 + parse_button_state(state); 343 480 } 344 481 345 482 static void avr_hid_enable_wheel(void) 346 483 { 347 - unsigned char wheel_en[4] = {CMD_SYNC, CMD_WHEEL_EN, 0x01, CMD_CLOSE}; 348 - 349 - spi_txrx(wheel_en, NULL, sizeof(wheel_en)); 484 + uint8_t enable = 0x01; 485 + avr_execute_command(CMD_WHEEL_EN, &enable, sizeof(enable)); 350 486 } 351 487 352 488 /* command that is sent by "hidtool -J 1" issued on every OF boot */ 353 489 void avr_hid_enable_charger(void) 354 490 { 355 - unsigned char charger_en[4] = {CMD_SYNC, CMD_SET_INTCHRG, 0x01, CMD_CLOSE}; 491 + uint8_t enable = 0x01; 492 + avr_execute_command(CMD_SET_INTCHRG, &enable, sizeof(enable)); 493 + } 356 494 357 - spi_txrx(charger_en, NULL, sizeof(charger_en)); 495 + static void avr_hid_lcm_power(uint8_t parameter) 496 + { 497 + avr_execute_command(CMD_LCM_POWER, &parameter, sizeof(parameter)); 358 498 } 359 499 360 500 void avr_hid_lcm_sleep(void) 361 501 { 362 - unsigned char lcm_sleep[4] = {CMD_SYNC, CMD_LCM_POWER, LCM_POWER_SLEEP, CMD_CLOSE}; 363 - 364 - spi_txrx(lcm_sleep, NULL, sizeof(lcm_sleep)); 502 + avr_hid_lcm_power(LCM_POWER_SLEEP); 365 503 } 366 504 367 - 368 505 void avr_hid_lcm_wake(void) 369 506 { 370 - unsigned char lcm_wake[4] = {CMD_SYNC, CMD_LCM_POWER, LCM_POWER_WAKE, CMD_CLOSE}; 371 - 372 - spi_txrx(lcm_wake, NULL, sizeof(lcm_wake)); 507 + avr_hid_lcm_power(LCM_POWER_WAKE); 373 508 } 374 509 375 510 void avr_hid_lcm_power_on(void) 376 511 { 377 - unsigned char lcm_power_on[4] = {CMD_SYNC, CMD_LCM_POWER, LCM_POWER_ON, CMD_CLOSE}; 378 - 379 - spi_txrx(lcm_power_on, NULL, sizeof(lcm_power_on)); 512 + avr_hid_lcm_power(LCM_POWER_ON); 380 513 } 381 514 382 515 void avr_hid_lcm_power_off(void) 383 516 { 384 - unsigned char lcm_power_off[4] = {CMD_SYNC, CMD_LCM_POWER, LCM_POWER_OFF, CMD_CLOSE}; 385 - 386 - spi_txrx(lcm_power_off, NULL, sizeof(lcm_power_off)); 517 + avr_hid_lcm_power(LCM_POWER_OFF); 387 518 } 388 519 389 520 void avr_hid_reset_codec(void) 390 521 { 391 - unsigned char codec_reset[4] = {CMD_SYNC, CMD_CODEC_RESET, CMD_CLOSE, CMD_FILL}; 522 + avr_execute_command(CMD_CODEC_RESET, NULL, 0); 523 + } 392 524 393 - spi_txrx(codec_reset, NULL, sizeof(codec_reset)); 525 + void avr_hid_set_amp_enable(uint8_t enable) 526 + { 527 + avr_execute_command(CMD_AMP_ENABLE, &enable, sizeof(enable)); 394 528 } 395 529 396 - void avr_hid_set_amp_enable(unsigned char enable) 530 + static void avr_hid_sys_ctrl(uint8_t parameter) 397 531 { 398 - unsigned char amp_enable[4] = {CMD_SYNC, CMD_AMP_ENABLE, enable, CMD_CLOSE}; 399 - 400 - spi_txrx(amp_enable, NULL, sizeof(amp_enable)); 532 + avr_execute_command(CMD_SYS_CTRL, &parameter, sizeof(parameter)); 401 533 } 402 534 403 535 void avr_hid_power_off(void) 404 536 { 405 - unsigned char prg[4] = {CMD_SYNC, CMD_SYS_CTRL, SYS_CTRL_POWEROFF, CMD_CLOSE}; 406 - 407 - spi_txrx(prg, NULL, sizeof(prg)); 537 + avr_hid_sys_ctrl(SYS_CTRL_POWEROFF); 408 538 } 409 539 410 540 #ifndef BOOTLOADER ··· 490 620 IF_COP(, CPU)); 491 621 #endif 492 622 IO_GIO_DIR0 |= 0x01; /* Set GIO0 as input */ 623 + 624 + /* Get in sync with AVR */ 625 + avr_hid_sync(); 493 626 494 627 /* Enable wheel */ 495 628 avr_hid_enable_wheel();
-1
firmware/target/arm/tms320dm320/sansa-connect/avr-sansaconnect.h
··· 24 24 25 25 #include "config.h" 26 26 27 - void avr_hid_sync(void); 28 27 void avr_hid_init(void); 29 28 30 29 void avr_hid_enable_charger(void);
-1
firmware/target/arm/tms320dm320/sansa-connect/lcd-sansaconnect.c
··· 123 123 /* Copy Rockbox frame buffer to the second framebuffer */ 124 124 lcd_update(); 125 125 126 - avr_hid_sync(); 127 126 avr_hid_lcm_power_on(); 128 127 129 128 /* set framebuffer address - OF sets RAM start address to 0x1000000 */