18bd5741eSChristian Lamparter // SPDX-License-Identifier: GPL-2.0 28bd5741eSChristian Lamparter /* Copyright (C) 2019-2020 Linaro Limited */ 38bd5741eSChristian Lamparter 48bd5741eSChristian Lamparter #include <linux/acpi.h> 58bd5741eSChristian Lamparter #include <linux/firmware.h> 68bd5741eSChristian Lamparter #include <linux/module.h> 78bd5741eSChristian Lamparter #include <linux/pci.h> 88bd5741eSChristian Lamparter #include <linux/slab.h> 9357abc1dSVinod Koul #include <asm/unaligned.h> 108bd5741eSChristian Lamparter 118bd5741eSChristian Lamparter #include "xhci.h" 128bd5741eSChristian Lamparter #include "xhci-trace.h" 138bd5741eSChristian Lamparter #include "xhci-pci.h" 148bd5741eSChristian Lamparter 158bd5741eSChristian Lamparter #define RENESAS_FW_VERSION 0x6C 168bd5741eSChristian Lamparter #define RENESAS_ROM_CONFIG 0xF0 178bd5741eSChristian Lamparter #define RENESAS_FW_STATUS 0xF4 188bd5741eSChristian Lamparter #define RENESAS_FW_STATUS_MSB 0xF5 198bd5741eSChristian Lamparter #define RENESAS_ROM_STATUS 0xF6 208bd5741eSChristian Lamparter #define RENESAS_ROM_STATUS_MSB 0xF7 218bd5741eSChristian Lamparter #define RENESAS_DATA0 0xF8 228bd5741eSChristian Lamparter #define RENESAS_DATA1 0xFC 238bd5741eSChristian Lamparter 248bd5741eSChristian Lamparter #define RENESAS_FW_VERSION_FIELD GENMASK(23, 7) 258bd5741eSChristian Lamparter #define RENESAS_FW_VERSION_OFFSET 8 268bd5741eSChristian Lamparter 278bd5741eSChristian Lamparter #define RENESAS_FW_STATUS_DOWNLOAD_ENABLE BIT(0) 288bd5741eSChristian Lamparter #define RENESAS_FW_STATUS_LOCK BIT(1) 298bd5741eSChristian Lamparter #define RENESAS_FW_STATUS_RESULT GENMASK(6, 4) 308bd5741eSChristian Lamparter #define RENESAS_FW_STATUS_INVALID 0 318bd5741eSChristian Lamparter #define RENESAS_FW_STATUS_SUCCESS BIT(4) 328bd5741eSChristian Lamparter #define RENESAS_FW_STATUS_ERROR BIT(5) 338bd5741eSChristian Lamparter #define RENESAS_FW_STATUS_SET_DATA0 BIT(8) 348bd5741eSChristian Lamparter #define RENESAS_FW_STATUS_SET_DATA1 BIT(9) 358bd5741eSChristian Lamparter 368bd5741eSChristian Lamparter #define RENESAS_ROM_STATUS_ACCESS BIT(0) 378bd5741eSChristian Lamparter #define RENESAS_ROM_STATUS_ERASE BIT(1) 388bd5741eSChristian Lamparter #define RENESAS_ROM_STATUS_RELOAD BIT(2) 398bd5741eSChristian Lamparter #define RENESAS_ROM_STATUS_RESULT GENMASK(6, 4) 408bd5741eSChristian Lamparter #define RENESAS_ROM_STATUS_NO_RESULT 0 418bd5741eSChristian Lamparter #define RENESAS_ROM_STATUS_SUCCESS BIT(4) 428bd5741eSChristian Lamparter #define RENESAS_ROM_STATUS_ERROR BIT(5) 438bd5741eSChristian Lamparter #define RENESAS_ROM_STATUS_SET_DATA0 BIT(8) 448bd5741eSChristian Lamparter #define RENESAS_ROM_STATUS_SET_DATA1 BIT(9) 458bd5741eSChristian Lamparter #define RENESAS_ROM_STATUS_ROM_EXISTS BIT(15) 468bd5741eSChristian Lamparter 478bd5741eSChristian Lamparter #define RENESAS_ROM_ERASE_MAGIC 0x5A65726F 488bd5741eSChristian Lamparter #define RENESAS_ROM_WRITE_MAGIC 0x53524F4D 498bd5741eSChristian Lamparter 508bd5741eSChristian Lamparter #define RENESAS_RETRY 10000 518bd5741eSChristian Lamparter #define RENESAS_DELAY 10 528bd5741eSChristian Lamparter 538bd5741eSChristian Lamparter static int renesas_fw_download_image(struct pci_dev *dev, 542478be82SVinod Koul const u32 *fw, size_t step, bool rom) 558bd5741eSChristian Lamparter { 568bd5741eSChristian Lamparter size_t i; 578bd5741eSChristian Lamparter int err; 588bd5741eSChristian Lamparter u8 fw_status; 598bd5741eSChristian Lamparter bool data0_or_data1; 602478be82SVinod Koul u32 status_reg; 612478be82SVinod Koul 622478be82SVinod Koul if (rom) 632478be82SVinod Koul status_reg = RENESAS_ROM_STATUS_MSB; 642478be82SVinod Koul else 652478be82SVinod Koul status_reg = RENESAS_FW_STATUS_MSB; 668bd5741eSChristian Lamparter 678bd5741eSChristian Lamparter /* 688bd5741eSChristian Lamparter * The hardware does alternate between two 32-bit pages. 698bd5741eSChristian Lamparter * (This is because each row of the firmware is 8 bytes). 708bd5741eSChristian Lamparter * 718bd5741eSChristian Lamparter * for even steps we use DATA0, for odd steps DATA1. 728bd5741eSChristian Lamparter */ 738bd5741eSChristian Lamparter data0_or_data1 = (step & 1) == 1; 748bd5741eSChristian Lamparter 758bd5741eSChristian Lamparter /* step+1. Read "Set DATAX" and confirm it is cleared. */ 768bd5741eSChristian Lamparter for (i = 0; i < RENESAS_RETRY; i++) { 772478be82SVinod Koul err = pci_read_config_byte(dev, status_reg, &fw_status); 788bd5741eSChristian Lamparter if (err) { 798bd5741eSChristian Lamparter dev_err(&dev->dev, "Read Status failed: %d\n", 808bd5741eSChristian Lamparter pcibios_err_to_errno(err)); 818bd5741eSChristian Lamparter return pcibios_err_to_errno(err); 828bd5741eSChristian Lamparter } 838bd5741eSChristian Lamparter if (!(fw_status & BIT(data0_or_data1))) 848bd5741eSChristian Lamparter break; 858bd5741eSChristian Lamparter 868bd5741eSChristian Lamparter udelay(RENESAS_DELAY); 878bd5741eSChristian Lamparter } 888bd5741eSChristian Lamparter if (i == RENESAS_RETRY) { 898bd5741eSChristian Lamparter dev_err(&dev->dev, "Timeout for Set DATAX step: %zd\n", step); 908bd5741eSChristian Lamparter return -ETIMEDOUT; 918bd5741eSChristian Lamparter } 928bd5741eSChristian Lamparter 938bd5741eSChristian Lamparter /* 948bd5741eSChristian Lamparter * step+2. Write FW data to "DATAX". 958bd5741eSChristian Lamparter * "LSB is left" => force little endian 968bd5741eSChristian Lamparter */ 978bd5741eSChristian Lamparter err = pci_write_config_dword(dev, data0_or_data1 ? 988bd5741eSChristian Lamparter RENESAS_DATA1 : RENESAS_DATA0, 998bd5741eSChristian Lamparter (__force u32)cpu_to_le32(fw[step])); 1008bd5741eSChristian Lamparter if (err) { 1018bd5741eSChristian Lamparter dev_err(&dev->dev, "Write to DATAX failed: %d\n", 1028bd5741eSChristian Lamparter pcibios_err_to_errno(err)); 1038bd5741eSChristian Lamparter return pcibios_err_to_errno(err); 1048bd5741eSChristian Lamparter } 1058bd5741eSChristian Lamparter 1068bd5741eSChristian Lamparter udelay(100); 1078bd5741eSChristian Lamparter 1088bd5741eSChristian Lamparter /* step+3. Set "Set DATAX". */ 1092478be82SVinod Koul err = pci_write_config_byte(dev, status_reg, BIT(data0_or_data1)); 1108bd5741eSChristian Lamparter if (err) { 1118bd5741eSChristian Lamparter dev_err(&dev->dev, "Write config for DATAX failed: %d\n", 1128bd5741eSChristian Lamparter pcibios_err_to_errno(err)); 1138bd5741eSChristian Lamparter return pcibios_err_to_errno(err); 1148bd5741eSChristian Lamparter } 1158bd5741eSChristian Lamparter 1168bd5741eSChristian Lamparter return 0; 1178bd5741eSChristian Lamparter } 1188bd5741eSChristian Lamparter 1198bd5741eSChristian Lamparter static int renesas_fw_verify(const void *fw_data, 1208bd5741eSChristian Lamparter size_t length) 1218bd5741eSChristian Lamparter { 1228bd5741eSChristian Lamparter u16 fw_version_pointer; 1238bd5741eSChristian Lamparter u16 fw_version; 1248bd5741eSChristian Lamparter 1258bd5741eSChristian Lamparter /* 1268bd5741eSChristian Lamparter * The Firmware's Data Format is describe in 1278bd5741eSChristian Lamparter * "6.3 Data Format" R19UH0078EJ0500 Rev.5.00 page 124 1288bd5741eSChristian Lamparter */ 1298bd5741eSChristian Lamparter 1308bd5741eSChristian Lamparter /* 1318bd5741eSChristian Lamparter * The bootrom chips of the big brother have sizes up to 64k, let's 1328bd5741eSChristian Lamparter * assume that's the biggest the firmware can get. 1338bd5741eSChristian Lamparter */ 1348bd5741eSChristian Lamparter if (length < 0x1000 || length >= 0x10000) { 1358bd5741eSChristian Lamparter pr_err("firmware is size %zd is not (4k - 64k).", 1368bd5741eSChristian Lamparter length); 1378bd5741eSChristian Lamparter return -EINVAL; 1388bd5741eSChristian Lamparter } 1398bd5741eSChristian Lamparter 1408bd5741eSChristian Lamparter /* The First 2 bytes are fixed value (55aa). "LSB on Left" */ 1418bd5741eSChristian Lamparter if (get_unaligned_le16(fw_data) != 0x55aa) { 1428bd5741eSChristian Lamparter pr_err("no valid firmware header found."); 1438bd5741eSChristian Lamparter return -EINVAL; 1448bd5741eSChristian Lamparter } 1458bd5741eSChristian Lamparter 1468bd5741eSChristian Lamparter /* verify the firmware version position and print it. */ 1478bd5741eSChristian Lamparter fw_version_pointer = get_unaligned_le16(fw_data + 4); 1488bd5741eSChristian Lamparter if (fw_version_pointer + 2 >= length) { 1498bd5741eSChristian Lamparter pr_err("fw ver pointer is outside of the firmware image"); 1508bd5741eSChristian Lamparter return -EINVAL; 1518bd5741eSChristian Lamparter } 1528bd5741eSChristian Lamparter 1538bd5741eSChristian Lamparter fw_version = get_unaligned_le16(fw_data + fw_version_pointer); 1548bd5741eSChristian Lamparter pr_err("got firmware version: %02x.", fw_version); 1558bd5741eSChristian Lamparter 1568bd5741eSChristian Lamparter return 0; 1578bd5741eSChristian Lamparter } 1588bd5741eSChristian Lamparter 1592478be82SVinod Koul static bool renesas_check_rom(struct pci_dev *pdev) 1602478be82SVinod Koul { 1612478be82SVinod Koul u16 rom_status; 1622478be82SVinod Koul int retval; 1632478be82SVinod Koul 1642478be82SVinod Koul /* Check if external ROM exists */ 1652478be82SVinod Koul retval = pci_read_config_word(pdev, RENESAS_ROM_STATUS, &rom_status); 1662478be82SVinod Koul if (retval) 1672478be82SVinod Koul return false; 1682478be82SVinod Koul 1692478be82SVinod Koul rom_status &= RENESAS_ROM_STATUS_ROM_EXISTS; 1702478be82SVinod Koul if (rom_status) { 1712478be82SVinod Koul dev_dbg(&pdev->dev, "External ROM exists\n"); 1722478be82SVinod Koul return true; /* External ROM exists */ 1732478be82SVinod Koul } 1742478be82SVinod Koul 1752478be82SVinod Koul return false; 1762478be82SVinod Koul } 1772478be82SVinod Koul 1782478be82SVinod Koul static int renesas_check_rom_state(struct pci_dev *pdev) 1792478be82SVinod Koul { 1802478be82SVinod Koul u16 rom_state; 1812478be82SVinod Koul u32 version; 1822478be82SVinod Koul int err; 1832478be82SVinod Koul 1842478be82SVinod Koul /* check FW version */ 1852478be82SVinod Koul err = pci_read_config_dword(pdev, RENESAS_FW_VERSION, &version); 1862478be82SVinod Koul if (err) 1872478be82SVinod Koul return pcibios_err_to_errno(err); 1882478be82SVinod Koul 1892478be82SVinod Koul version &= RENESAS_FW_VERSION_FIELD; 1902478be82SVinod Koul version = version >> RENESAS_FW_VERSION_OFFSET; 191d66a57beSVinod Koul dev_dbg(&pdev->dev, "Found ROM version: %x\n", version); 1922478be82SVinod Koul 1932478be82SVinod Koul /* 1942478be82SVinod Koul * Test if ROM is present and loaded, if so we can skip everything 1952478be82SVinod Koul */ 1962478be82SVinod Koul err = pci_read_config_word(pdev, RENESAS_ROM_STATUS, &rom_state); 1972478be82SVinod Koul if (err) 1982478be82SVinod Koul return pcibios_err_to_errno(err); 1992478be82SVinod Koul 200e90f9cebSMoritz Fischer if (rom_state & RENESAS_ROM_STATUS_ROM_EXISTS) { 2012478be82SVinod Koul /* ROM exists */ 2022478be82SVinod Koul dev_dbg(&pdev->dev, "ROM exists\n"); 2032478be82SVinod Koul 2042478be82SVinod Koul /* Check the "Result Code" Bits (6:4) and act accordingly */ 2052478be82SVinod Koul switch (rom_state & RENESAS_ROM_STATUS_RESULT) { 2062478be82SVinod Koul case RENESAS_ROM_STATUS_SUCCESS: 2072478be82SVinod Koul return 0; 2082478be82SVinod Koul 2092478be82SVinod Koul case RENESAS_ROM_STATUS_NO_RESULT: /* No result yet */ 210d143825bSMoritz Fischer dev_dbg(&pdev->dev, "Unknown ROM status ...\n"); 211d143825bSMoritz Fischer break; 2122478be82SVinod Koul 2132478be82SVinod Koul case RENESAS_ROM_STATUS_ERROR: /* Error State */ 2142478be82SVinod Koul default: /* All other states are marked as "Reserved states" */ 2152478be82SVinod Koul dev_err(&pdev->dev, "Invalid ROM.."); 2162478be82SVinod Koul break; 2172478be82SVinod Koul } 2182478be82SVinod Koul } 2192478be82SVinod Koul 2202478be82SVinod Koul return -EIO; 2212478be82SVinod Koul } 2222478be82SVinod Koul 2238bd5741eSChristian Lamparter static int renesas_fw_check_running(struct pci_dev *pdev) 2248bd5741eSChristian Lamparter { 2258bd5741eSChristian Lamparter u8 fw_state; 2262478be82SVinod Koul int err; 2272478be82SVinod Koul 228d143825bSMoritz Fischer /* 229d143825bSMoritz Fischer * Only if device has ROM and loaded FW we can skip loading and 230d143825bSMoritz Fischer * return success. Otherwise (even unknown state), attempt to load FW. 231d143825bSMoritz Fischer */ 232d143825bSMoritz Fischer if (renesas_check_rom(pdev) && !renesas_check_rom_state(pdev)) 233d143825bSMoritz Fischer return 0; 2348bd5741eSChristian Lamparter 2358bd5741eSChristian Lamparter /* 2368bd5741eSChristian Lamparter * Test if the device is actually needing the firmware. As most 2378bd5741eSChristian Lamparter * BIOSes will initialize the device for us. If the device is 2388bd5741eSChristian Lamparter * initialized. 2398bd5741eSChristian Lamparter */ 2408bd5741eSChristian Lamparter err = pci_read_config_byte(pdev, RENESAS_FW_STATUS, &fw_state); 2418bd5741eSChristian Lamparter if (err) 2428bd5741eSChristian Lamparter return pcibios_err_to_errno(err); 2438bd5741eSChristian Lamparter 2448bd5741eSChristian Lamparter /* 2458bd5741eSChristian Lamparter * Check if "FW Download Lock" is locked. If it is and the FW is 2468bd5741eSChristian Lamparter * ready we can simply continue. If the FW is not ready, we have 2478bd5741eSChristian Lamparter * to give up. 2488bd5741eSChristian Lamparter */ 2498bd5741eSChristian Lamparter if (fw_state & RENESAS_FW_STATUS_LOCK) { 2508bd5741eSChristian Lamparter dev_dbg(&pdev->dev, "FW Download Lock is engaged."); 2518bd5741eSChristian Lamparter 2528bd5741eSChristian Lamparter if (fw_state & RENESAS_FW_STATUS_SUCCESS) 2538bd5741eSChristian Lamparter return 0; 2548bd5741eSChristian Lamparter 2558bd5741eSChristian Lamparter dev_err(&pdev->dev, 2568bd5741eSChristian Lamparter "FW Download Lock is set and FW is not ready. Giving Up."); 2578bd5741eSChristian Lamparter return -EIO; 2588bd5741eSChristian Lamparter } 2598bd5741eSChristian Lamparter 2608bd5741eSChristian Lamparter /* 2618bd5741eSChristian Lamparter * Check if "FW Download Enable" is set. If someone (us?) tampered 2628bd5741eSChristian Lamparter * with it and it can't be reset, we have to give up too... and 2638bd5741eSChristian Lamparter * ask for a forgiveness and a reboot. 2648bd5741eSChristian Lamparter */ 2658bd5741eSChristian Lamparter if (fw_state & RENESAS_FW_STATUS_DOWNLOAD_ENABLE) { 2668bd5741eSChristian Lamparter dev_err(&pdev->dev, 2678bd5741eSChristian Lamparter "FW Download Enable is stale. Giving Up (poweroff/reboot needed)."); 2688bd5741eSChristian Lamparter return -EIO; 2698bd5741eSChristian Lamparter } 2708bd5741eSChristian Lamparter 2718bd5741eSChristian Lamparter /* Otherwise, Check the "Result Code" Bits (6:4) and act accordingly */ 2728bd5741eSChristian Lamparter switch (fw_state & RENESAS_FW_STATUS_RESULT) { 2738bd5741eSChristian Lamparter case 0: /* No result yet */ 2748bd5741eSChristian Lamparter dev_dbg(&pdev->dev, "FW is not ready/loaded yet."); 2758bd5741eSChristian Lamparter 2768bd5741eSChristian Lamparter /* tell the caller, that this device needs the firmware. */ 2778bd5741eSChristian Lamparter return 1; 2788bd5741eSChristian Lamparter 2798bd5741eSChristian Lamparter case RENESAS_FW_STATUS_SUCCESS: /* Success, device should be working. */ 2808bd5741eSChristian Lamparter dev_dbg(&pdev->dev, "FW is ready."); 2818bd5741eSChristian Lamparter return 0; 2828bd5741eSChristian Lamparter 2838bd5741eSChristian Lamparter case RENESAS_FW_STATUS_ERROR: /* Error State */ 2848bd5741eSChristian Lamparter dev_err(&pdev->dev, 2858bd5741eSChristian Lamparter "hardware is in an error state. Giving up (poweroff/reboot needed)."); 2868bd5741eSChristian Lamparter return -ENODEV; 2878bd5741eSChristian Lamparter 2888bd5741eSChristian Lamparter default: /* All other states are marked as "Reserved states" */ 2898bd5741eSChristian Lamparter dev_err(&pdev->dev, 2908bd5741eSChristian Lamparter "hardware is in an invalid state %lx. Giving up (poweroff/reboot needed).", 2918bd5741eSChristian Lamparter (fw_state & RENESAS_FW_STATUS_RESULT) >> 4); 2928bd5741eSChristian Lamparter return -EINVAL; 2938bd5741eSChristian Lamparter } 2948bd5741eSChristian Lamparter } 2958bd5741eSChristian Lamparter 2968bd5741eSChristian Lamparter static int renesas_fw_download(struct pci_dev *pdev, 2978bd5741eSChristian Lamparter const struct firmware *fw) 2988bd5741eSChristian Lamparter { 2998bd5741eSChristian Lamparter const u32 *fw_data = (const u32 *)fw->data; 3008bd5741eSChristian Lamparter size_t i; 3018bd5741eSChristian Lamparter int err; 3028bd5741eSChristian Lamparter u8 fw_status; 3038bd5741eSChristian Lamparter 3048bd5741eSChristian Lamparter /* 3058bd5741eSChristian Lamparter * For more information and the big picture: please look at the 3068bd5741eSChristian Lamparter * "Firmware Download Sequence" in "7.1 FW Download Interface" 3078bd5741eSChristian Lamparter * of R19UH0078EJ0500 Rev.5.00 page 131 3088bd5741eSChristian Lamparter */ 3098bd5741eSChristian Lamparter 3108bd5741eSChristian Lamparter /* 3118bd5741eSChristian Lamparter * 0. Set "FW Download Enable" bit in the 3128bd5741eSChristian Lamparter * "FW Download Control & Status Register" at 0xF4 3138bd5741eSChristian Lamparter */ 3148bd5741eSChristian Lamparter err = pci_write_config_byte(pdev, RENESAS_FW_STATUS, 3158bd5741eSChristian Lamparter RENESAS_FW_STATUS_DOWNLOAD_ENABLE); 3168bd5741eSChristian Lamparter if (err) 3178bd5741eSChristian Lamparter return pcibios_err_to_errno(err); 3188bd5741eSChristian Lamparter 3198bd5741eSChristian Lamparter /* 1 - 10 follow one step after the other. */ 3208bd5741eSChristian Lamparter for (i = 0; i < fw->size / 4; i++) { 3212478be82SVinod Koul err = renesas_fw_download_image(pdev, fw_data, i, false); 3228bd5741eSChristian Lamparter if (err) { 3238bd5741eSChristian Lamparter dev_err(&pdev->dev, 3248bd5741eSChristian Lamparter "Firmware Download Step %zd failed at position %zd bytes with (%d).", 3258bd5741eSChristian Lamparter i, i * 4, err); 3268bd5741eSChristian Lamparter return err; 3278bd5741eSChristian Lamparter } 3288bd5741eSChristian Lamparter } 3298bd5741eSChristian Lamparter 3308bd5741eSChristian Lamparter /* 3318bd5741eSChristian Lamparter * This sequence continues until the last data is written to 3328bd5741eSChristian Lamparter * "DATA0" or "DATA1". Naturally, we wait until "SET DATA0/1" 3338bd5741eSChristian Lamparter * is cleared by the hardware beforehand. 3348bd5741eSChristian Lamparter */ 3358bd5741eSChristian Lamparter for (i = 0; i < RENESAS_RETRY; i++) { 3368bd5741eSChristian Lamparter err = pci_read_config_byte(pdev, RENESAS_FW_STATUS_MSB, 3378bd5741eSChristian Lamparter &fw_status); 3388bd5741eSChristian Lamparter if (err) 3398bd5741eSChristian Lamparter return pcibios_err_to_errno(err); 3408bd5741eSChristian Lamparter if (!(fw_status & (BIT(0) | BIT(1)))) 3418bd5741eSChristian Lamparter break; 3428bd5741eSChristian Lamparter 3438bd5741eSChristian Lamparter udelay(RENESAS_DELAY); 3448bd5741eSChristian Lamparter } 3458bd5741eSChristian Lamparter if (i == RENESAS_RETRY) 3468bd5741eSChristian Lamparter dev_warn(&pdev->dev, "Final Firmware Download step timed out."); 3478bd5741eSChristian Lamparter 3488bd5741eSChristian Lamparter /* 3498bd5741eSChristian Lamparter * 11. After finishing writing the last data of FW, the 3508bd5741eSChristian Lamparter * System Software must clear "FW Download Enable" 3518bd5741eSChristian Lamparter */ 3528bd5741eSChristian Lamparter err = pci_write_config_byte(pdev, RENESAS_FW_STATUS, 0); 3538bd5741eSChristian Lamparter if (err) 3548bd5741eSChristian Lamparter return pcibios_err_to_errno(err); 3558bd5741eSChristian Lamparter 3568bd5741eSChristian Lamparter /* 12. Read "Result Code" and confirm it is good. */ 3578bd5741eSChristian Lamparter for (i = 0; i < RENESAS_RETRY; i++) { 3588bd5741eSChristian Lamparter err = pci_read_config_byte(pdev, RENESAS_FW_STATUS, &fw_status); 3598bd5741eSChristian Lamparter if (err) 3608bd5741eSChristian Lamparter return pcibios_err_to_errno(err); 3618bd5741eSChristian Lamparter if (fw_status & RENESAS_FW_STATUS_SUCCESS) 3628bd5741eSChristian Lamparter break; 3638bd5741eSChristian Lamparter 3648bd5741eSChristian Lamparter udelay(RENESAS_DELAY); 3658bd5741eSChristian Lamparter } 3668bd5741eSChristian Lamparter if (i == RENESAS_RETRY) { 3678bd5741eSChristian Lamparter /* Timed out / Error - let's see if we can fix this */ 3688bd5741eSChristian Lamparter err = renesas_fw_check_running(pdev); 3698bd5741eSChristian Lamparter switch (err) { 3708bd5741eSChristian Lamparter case 0: /* 3718bd5741eSChristian Lamparter * we shouldn't end up here. 3728bd5741eSChristian Lamparter * maybe it took a little bit longer. 3738bd5741eSChristian Lamparter * But all should be well? 3748bd5741eSChristian Lamparter */ 3758bd5741eSChristian Lamparter break; 3768bd5741eSChristian Lamparter 3778bd5741eSChristian Lamparter case 1: /* (No result yet! */ 3788bd5741eSChristian Lamparter dev_err(&pdev->dev, "FW Load timedout"); 3798bd5741eSChristian Lamparter return -ETIMEDOUT; 3808bd5741eSChristian Lamparter 3818bd5741eSChristian Lamparter default: 3828bd5741eSChristian Lamparter return err; 3838bd5741eSChristian Lamparter } 3848bd5741eSChristian Lamparter } 3858bd5741eSChristian Lamparter 3868bd5741eSChristian Lamparter return 0; 3878bd5741eSChristian Lamparter } 3888bd5741eSChristian Lamparter 3892478be82SVinod Koul static void renesas_rom_erase(struct pci_dev *pdev) 3902478be82SVinod Koul { 3912478be82SVinod Koul int retval, i; 3922478be82SVinod Koul u8 status; 3932478be82SVinod Koul 3942478be82SVinod Koul dev_dbg(&pdev->dev, "Performing ROM Erase...\n"); 3952478be82SVinod Koul retval = pci_write_config_dword(pdev, RENESAS_DATA0, 3962478be82SVinod Koul RENESAS_ROM_ERASE_MAGIC); 3972478be82SVinod Koul if (retval) { 3982478be82SVinod Koul dev_err(&pdev->dev, "ROM erase, magic word write failed: %d\n", 3992478be82SVinod Koul pcibios_err_to_errno(retval)); 4002478be82SVinod Koul return; 4012478be82SVinod Koul } 4022478be82SVinod Koul 4032478be82SVinod Koul retval = pci_read_config_byte(pdev, RENESAS_ROM_STATUS, &status); 4042478be82SVinod Koul if (retval) { 4052478be82SVinod Koul dev_err(&pdev->dev, "ROM status read failed: %d\n", 4062478be82SVinod Koul pcibios_err_to_errno(retval)); 4072478be82SVinod Koul return; 4082478be82SVinod Koul } 4092478be82SVinod Koul status |= RENESAS_ROM_STATUS_ERASE; 4102478be82SVinod Koul retval = pci_write_config_byte(pdev, RENESAS_ROM_STATUS, status); 4112478be82SVinod Koul if (retval) { 4122478be82SVinod Koul dev_err(&pdev->dev, "ROM erase set word write failed\n"); 4132478be82SVinod Koul return; 4142478be82SVinod Koul } 4152478be82SVinod Koul 4162478be82SVinod Koul /* sleep a bit while ROM is erased */ 4172478be82SVinod Koul msleep(20); 4182478be82SVinod Koul 4192478be82SVinod Koul for (i = 0; i < RENESAS_RETRY; i++) { 4202478be82SVinod Koul retval = pci_read_config_byte(pdev, RENESAS_ROM_STATUS, 4212478be82SVinod Koul &status); 4222478be82SVinod Koul status &= RENESAS_ROM_STATUS_ERASE; 4232478be82SVinod Koul if (!status) 4242478be82SVinod Koul break; 4252478be82SVinod Koul 4262478be82SVinod Koul mdelay(RENESAS_DELAY); 4272478be82SVinod Koul } 4282478be82SVinod Koul 4292478be82SVinod Koul if (i == RENESAS_RETRY) 4302478be82SVinod Koul dev_dbg(&pdev->dev, "Chip erase timedout: %x\n", status); 4312478be82SVinod Koul 4322478be82SVinod Koul dev_dbg(&pdev->dev, "ROM Erase... Done success\n"); 4332478be82SVinod Koul } 4342478be82SVinod Koul 4352478be82SVinod Koul static bool renesas_setup_rom(struct pci_dev *pdev, const struct firmware *fw) 4362478be82SVinod Koul { 4372478be82SVinod Koul const u32 *fw_data = (const u32 *)fw->data; 4382478be82SVinod Koul int err, i; 4392478be82SVinod Koul u8 status; 4402478be82SVinod Koul 4412478be82SVinod Koul /* 2. Write magic word to Data0 */ 4422478be82SVinod Koul err = pci_write_config_dword(pdev, RENESAS_DATA0, 4432478be82SVinod Koul RENESAS_ROM_WRITE_MAGIC); 4442478be82SVinod Koul if (err) 4452478be82SVinod Koul return false; 4462478be82SVinod Koul 4472478be82SVinod Koul /* 3. Set External ROM access */ 4482478be82SVinod Koul err = pci_write_config_byte(pdev, RENESAS_ROM_STATUS, 4492478be82SVinod Koul RENESAS_ROM_STATUS_ACCESS); 4502478be82SVinod Koul if (err) 4512478be82SVinod Koul goto remove_bypass; 4522478be82SVinod Koul 4532478be82SVinod Koul /* 4. Check the result */ 4542478be82SVinod Koul err = pci_read_config_byte(pdev, RENESAS_ROM_STATUS, &status); 4552478be82SVinod Koul if (err) 4562478be82SVinod Koul goto remove_bypass; 4572478be82SVinod Koul status &= GENMASK(6, 4); 4582478be82SVinod Koul if (status) { 4592478be82SVinod Koul dev_err(&pdev->dev, 4602478be82SVinod Koul "setting external rom failed: %x\n", status); 4612478be82SVinod Koul goto remove_bypass; 4622478be82SVinod Koul } 4632478be82SVinod Koul 4642478be82SVinod Koul /* 5 to 16 Write FW to DATA0/1 while checking SetData0/1 */ 4652478be82SVinod Koul for (i = 0; i < fw->size / 4; i++) { 4662478be82SVinod Koul err = renesas_fw_download_image(pdev, fw_data, i, true); 4672478be82SVinod Koul if (err) { 4682478be82SVinod Koul dev_err(&pdev->dev, 4692478be82SVinod Koul "ROM Download Step %d failed at position %d bytes with (%d)\n", 4702478be82SVinod Koul i, i * 4, err); 4712478be82SVinod Koul goto remove_bypass; 4722478be82SVinod Koul } 4732478be82SVinod Koul } 4742478be82SVinod Koul 4752478be82SVinod Koul /* 4762478be82SVinod Koul * wait till DATA0/1 is cleared 4772478be82SVinod Koul */ 4782478be82SVinod Koul for (i = 0; i < RENESAS_RETRY; i++) { 4792478be82SVinod Koul err = pci_read_config_byte(pdev, RENESAS_ROM_STATUS_MSB, 4802478be82SVinod Koul &status); 4812478be82SVinod Koul if (err) 4822478be82SVinod Koul goto remove_bypass; 4832478be82SVinod Koul if (!(status & (BIT(0) | BIT(1)))) 4842478be82SVinod Koul break; 4852478be82SVinod Koul 4862478be82SVinod Koul udelay(RENESAS_DELAY); 4872478be82SVinod Koul } 4882478be82SVinod Koul if (i == RENESAS_RETRY) { 4892478be82SVinod Koul dev_err(&pdev->dev, "Final Firmware ROM Download step timed out\n"); 4902478be82SVinod Koul goto remove_bypass; 4912478be82SVinod Koul } 4922478be82SVinod Koul 4932478be82SVinod Koul /* 17. Remove bypass */ 4942478be82SVinod Koul err = pci_write_config_byte(pdev, RENESAS_ROM_STATUS, 0); 4952478be82SVinod Koul if (err) 4962478be82SVinod Koul return false; 4972478be82SVinod Koul 4982478be82SVinod Koul udelay(10); 4992478be82SVinod Koul 5002478be82SVinod Koul /* 18. check result */ 5012478be82SVinod Koul for (i = 0; i < RENESAS_RETRY; i++) { 5022478be82SVinod Koul err = pci_read_config_byte(pdev, RENESAS_ROM_STATUS, &status); 5032478be82SVinod Koul if (err) { 5042478be82SVinod Koul dev_err(&pdev->dev, "Read ROM status failed:%d\n", 5052478be82SVinod Koul pcibios_err_to_errno(err)); 5062478be82SVinod Koul return false; 5072478be82SVinod Koul } 5082478be82SVinod Koul status &= RENESAS_ROM_STATUS_RESULT; 5092478be82SVinod Koul if (status == RENESAS_ROM_STATUS_SUCCESS) { 5102478be82SVinod Koul dev_dbg(&pdev->dev, "Download ROM success\n"); 5112478be82SVinod Koul break; 5122478be82SVinod Koul } 5132478be82SVinod Koul udelay(RENESAS_DELAY); 5142478be82SVinod Koul } 5152478be82SVinod Koul if (i == RENESAS_RETRY) { /* Timed out */ 5162478be82SVinod Koul dev_err(&pdev->dev, 5172478be82SVinod Koul "Download to external ROM TO: %x\n", status); 5182478be82SVinod Koul return false; 5192478be82SVinod Koul } 5202478be82SVinod Koul 5212478be82SVinod Koul dev_dbg(&pdev->dev, "Download to external ROM succeeded\n"); 5222478be82SVinod Koul 5232478be82SVinod Koul /* Last step set Reload */ 5242478be82SVinod Koul err = pci_write_config_byte(pdev, RENESAS_ROM_STATUS, 5252478be82SVinod Koul RENESAS_ROM_STATUS_RELOAD); 5262478be82SVinod Koul if (err) { 5272478be82SVinod Koul dev_err(&pdev->dev, "Set ROM execute failed: %d\n", 5282478be82SVinod Koul pcibios_err_to_errno(err)); 5292478be82SVinod Koul return false; 5302478be82SVinod Koul } 5312478be82SVinod Koul 5322478be82SVinod Koul /* 5332478be82SVinod Koul * wait till Reload is cleared 5342478be82SVinod Koul */ 5352478be82SVinod Koul for (i = 0; i < RENESAS_RETRY; i++) { 5362478be82SVinod Koul err = pci_read_config_byte(pdev, RENESAS_ROM_STATUS, &status); 5372478be82SVinod Koul if (err) 5382478be82SVinod Koul return false; 5392478be82SVinod Koul if (!(status & RENESAS_ROM_STATUS_RELOAD)) 5402478be82SVinod Koul break; 5412478be82SVinod Koul 5422478be82SVinod Koul udelay(RENESAS_DELAY); 5432478be82SVinod Koul } 5442478be82SVinod Koul if (i == RENESAS_RETRY) { 5452478be82SVinod Koul dev_err(&pdev->dev, "ROM Exec timed out: %x\n", status); 5462478be82SVinod Koul return false; 5472478be82SVinod Koul } 5482478be82SVinod Koul 5492478be82SVinod Koul return true; 5502478be82SVinod Koul 5512478be82SVinod Koul remove_bypass: 5522478be82SVinod Koul pci_write_config_byte(pdev, RENESAS_ROM_STATUS, 0); 5532478be82SVinod Koul return false; 5542478be82SVinod Koul } 5552478be82SVinod Koul 5568bd5741eSChristian Lamparter static int renesas_load_fw(struct pci_dev *pdev, const struct firmware *fw) 5578bd5741eSChristian Lamparter { 5588bd5741eSChristian Lamparter int err = 0; 5592478be82SVinod Koul bool rom; 5602478be82SVinod Koul 5612478be82SVinod Koul /* Check if the device has external ROM */ 5622478be82SVinod Koul rom = renesas_check_rom(pdev); 5632478be82SVinod Koul if (rom) { 5642478be82SVinod Koul /* perform chip erase first */ 5652478be82SVinod Koul renesas_rom_erase(pdev); 5662478be82SVinod Koul 5672478be82SVinod Koul /* lets try loading fw on ROM first */ 5682478be82SVinod Koul rom = renesas_setup_rom(pdev, fw); 5692478be82SVinod Koul if (!rom) { 5702478be82SVinod Koul dev_dbg(&pdev->dev, 5712478be82SVinod Koul "ROM load failed, falling back on FW load\n"); 5722478be82SVinod Koul } else { 5732478be82SVinod Koul dev_dbg(&pdev->dev, 5742478be82SVinod Koul "ROM load success\n"); 5752478be82SVinod Koul goto exit; 5762478be82SVinod Koul } 5772478be82SVinod Koul } 5788bd5741eSChristian Lamparter 5798bd5741eSChristian Lamparter err = renesas_fw_download(pdev, fw); 5802478be82SVinod Koul 5812478be82SVinod Koul exit: 5828bd5741eSChristian Lamparter if (err) 5838bd5741eSChristian Lamparter dev_err(&pdev->dev, "firmware failed to download (%d).", err); 5848bd5741eSChristian Lamparter return err; 5858bd5741eSChristian Lamparter } 5868bd5741eSChristian Lamparter 5878bd5741eSChristian Lamparter int renesas_xhci_check_request_fw(struct pci_dev *pdev, 5888bd5741eSChristian Lamparter const struct pci_device_id *id) 5898bd5741eSChristian Lamparter { 5908bd5741eSChristian Lamparter struct xhci_driver_data *driver_data = 5918bd5741eSChristian Lamparter (struct xhci_driver_data *)id->driver_data; 5928bd5741eSChristian Lamparter const char *fw_name = driver_data->firmware; 5938bd5741eSChristian Lamparter const struct firmware *fw; 5948bd5741eSChristian Lamparter int err; 5958bd5741eSChristian Lamparter 5968bd5741eSChristian Lamparter err = renesas_fw_check_running(pdev); 5978bd5741eSChristian Lamparter /* Continue ahead, if the firmware is already running. */ 598*e13690d5SMoritz Fischer if (!err) 5998bd5741eSChristian Lamparter return 0; 6008bd5741eSChristian Lamparter 6018bd5741eSChristian Lamparter if (err != 1) 6028bd5741eSChristian Lamparter return err; 6038bd5741eSChristian Lamparter 6048bd5741eSChristian Lamparter pci_dev_get(pdev); 6058bd5741eSChristian Lamparter err = request_firmware(&fw, fw_name, &pdev->dev); 6068bd5741eSChristian Lamparter pci_dev_put(pdev); 6078bd5741eSChristian Lamparter if (err) { 6088bd5741eSChristian Lamparter dev_err(&pdev->dev, "request_firmware failed: %d\n", err); 6098bd5741eSChristian Lamparter return err; 6108bd5741eSChristian Lamparter } 6118bd5741eSChristian Lamparter 6128bd5741eSChristian Lamparter err = renesas_fw_verify(fw->data, fw->size); 6138bd5741eSChristian Lamparter if (err) 6148bd5741eSChristian Lamparter goto exit; 6158bd5741eSChristian Lamparter 6168bd5741eSChristian Lamparter err = renesas_load_fw(pdev, fw); 6178bd5741eSChristian Lamparter exit: 6188bd5741eSChristian Lamparter release_firmware(fw); 6198bd5741eSChristian Lamparter return err; 6208bd5741eSChristian Lamparter } 6218bd5741eSChristian Lamparter EXPORT_SYMBOL_GPL(renesas_xhci_check_request_fw); 6228bd5741eSChristian Lamparter 6238bd5741eSChristian Lamparter void renesas_xhci_pci_exit(struct pci_dev *dev) 6248bd5741eSChristian Lamparter { 6258bd5741eSChristian Lamparter } 6268bd5741eSChristian Lamparter EXPORT_SYMBOL_GPL(renesas_xhci_pci_exit); 6278bd5741eSChristian Lamparter 6288bd5741eSChristian Lamparter MODULE_LICENSE("GPL v2"); 629