在linux4.19内核下的UPD720201驱动里添加固件下载的代码

目录

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

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

 

 

 

 

您好,对于使用PCIE 转 USB 3.0 控制器 chip upd720201Linux 系统下的驱动,下面是一个简要的回答: upd720201 是一种常见的 PCIE 转 USB 3.0 控制器芯片,一般用于将 PCIE 接口转换为 USB 3.0 接口的转换器或扩展卡上。在使用 Linux 系统时,对于 upd720201驱动,一般来说,Linux 内核已集成了常见的控制器芯片的驱动程序,因此通常无需手动安装额外的驱动。 通常在多数 Linux 发行版中,内核已经支持 upd720201 控制器芯片,并自动加载正确的驱动。因此,当您将 PCIE 转 USB 3.0 转换器或扩展卡插入服务器或台式机的 PCIE 插槽时,Linux 内核会自动识别并加载驱动。运行 lsusb 命令可以查看与该控制器相关的 USB 设备是否正确识别。 但请注意,在某些情况下,可能会出现兼容性问题,导致标准内核驱动无法正常工作。如果您遇到这种情况,您可以尝试以下解决方法: 1. 更新 Linux 内核:某些发行版的内核版本可能较旧,不支持最新的硬件设备。通过更新最新版本的内核,可以增加对 upd720201 的支持,并解决兼容性问题。 2. 安装额外的驱动程序:如果更新内核后问题仍然存在,您可以尝试手动安装 upd720201 的特定驱动程序。您可以在 upd720201 控制器芯片制造商的网站上查找针对 Linux驱动程序,并根据提供的安装指南进行操作。 总结一下,大多数情况下,在 Linux 系统中使用 PCIE 转 USB 3.0 控制器芯片 upd720201 时,不需要手动安装额外驱动程序。但在某些情况下,可能需要更新内核或安装特定的驱动程序来解决兼容性问题。希望能对您有所帮助!
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值