Firefly-R3288 的 JTAG 建置

最近要在 Rockchip RK3288 上面跑 RTOS,為了讓同事可以在上面方便的除錯,我負責的部分就是要開通 RK3288 的 JTAG,並運行在 firefly-RK3288 的開發板上面
文章中說明了從 0 開始的設定過程,途中遇到的問題,以及要查找哪些資料,最後成功連線 JTAG

開發順序

再做設定之前,先說明一下我們所用的環境好了,我們要先了解軟硬體支援在下手,才知道我們是不是白做工,而我們所使用的環境是:

  1. JTAG: SEGGER JLINK BASE (hardware version: v9.4)
  2. GDBServer: JLINK GDBServer
  3. Rockchip RK3288 (ARM Coretex-A17, ARMv7 ISA)
  4. Board: Firefly-RK3288
  5. Debug 用具: USB 轉 TTL 傳輸線 (device: ttyUSB0, baud-rate: 115200 8,N,1)

開發順序是:

  1. 我們要先了解開發版資訊,在開發板上的 PIN 腳位置以及對應到晶片的 GPIO 位置
  2. 之後要進行初始化,我們選擇使用 RK3288 的 U-boot (bootloader) 來協助我們進行初始化
  3. 我們停在 U-boot command,等待 GDBServer 的回饋
  4. 透過 Ubuntu 的 JLINK GDBServer 連接上

開發版資訊

http://en.t-firefly.com/doc/download/4.html

firefly RK3288 Jtag 設定

JTAG socket type

JTAG/SW 分成兩種 socket: 5 線的 JTAG socket 以及 2 線的 SW socket

  • JTAG socket 包括了 TDO、TDI、TRST_N、TMS、TCK 五條
  • SW socket 則是包括了 TMS 和 TCK 兩條

我們所使用的是五線的 JTAG Socket

從 Data Sheet 找出開發版與晶片的對應腳位

這裡有非常詳盡的解說

當然要先從官網下載 RK3288 的 user manual

我們發現 sdmmc0 與 jtag socket 腳位衝突,這部份我們會在 U-Boot 設定小結做說明

從 Data Sheet 找出需要設定的 register address & value

設定是使用兩個 register,目前還沒有成功,但這兩個 register 跑不掉

U-boot 端設定

可以在兩個地方進行初始化,二擇一即可:

In arch/arm/mach-rockchip/rk3288-board-spl.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
void board_init_f(ulong dummy)
{
struct udevice *pinctrl;
struct udevice *dev;
int ret;

/* Example code showing how to enable the debug UART on RK3288 */
/* Enable early UART on the RK3288 */
#define GRF_BASE 0xff770000

struct rk3288_grf * const grf = (void *)GRF_BASE;
struct rk3288_cru * cru;
/* set jtag clock */
cru = (struct rk3288_cru *)rockchip_get_cru(); //get cru addresses

/* set CLKGATE4_CON register, 0 is enable all clocks */
cru->cru_clkgate_con[4] = 0xFFFF0000;
printf("=====%p=====: value = %08x\n",(void *)cru,
cru->cru_clkgate_con[4]);

/* set bit 28 and 14 (mask and enable) */
printf("set jtag mode.\n");
grf->soc_con0 |= ((1<<28)+(1<<14));
printf("=====%p=====: value = %08x\n",(void *)&grf->soc_con0,
grf->soc_con0);
}

Or in arch/arm/mach-rockchip/rk3288-board.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
int board_late_init(void)
{
struct rk3288_cru * cru;
struct rk3288_grf * grf = (void *)0xff770000;
setup_boot_mode();
rk3288_qos_init();
rk3288_detect_reset_reason();
printf("board_late_init\n");

/* set jtag clock */
cru = (struct rk3288_cru *)rockchip_get_cru(); //get cru addresses

/* set CLKGATE4_CON register, 0 is enable all clocks */
cru->cru_clkgate_con[4] = 0xFFFF0000;
printf("=====%p=====:%p value = %08x\n",(void *)cru,
&cru->cru_clkgate_con[4], cru->cru_clkgate_con[4]);

printf("get jtag mode.\n");

/* ((1<<28)+(1<<12)); //set bit 28 and 14 (mask and enable) */
grf->soc_con0 = 0x10000c18;
printf("=====%p=====: value = %08x\n",(void *)&grf->soc_con0,
grf->soc_con0);
grf->gpio6c_iomux = 0xffff02aa;

return rk_board_late_init();
}

製作 U-Boot

之後透過腳本 build 出 idbloader_SPL.img 就可以了,這就是我們要的檔案

燒錄動作

  • put your sd card on your PC, and run command down below

    1
    sudo dd if=idbloader_SPL.img of=/dev/sdx  seek=64

    sdx 就是你的 sd card partition

  • SD boot 開機即可

問題:設定完成後依舊無法連線

跳出訊息

1
Connecting to target...ERROR: Cortex-A/R-JTAG (connect): Could not determine address of core debug registers. Incorrect CoreSight ROM table in device?

我預估有三種可能性

有數種可能性

  1. Jtag pin 腳設錯了
  2. JLinkGDBServer 初始化腳本設錯了
  3. JLink 軟硬體本身就不支援

針對 1. 的問題我已經驗證過了,如果直接初始化 SD/MMC mode 的話,會直接跳出無法連線而不會跳出類似圖片的內容

而 3. 的部份,我們也查證過了

V9.1 才支援,我們的版本是有點舊,不過 yenchin 的 hardware version 是 9.4 應該還是沒問題才是

而 3 還有另一個問題,就是 SEGGER 本身有沒有支援??
這部份很難查證,從 https://forum.segger.com/index.php/Thread/4341-SOLVED-JLinkGDBSserver-device-options-list/ 的教學,我們可以先透過 JLinkExe 上輸入

1
2
3
4
5
6
7
8
weintek-timmy@weintek-timmy:~/Downloads/JLink_V612j$ JLinkExe 
SEGGER J-Link Commander V6.22g (Compiled Jan 17 2018 16:40:37)
DLL version V6.22g, compiled Jan 17 2018 16:40:32

Connecting to J-Link via USB...FAILED: Cannot connect to J-Link via USB.
J-Link>expdevlist list.txt
Opening text file for writing... [list.txt]
J-Link>exit

像是 NXP (freeescale) i.MX6 就有支援

1
2
"Manufacturer", "Device", "Core", {Flash areas}, {RAM areas}
"NXP", "MCIMX6U7", "Cortex-A9", {0x00000000, 0x00000000}, {0x00000000, 0x00000000}

所以 i.MX6 可以用以下兩種方式執行

1
2
./JLinkGDBServer -select USB -device MCIMX6U7 -if JTAG -speed auto -noreset -noir
./JLinkGDBServer -select USB -device Cortex-A9 -if JTAG -speed auto -noreset -noir

A17 也有支援,不過是列在 unspecified 上面

1
2
"Manufacturer", "Device", "Core", {Flash areas}, {RAM areas}
"Unspecified", "Cortex-A17", "Cortex-A17", {0x00000000, 0x00000000}, {0x00000000, 0x00000000}

所以可能是 2. 的問題

首先透過論壇問了原廠,原廠沒有很完善的解答,只寫說「請找 SoC vendor」

而我們突然在網路上找到一篇 datasheet TRM v0.3 似乎是開發期間的版本

裏面可以查到 DAP address 如下

之後根據之前的範例嘗試修改 JLink.script,已經可以讓 rk3288 與 jtag 連接上

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
/*********************************************************************
* (c) SEGGER Microcontroller GmbH & Co. KG *
* The Embedded Experts *
* www.segger.com *
**********************************************************************
*/

/*********************************************************************
--- PLEASE do not remove this header ---

This init script was modified by
D.RY [dry@embedded-synergy.co.za]

The customized ResetTarget() should allow you to connect and start
debugging on the iMX7D Cortex-M4, without first doing connect &
initial M4 firmware upload on the Cortex-A7 side, as per howto.

It also should allow you to do resets 0, 1 without resetting entire
SoC when the aim is just M4 (and not A7 core(s) in particular).

This was tested on the NXP iMX7D / SABRE board, Toradex's Colibri
and Aster board + iMX7D, and Phytec's Zeta with iMX7D,
using NXP's provided FreeRTOS demo apps.

This thread

https://community.nxp.com/thread/461296

may have updated version of the script.
*********************************************************************/


/*********************************************************************
*
* ResetTarget
*/
void ResetTarget(void) {
}

/*********************************************************************
*
* InitTarget
*/
void InitTarget(void) {
Report("*************************************************");
Report("J-Link script: RK3288 core0 J-Link script");
Report("*************************************************");
// JLINK_CORESIGHT_Configure("IRPre=0;DRPre=0;IRPost=21;DRPost=2;IRLenDevice=4");
CPU = CORTEX_A17; // Pre-select that we have a Cortex-M4 connected
JTAG_AllowTAPReset = 1; // J-Link is allowed to use a TAP reset for JTAG-chain auto-detection

JTAG_SetDeviceId(0, 0x5BA00477); // 4-bits IRLen

CORESIGHT_CoreBaseAddr = 0xFFBB0000; // core 0
// CORESIGHT_CoreBaseAddr = 0xFFBB2000; // core 1
// CORESIGHT_CoreBaseAddr = 0xFFBB4000; // core 2
// CORESIGHT_CoreBaseAddr = 0xFFBB6000; // core 3
//
// Manually configure which APs are present on the CoreSight device
//
CORESIGHT_AddAP(1, CORESIGHT_AHB_AP);
CORESIGHT_AddAP(0, CORESIGHT_APB_AP);
// ResetTarget();
}

Reference

firefly forum: 求助下RK3288板子的JTAG
CSDN: rk3288的JTAG
CSDN: How Jtag works