天天看點

在linux4.19核心下的UPD720201驅動裡添加強件下載下傳的代碼1 簡介2 UPD720201寄存器上的資訊3 修改驅動代碼4 将固件編譯到核心鏡像裡

目錄

1 簡介

2 UPD720201寄存器上的資訊

2.1 相關寄存器

2.2 讀ROM的步驟(How to read ROM Data from External ROM)

2.3 寫的步驟(How to write FW to External ROM)

3 修改驅動代碼

3.1 添加ROM擦除函數

3.2 添加向ROM裡寫固件的函數

3.3 添加從ROM裡讀資料的函數

3.4 調用新添加的函數

4 将固件編譯到核心鏡像裡

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
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, &reg_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, &reg_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, &reg_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, &reg_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, &reg_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, &reg_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, &reg_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, &reg_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"
           

繼續閱讀