目录
2.2 读ROM的步骤(How to read ROM Data from External ROM)
2.3 写的步骤(How to write FW to External ROM)
1 简介
在系统上电的时候,UPD720201芯片会从外部ROM里读取固件信息来对自己进行配置。
本文档是介绍在linux内核代码里来更新ROM里的固件的方法。
使用的硬件平台是瑞萨的RZG2H,软件平台是瑞萨官方提供的linux4.19内核。
注意:更新完ROM里的固件,需要重启板卡才有效。
2 UPD720201寄存器上的信息
2.1 相关寄存器
Accessing the External ROM related registers uses a total of five registers in the PCI Configuration registers of μPD720201 and μPD720202.
《r19uh0078ej0600_usb[uPD720201uPD720202+User's+Manual+Hardware].pdf》P120
<1> External ROM Information Register(Refer to Table 3-57)
<2> External ROM Configuration Register(Refer to Table 3-58)
<3> External ROM Access Control and Status Register(ERACSR)(Refer to Table 3-60)
Table 3-60. FW Control and Status Register (Offset Address: F6h)
Bits | Field | Read/Write | Value (Default) | Comment |
0 | External ROM Access Enable | RW | 0b | When set to’1b’, External ROM Write Request is initiated. Before setting to ‘1b’, FW data shall be written in the DATA0 register. When the data0 download is completed, this bit is automatically cleared to ‘0b’. Setting Get Data0 or Get DATA1 while Set DATA0 is ‘1b’ results in undefined behavior. |
1 | External ROM Erase | RW | 0b | When this bit is set to ‘1b’, External ROM Data is erased. When this operation is complete, this bit is cleared to ‘0b’ automatically. Before writing ‘1b’ to this bit, the DATA0 register must be set to 5A65726Fh. |
2 | Reload | RW | 0b | When this bit is set to ‘1b’, External ROM Data is reloaded. This function is used when immediate reload is required after External ROM is updated. At the completion of reload process, this bit is cleared to ‘0b’ automatically. |
3 | Reserved | RO | 0b | Reserved |
6:4 | Result Code | RO | 000b | This field shows the result of External ROM update process. 000b : Invalid (no result yet) 001b : Success 010b : Error 111b~011b : Reserved. |
7 | Reserved | RO | 0b | Reserved |
8 | Set DATA0 | RW1S | 0b | When set to’1b’, External ROM Write Request is initiated. Before setting to ‘1b’, FW data shall be written in the DATA0 register. When the data0 download is completed, this bit is automatically cleared to ‘0b’. Setting Get Data0 or Get DATA1 while Set DATA0 is ‘1b’ results in undefined behavior. |
9 | Set DATA1 | RW1S | 0b | When set to’1b’, External ROM Write Request is initiated. Before setting to ‘1b’, FW data shall be written in the DATA1 register. When the data1 download is completed, this bit is automatically cleared to ‘0b’. Setting Get Data0 or Get DATA1 while Set DATA1 is ‘1b’ results in undefined behavior. |
10 | Get DATA0 | RW1S | 0b | When set to’1b’, External ROM Read Request is initiated. This bit is automatically cleared to ‘0b’ when valid data is available in the Data0 register. Setting Set Data0 or Set DATA1 while Get DATA0 is ‘1b’ results in undefined behavior. |
11 | Get DATA1 | RW1S | 0b | When set to’1b’, External ROM Read Request is initiated. This bit is automatically cleared to ‘0b’ when valid data is available in the Data1 register. Setting Set Data0 or Set DATA1 while Get DATA1 is ‘1b’ results in undefined behavior. |
14:12 | Reserved | RO | 000b | Reserved |
15 | External ROM Exists | RO | HwInit | Indicates that the External ROM is connected. Even if the external ROM exists, FW can be downloaded from External ROM . In this case, FW in the xHC is overwritten by FW download data. 1 : External ROM Exists 0 : No External ROM Exists |
<4> Data0 Register(Refer to Table 3-61)
<5> Data1 Register(Refer to Table 3-62)
2.2 读ROM的步骤(How to read ROM Data from External ROM)
1. Read “External ROM Exists” and confirm it is ‘1b’.
2. Write ‘53524F4Dh’ to “DATA0”.
3. Set “1b” to “External ROM Access Enable”
4. Read “Result Code” and confirm it is ‘000b’.
5. Set “Get DATA0” and “Get DATA1” to ‘1b’.
6. Read “Get DATA0” and confirm it is ‘0b’.
7. Get External ROM data from “DATA0”.
8. Set “Get DATA0” to ‘1b’.
9. Read “Get DATA1” and confirm it is ‘0b’.
10. Get External ROM data from “DATA1”.
11. Set “Get DATA1” to ‘1b’.
12. Return to sequence 6 and repeat sequence 6 to sequence 11.
13. After reading the last data of External ROM data, the System Software must set “External ROM Access Enable” to ‘0b’.
《r19uh0078ej0600_usb[uPD720201uPD720202+User's+Manual+Hardware].pdf》P123
2.3 写的步骤(How to write FW to External ROM)
1. Read “External ROM Exists” and confirm it is ‘1b’.
2. Write ‘53524F4Dh’ to “DATA0”.
3. Set “External ROM Access Enable” to ‘1b’
4. Read “Result Code” and confirm it is ‘000b’.
5. Read “Set DATA0” and confirm it is ‘0b’.
6. Write FW data to”DATA0”.
7. Read “Set DATA1” and confirm it is ‘0b’.
8. Write FW data to”DATA1”.
9. Set “Set DATA0” and “Set DATA1” to ‘1b’.
10. Read “Set DATA0” and confirm it is ‘0b’.
11. Write FW data to”DATA0”.
12. Set “Set DATA0” to ’1b’.
13. Read “Set DATA1” and confirm it is ‘0b’.
14. Write FW data to”DATA1”.
15. Set “Set DATA1” to ‘1b’.
16. Return to step 10 and repeat steps 10 to 15.
17. After writing the last data of FW, the System Software must set “External ROM Access Enable” to ‘0b’.
18. Read “Result Code” and confirm it is ‘001b’.
3 修改驱动代码
文件:drivers/usb/host/xhci-pci.c
3.1 添加ROM擦除函数
#define EXTERNAL_ROM_INFO 0xEC
#define EXTERNAL_ROM_CONF 0xF0
#define EXTERNAL_ROM_SATUS 0xF6
#define DATA0 0xF8
#define DATA1 0xFC
void erase_chip(struct pci_dev *dev)
{
u16 data = 0;
u32 loop = 0;
/* 1. Read "External ROM Exists" and confirm it is '1b' */
if(pci_read_config_word(dev, EXTERNAL_ROM_SATUS, &data)){
printk(KERN_INFO"----- read status failed\n");
return;
}
while(data & 4){
pci_read_config_word(dev, EXTERNAL_ROM_SATUS, &data);
udelay(1000);
}
printk(KERN_INFO"----- start erase, status = %x\n", data);
if(!(data & (1 << 15))){
printk(KERN_INFO"----- rom not exist \n");
return;
}
/* 2. Write '5A65726Fh' to "DATA0" */
pci_write_config_dword(dev, DATA0, 0x5A65726F);
/* 3. Set '1b' to "External ROM Erase"*/
pci_write_config_word(dev, EXTERNAL_ROM_SATUS, data | 0x2);
/* 4. Read "External ROM Erase" and confirm it is '000b'*/
do{
pci_read_config_word(dev, EXTERNAL_ROM_SATUS, &data);
}while((data & 2));
}
3.2 添加向ROM里写固件的函数
void write_FW(struct pci_dev *dev)
{
unsigned long count = 0;
int retval, index, j;
u32 data;
u32 loop = 0;
u16 reg_val;
const struct firmware *fw;
//retval = request_firmware(&fw, "K2026090.mem", &(dev->dev));
//retval = request_firmware(&fw, "K20280B0.mem", &(dev->dev));
retval = request_firmware(&fw, "ROMimage2028.bin", &(dev->dev));
if (retval){
printk(KERN_INFO"----- request_firmware failed\n");
return;
}
/* 1. Read "External ROM Exists" and confirm it is '1b' */
if(pci_read_config_word(dev, EXTERNAL_ROM_SATUS, ®_val)){
printk(KERN_INFO"----- read status failed\n");
return;
}
printk(KERN_INFO"----- start write,status = %x\n", reg_val);
if(!(reg_val & (1 << 15))){
printk(KERN_INFO"----- rom not exist \n");
return;
}
/* 2. Write '53524F4Dh' to "DATA0" */
pci_write_config_dword(dev, DATA0, 0x53524F4D);
/* 3. Set "External ROM Access Enable" to '1b' */
pci_write_config_word(dev, EXTERNAL_ROM_SATUS, reg_val | 0x1);
/* 4. Read "Result Code" and confirm it is '000b' */
do{
pci_read_config_word(dev, EXTERNAL_ROM_SATUS, ®_val);
udelay(500);
if(loop++ == 20){
printk(KERN_INFO"----- Result Code not 000b\n");
return ;
}
}while(reg_val & (7 <<4));
/* 5. Read "Set DATA0" and confirm it is '0b' */
do{
pci_read_config_word(dev, EXTERNAL_ROM_SATUS, ®_val);
udelay(500);
}while(reg_val & (1 << 8));
index = 0;
/* 6. Write FW data to "DATA0" */
/* to avoid reading beyond the end of the buffer */
for (data = 0, j = 3; j >= 0; j--) {
if ((j + index) < fw->size)
data |= fw->data[index + j] << (8 * j);
}
pci_write_config_dword(dev, DATA0, data);
/* 7. Read "Set DATA1" and confirm it is '0b' */
do{
pci_read_config_word(dev, EXTERNAL_ROM_SATUS, ®_val);
udelay(500);
}while(reg_val& (1 << 9));
/* 8. Write FW data to "DATA1" */
index += 4;
/* to avoid reading beyond the end of the buffer */
for (data = 0, j = 3; j >= 0; j--) {
if ((j + index) < fw->size)
data |= fw->data[index + j] << (8 * j);
}
pci_write_config_dword(dev, DATA1, data);
/* 9. Set "Set DATA0" and "Set DATA1" to '1b' */
pci_write_config_word(dev, EXTERNAL_ROM_SATUS, reg_val | (3 << 8));
while(index < fw->size){
/* 10. Read "Set DATA0" and confirm it is '0b' */
do{
udelay(500);
pci_read_config_word(dev, EXTERNAL_ROM_SATUS, ®_val);
}while(reg_val & (1 << 8));
/* 11. Write FW data to "DATA0" */
index += 4;
/* to avoid reading beyond the end of the buffer */
for (data = 0, j = 3; j >= 0; j--) {
if ((j + index) < fw->size)
data |= fw->data[index + j] << (8 * j);
}
pci_write_config_dword(dev, DATA0, data);
//printk(KERN_DEBUG"----- %d, %08x\n",index / 4, data);
/* 12. Set "Set DATA0" to '1b' */
pci_write_config_word(dev, EXTERNAL_ROM_SATUS, reg_val | (1 << 8));
#if 1
/* 13. Read "Set DATA1" and confirm it is '0b' */
do{
udelay(500);
pci_read_config_word(dev, EXTERNAL_ROM_SATUS, ®_val);
}while(reg_val& (1 << 9));
/* 14. Write FW data to "DATA1" */
index += 4;
/* to avoid reading beyond the end of the buffer */
for (data = 0, j = 3; j >= 0; j--) {
if ((j + index) < fw->size)
data |= fw->data[index + j] << (8 * j);
}
pci_write_config_dword(dev, DATA1, data);
//printk(KERN_DEBUG"----- %d, %08x\n",index / 4, data);
/* 15. Set "Set DATA1" to '1b' */
pci_write_config_word(dev, EXTERNAL_ROM_SATUS, reg_val | (1 << 9));
#endif
/* 16. Return to step 10 and repeat steps 10 to 15 */
#if 0
if(index > 200)
break;
#endif
}
#if 0
do{
pci_read_config_word(dev, EXTERNAL_ROM_SATUS, ®_val);
udelay(500);
}while(reg_val & (3 << 8));
#endif
/* 17. After writing the last data of FW, the System Software
* must set "External ROM Access Enable" to '0b' */
pci_write_config_word(dev, EXTERNAL_ROM_SATUS, reg_val & ~(1));
/* 18. Read "Result Code" and confirm it is '001b' */
loop = 0;
do{
pci_read_config_word(dev, EXTERNAL_ROM_SATUS, ®_val);
udelay(5000);
if(loop++ == 1000){
printk(KERN_INFO"----- Result Code not 001b,is %x, index = %d\n",
reg_val, index);
return ;
}
}while((reg_val & (7 <<4)) != (1 << 4));
printk(KERN_INFO"----- index = %d\n", index);
}
3.3 添加从ROM里读数据的函数
void read_FW(struct pci_dev *dev)
{
u16 data = 0;
u32 fw_data = 0;
u32 loop = 0;
unsigned long count = 0;
/* 1. Read "External ROM Exists" and confirm it is '1b' */
if(pci_read_config_word(dev, EXTERNAL_ROM_SATUS, &data)){
printk(KERN_INFO"----- read status failed\n");
return;
}
while(data & 4){
pci_read_config_word(dev, EXTERNAL_ROM_SATUS, &data);
udelay(1000);
}
printk(KERN_INFO"----- start read, status = %x\n", data);
if(!(data & (1 << 15))){
printk(KERN_INFO"----- rom not exist \n");
return;
}
/* 2. Write '53524F4Dh' to "DATA0" */
if(pci_write_config_dword(dev, DATA0, 0x53524F4D)){
printk(KERN_INFO"----- write DATA0 failed\n");
return;
}
/* 3. Set '1b' to "External ROM Access Enable" */
pci_write_config_word(dev, EXTERNAL_ROM_SATUS, data | 0x1);
/* 4. Read "Result Code" and confirm it is '000b' */
do{
pci_read_config_word(dev, EXTERNAL_ROM_SATUS, &data);
udelay(500);
if(loop++ == 20){
printk(KERN_INFO"----- Result Code not 0\n");
return ;
}
}while(data & (7 <<4));
/* 5. Set "Get DATA0" and "Get DATA1" to '1b' */
pci_write_config_word(dev, EXTERNAL_ROM_SATUS, data | (0x3 << 10));
while(1){
/* 6. Read "Get DATA0" and confirm it is '0b' */
do{
pci_read_config_word(dev, EXTERNAL_ROM_SATUS, &data);
udelay(500);
}while(data & (1 <<10));
/* 7. Get External ROM data from "DATA0" */
pci_read_config_dword(dev, DATA0, &fw_data);
printk(KERN_DEBUG"----- %lu, %08x\n",count * 2, fw_data);
#if 1
if(fw_data == 0xffffffff)
break;
#endif
/* 8. Set "Get DATA0" to '1b' */
pci_write_config_word(dev, EXTERNAL_ROM_SATUS, data | (0x1 << 10));
/* 9. Read "Get DATA1" and confirm it is '0b' */
do{
pci_read_config_word(dev, EXTERNAL_ROM_SATUS, &data);
udelay(500);
}while(data & (1 <<11));
/* 10. Get External ROM data from "DATA1" */
pci_read_config_dword(dev, DATA1, &fw_data);
//printk(KERN_INFO"----- fw_data from DATA1 is %x\n",fw_data);
printk(KERN_DEBUG"----- %lu, %08x\n",count * 2 + 1, fw_data);
#if 1
if(fw_data == 0xffffffff)
break;
#endif
/* 11. Set "Get DATA1" to '1b' */
pci_write_config_word(dev, EXTERNAL_ROM_SATUS, data | (0x1 << 11));
/* 12. Return to sequence 6 and repeat sequence 6 to sequence 11 */
count ++;
#if 1
if(count > 50)
break;
#endif
}
printk(KERN_INFO"----- count %lu\n",count);
/* 13. After reading the last data of External ROM data, the System
* Software must set "External ROM Access Enable" to '0b' */
pci_write_config_word(dev, EXTERNAL_ROM_SATUS, data & ~(1));
}
3.4 调用新添加的函数
文件:drivers/usb/host/xhci-pci.c
函数:xhci_pci_probe();
在
pm_runtime_get_noresume(&dev->dev);
后面添加:
/************** load FW ***************/
erase_chip(dev);
write_FW(dev);
read_FW(dev);
4 将固件编译到内核镜像里
将固件文件(如:ROMimage2028.bin)拷贝到内核源码根目录下的firmware目录
配置内核
make menuconfig
在CONFIG_EXTRA_FIRMWARE配置里加上ROMimage2028.bin
配置完的.config相关内容如下:
CONFIG_EXTRA_FIRMWARE="... ROMimage2028.bin"
CONFIG_EXTRA_FIRMWARE_DIR="firmware"