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 532478be82SVinod Koul #define ROM_VALID_01 0x2013 542478be82SVinod Koul #define ROM_VALID_02 0x2026 552478be82SVinod Koul 562478be82SVinod Koul static int renesas_verify_fw_version(struct pci_dev *pdev, u32 version) 572478be82SVinod Koul { 582478be82SVinod Koul switch (version) { 592478be82SVinod Koul case ROM_VALID_01: 602478be82SVinod Koul case ROM_VALID_02: 612478be82SVinod Koul return 0; 622478be82SVinod Koul } 632478be82SVinod Koul dev_err(&pdev->dev, "FW has invalid version :%d\n", version); 642478be82SVinod Koul return -EINVAL; 652478be82SVinod Koul } 662478be82SVinod Koul 678bd5741eSChristian Lamparter static int renesas_fw_download_image(struct pci_dev *dev, 682478be82SVinod Koul const u32 *fw, size_t step, bool rom) 698bd5741eSChristian Lamparter { 708bd5741eSChristian Lamparter size_t i; 718bd5741eSChristian Lamparter int err; 728bd5741eSChristian Lamparter u8 fw_status; 738bd5741eSChristian Lamparter bool data0_or_data1; 742478be82SVinod Koul u32 status_reg; 752478be82SVinod Koul 762478be82SVinod Koul if (rom) 772478be82SVinod Koul status_reg = RENESAS_ROM_STATUS_MSB; 782478be82SVinod Koul else 792478be82SVinod Koul status_reg = RENESAS_FW_STATUS_MSB; 808bd5741eSChristian Lamparter 818bd5741eSChristian Lamparter /* 828bd5741eSChristian Lamparter * The hardware does alternate between two 32-bit pages. 838bd5741eSChristian Lamparter * (This is because each row of the firmware is 8 bytes). 848bd5741eSChristian Lamparter * 858bd5741eSChristian Lamparter * for even steps we use DATA0, for odd steps DATA1. 868bd5741eSChristian Lamparter */ 878bd5741eSChristian Lamparter data0_or_data1 = (step & 1) == 1; 888bd5741eSChristian Lamparter 898bd5741eSChristian Lamparter /* step+1. Read "Set DATAX" and confirm it is cleared. */ 908bd5741eSChristian Lamparter for (i = 0; i < RENESAS_RETRY; i++) { 912478be82SVinod Koul err = pci_read_config_byte(dev, status_reg, &fw_status); 928bd5741eSChristian Lamparter if (err) { 938bd5741eSChristian Lamparter dev_err(&dev->dev, "Read Status failed: %d\n", 948bd5741eSChristian Lamparter pcibios_err_to_errno(err)); 958bd5741eSChristian Lamparter return pcibios_err_to_errno(err); 968bd5741eSChristian Lamparter } 978bd5741eSChristian Lamparter if (!(fw_status & BIT(data0_or_data1))) 988bd5741eSChristian Lamparter break; 998bd5741eSChristian Lamparter 1008bd5741eSChristian Lamparter udelay(RENESAS_DELAY); 1018bd5741eSChristian Lamparter } 1028bd5741eSChristian Lamparter if (i == RENESAS_RETRY) { 1038bd5741eSChristian Lamparter dev_err(&dev->dev, "Timeout for Set DATAX step: %zd\n", step); 1048bd5741eSChristian Lamparter return -ETIMEDOUT; 1058bd5741eSChristian Lamparter } 1068bd5741eSChristian Lamparter 1078bd5741eSChristian Lamparter /* 1088bd5741eSChristian Lamparter * step+2. Write FW data to "DATAX". 1098bd5741eSChristian Lamparter * "LSB is left" => force little endian 1108bd5741eSChristian Lamparter */ 1118bd5741eSChristian Lamparter err = pci_write_config_dword(dev, data0_or_data1 ? 1128bd5741eSChristian Lamparter RENESAS_DATA1 : RENESAS_DATA0, 1138bd5741eSChristian Lamparter (__force u32)cpu_to_le32(fw[step])); 1148bd5741eSChristian Lamparter if (err) { 1158bd5741eSChristian Lamparter dev_err(&dev->dev, "Write to DATAX failed: %d\n", 1168bd5741eSChristian Lamparter pcibios_err_to_errno(err)); 1178bd5741eSChristian Lamparter return pcibios_err_to_errno(err); 1188bd5741eSChristian Lamparter } 1198bd5741eSChristian Lamparter 1208bd5741eSChristian Lamparter udelay(100); 1218bd5741eSChristian Lamparter 1228bd5741eSChristian Lamparter /* step+3. Set "Set DATAX". */ 1232478be82SVinod Koul err = pci_write_config_byte(dev, status_reg, BIT(data0_or_data1)); 1248bd5741eSChristian Lamparter if (err) { 1258bd5741eSChristian Lamparter dev_err(&dev->dev, "Write config for DATAX failed: %d\n", 1268bd5741eSChristian Lamparter pcibios_err_to_errno(err)); 1278bd5741eSChristian Lamparter return pcibios_err_to_errno(err); 1288bd5741eSChristian Lamparter } 1298bd5741eSChristian Lamparter 1308bd5741eSChristian Lamparter return 0; 1318bd5741eSChristian Lamparter } 1328bd5741eSChristian Lamparter 1338bd5741eSChristian Lamparter static int renesas_fw_verify(const void *fw_data, 1348bd5741eSChristian Lamparter size_t length) 1358bd5741eSChristian Lamparter { 1368bd5741eSChristian Lamparter u16 fw_version_pointer; 1378bd5741eSChristian Lamparter u16 fw_version; 1388bd5741eSChristian Lamparter 1398bd5741eSChristian Lamparter /* 1408bd5741eSChristian Lamparter * The Firmware's Data Format is describe in 1418bd5741eSChristian Lamparter * "6.3 Data Format" R19UH0078EJ0500 Rev.5.00 page 124 1428bd5741eSChristian Lamparter */ 1438bd5741eSChristian Lamparter 1448bd5741eSChristian Lamparter /* 1458bd5741eSChristian Lamparter * The bootrom chips of the big brother have sizes up to 64k, let's 1468bd5741eSChristian Lamparter * assume that's the biggest the firmware can get. 1478bd5741eSChristian Lamparter */ 1488bd5741eSChristian Lamparter if (length < 0x1000 || length >= 0x10000) { 1498bd5741eSChristian Lamparter pr_err("firmware is size %zd is not (4k - 64k).", 1508bd5741eSChristian Lamparter length); 1518bd5741eSChristian Lamparter return -EINVAL; 1528bd5741eSChristian Lamparter } 1538bd5741eSChristian Lamparter 1548bd5741eSChristian Lamparter /* The First 2 bytes are fixed value (55aa). "LSB on Left" */ 1558bd5741eSChristian Lamparter if (get_unaligned_le16(fw_data) != 0x55aa) { 1568bd5741eSChristian Lamparter pr_err("no valid firmware header found."); 1578bd5741eSChristian Lamparter return -EINVAL; 1588bd5741eSChristian Lamparter } 1598bd5741eSChristian Lamparter 1608bd5741eSChristian Lamparter /* verify the firmware version position and print it. */ 1618bd5741eSChristian Lamparter fw_version_pointer = get_unaligned_le16(fw_data + 4); 1628bd5741eSChristian Lamparter if (fw_version_pointer + 2 >= length) { 1638bd5741eSChristian Lamparter pr_err("fw ver pointer is outside of the firmware image"); 1648bd5741eSChristian Lamparter return -EINVAL; 1658bd5741eSChristian Lamparter } 1668bd5741eSChristian Lamparter 1678bd5741eSChristian Lamparter fw_version = get_unaligned_le16(fw_data + fw_version_pointer); 1688bd5741eSChristian Lamparter pr_err("got firmware version: %02x.", fw_version); 1698bd5741eSChristian Lamparter 1708bd5741eSChristian Lamparter return 0; 1718bd5741eSChristian Lamparter } 1728bd5741eSChristian Lamparter 1732478be82SVinod Koul static bool renesas_check_rom(struct pci_dev *pdev) 1742478be82SVinod Koul { 1752478be82SVinod Koul u16 rom_status; 1762478be82SVinod Koul int retval; 1772478be82SVinod Koul 1782478be82SVinod Koul /* Check if external ROM exists */ 1792478be82SVinod Koul retval = pci_read_config_word(pdev, RENESAS_ROM_STATUS, &rom_status); 1802478be82SVinod Koul if (retval) 1812478be82SVinod Koul return false; 1822478be82SVinod Koul 1832478be82SVinod Koul rom_status &= RENESAS_ROM_STATUS_ROM_EXISTS; 1842478be82SVinod Koul if (rom_status) { 1852478be82SVinod Koul dev_dbg(&pdev->dev, "External ROM exists\n"); 1862478be82SVinod Koul return true; /* External ROM exists */ 1872478be82SVinod Koul } 1882478be82SVinod Koul 1892478be82SVinod Koul return false; 1902478be82SVinod Koul } 1912478be82SVinod Koul 1922478be82SVinod Koul static int renesas_check_rom_state(struct pci_dev *pdev) 1932478be82SVinod Koul { 1942478be82SVinod Koul u16 rom_state; 1952478be82SVinod Koul u32 version; 1962478be82SVinod Koul int err; 1972478be82SVinod Koul 1982478be82SVinod Koul /* check FW version */ 1992478be82SVinod Koul err = pci_read_config_dword(pdev, RENESAS_FW_VERSION, &version); 2002478be82SVinod Koul if (err) 2012478be82SVinod Koul return pcibios_err_to_errno(err); 2022478be82SVinod Koul 2032478be82SVinod Koul version &= RENESAS_FW_VERSION_FIELD; 2042478be82SVinod Koul version = version >> RENESAS_FW_VERSION_OFFSET; 2052478be82SVinod Koul 2062478be82SVinod Koul err = renesas_verify_fw_version(pdev, version); 2072478be82SVinod Koul if (err) 2082478be82SVinod Koul return err; 2092478be82SVinod Koul 2102478be82SVinod Koul /* 2112478be82SVinod Koul * Test if ROM is present and loaded, if so we can skip everything 2122478be82SVinod Koul */ 2132478be82SVinod Koul err = pci_read_config_word(pdev, RENESAS_ROM_STATUS, &rom_state); 2142478be82SVinod Koul if (err) 2152478be82SVinod Koul return pcibios_err_to_errno(err); 2162478be82SVinod Koul 2172478be82SVinod Koul if (rom_state & BIT(15)) { 2182478be82SVinod Koul /* ROM exists */ 2192478be82SVinod Koul dev_dbg(&pdev->dev, "ROM exists\n"); 2202478be82SVinod Koul 2212478be82SVinod Koul /* Check the "Result Code" Bits (6:4) and act accordingly */ 2222478be82SVinod Koul switch (rom_state & RENESAS_ROM_STATUS_RESULT) { 2232478be82SVinod Koul case RENESAS_ROM_STATUS_SUCCESS: 2242478be82SVinod Koul return 0; 2252478be82SVinod Koul 2262478be82SVinod Koul case RENESAS_ROM_STATUS_NO_RESULT: /* No result yet */ 2272478be82SVinod Koul return 0; 2282478be82SVinod Koul 2292478be82SVinod Koul case RENESAS_ROM_STATUS_ERROR: /* Error State */ 2302478be82SVinod Koul default: /* All other states are marked as "Reserved states" */ 2312478be82SVinod Koul dev_err(&pdev->dev, "Invalid ROM.."); 2322478be82SVinod Koul break; 2332478be82SVinod Koul } 2342478be82SVinod Koul } 2352478be82SVinod Koul 2362478be82SVinod Koul return -EIO; 2372478be82SVinod Koul } 2382478be82SVinod Koul 2398bd5741eSChristian Lamparter static int renesas_fw_check_running(struct pci_dev *pdev) 2408bd5741eSChristian Lamparter { 2418bd5741eSChristian Lamparter u8 fw_state; 2422478be82SVinod Koul int err; 2432478be82SVinod Koul 2442478be82SVinod Koul /* Check if device has ROM and loaded, if so skip everything */ 2452478be82SVinod Koul err = renesas_check_rom(pdev); 2462478be82SVinod Koul if (err) { /* we have rom */ 2472478be82SVinod Koul err = renesas_check_rom_state(pdev); 2482478be82SVinod Koul if (!err) 2492478be82SVinod Koul return err; 2502478be82SVinod Koul } 2518bd5741eSChristian Lamparter 2528bd5741eSChristian Lamparter /* 2538bd5741eSChristian Lamparter * Test if the device is actually needing the firmware. As most 2548bd5741eSChristian Lamparter * BIOSes will initialize the device for us. If the device is 2558bd5741eSChristian Lamparter * initialized. 2568bd5741eSChristian Lamparter */ 2578bd5741eSChristian Lamparter err = pci_read_config_byte(pdev, RENESAS_FW_STATUS, &fw_state); 2588bd5741eSChristian Lamparter if (err) 2598bd5741eSChristian Lamparter return pcibios_err_to_errno(err); 2608bd5741eSChristian Lamparter 2618bd5741eSChristian Lamparter /* 2628bd5741eSChristian Lamparter * Check if "FW Download Lock" is locked. If it is and the FW is 2638bd5741eSChristian Lamparter * ready we can simply continue. If the FW is not ready, we have 2648bd5741eSChristian Lamparter * to give up. 2658bd5741eSChristian Lamparter */ 2668bd5741eSChristian Lamparter if (fw_state & RENESAS_FW_STATUS_LOCK) { 2678bd5741eSChristian Lamparter dev_dbg(&pdev->dev, "FW Download Lock is engaged."); 2688bd5741eSChristian Lamparter 2698bd5741eSChristian Lamparter if (fw_state & RENESAS_FW_STATUS_SUCCESS) 2708bd5741eSChristian Lamparter return 0; 2718bd5741eSChristian Lamparter 2728bd5741eSChristian Lamparter dev_err(&pdev->dev, 2738bd5741eSChristian Lamparter "FW Download Lock is set and FW is not ready. Giving Up."); 2748bd5741eSChristian Lamparter return -EIO; 2758bd5741eSChristian Lamparter } 2768bd5741eSChristian Lamparter 2778bd5741eSChristian Lamparter /* 2788bd5741eSChristian Lamparter * Check if "FW Download Enable" is set. If someone (us?) tampered 2798bd5741eSChristian Lamparter * with it and it can't be reset, we have to give up too... and 2808bd5741eSChristian Lamparter * ask for a forgiveness and a reboot. 2818bd5741eSChristian Lamparter */ 2828bd5741eSChristian Lamparter if (fw_state & RENESAS_FW_STATUS_DOWNLOAD_ENABLE) { 2838bd5741eSChristian Lamparter dev_err(&pdev->dev, 2848bd5741eSChristian Lamparter "FW Download Enable is stale. Giving Up (poweroff/reboot needed)."); 2858bd5741eSChristian Lamparter return -EIO; 2868bd5741eSChristian Lamparter } 2878bd5741eSChristian Lamparter 2888bd5741eSChristian Lamparter /* Otherwise, Check the "Result Code" Bits (6:4) and act accordingly */ 2898bd5741eSChristian Lamparter switch (fw_state & RENESAS_FW_STATUS_RESULT) { 2908bd5741eSChristian Lamparter case 0: /* No result yet */ 2918bd5741eSChristian Lamparter dev_dbg(&pdev->dev, "FW is not ready/loaded yet."); 2928bd5741eSChristian Lamparter 2938bd5741eSChristian Lamparter /* tell the caller, that this device needs the firmware. */ 2948bd5741eSChristian Lamparter return 1; 2958bd5741eSChristian Lamparter 2968bd5741eSChristian Lamparter case RENESAS_FW_STATUS_SUCCESS: /* Success, device should be working. */ 2978bd5741eSChristian Lamparter dev_dbg(&pdev->dev, "FW is ready."); 2988bd5741eSChristian Lamparter return 0; 2998bd5741eSChristian Lamparter 3008bd5741eSChristian Lamparter case RENESAS_FW_STATUS_ERROR: /* Error State */ 3018bd5741eSChristian Lamparter dev_err(&pdev->dev, 3028bd5741eSChristian Lamparter "hardware is in an error state. Giving up (poweroff/reboot needed)."); 3038bd5741eSChristian Lamparter return -ENODEV; 3048bd5741eSChristian Lamparter 3058bd5741eSChristian Lamparter default: /* All other states are marked as "Reserved states" */ 3068bd5741eSChristian Lamparter dev_err(&pdev->dev, 3078bd5741eSChristian Lamparter "hardware is in an invalid state %lx. Giving up (poweroff/reboot needed).", 3088bd5741eSChristian Lamparter (fw_state & RENESAS_FW_STATUS_RESULT) >> 4); 3098bd5741eSChristian Lamparter return -EINVAL; 3108bd5741eSChristian Lamparter } 3118bd5741eSChristian Lamparter } 3128bd5741eSChristian Lamparter 3138bd5741eSChristian Lamparter static int renesas_fw_download(struct pci_dev *pdev, 3148bd5741eSChristian Lamparter const struct firmware *fw) 3158bd5741eSChristian Lamparter { 3168bd5741eSChristian Lamparter const u32 *fw_data = (const u32 *)fw->data; 3178bd5741eSChristian Lamparter size_t i; 3188bd5741eSChristian Lamparter int err; 3198bd5741eSChristian Lamparter u8 fw_status; 3208bd5741eSChristian Lamparter 3218bd5741eSChristian Lamparter /* 3228bd5741eSChristian Lamparter * For more information and the big picture: please look at the 3238bd5741eSChristian Lamparter * "Firmware Download Sequence" in "7.1 FW Download Interface" 3248bd5741eSChristian Lamparter * of R19UH0078EJ0500 Rev.5.00 page 131 3258bd5741eSChristian Lamparter */ 3268bd5741eSChristian Lamparter 3278bd5741eSChristian Lamparter /* 3288bd5741eSChristian Lamparter * 0. Set "FW Download Enable" bit in the 3298bd5741eSChristian Lamparter * "FW Download Control & Status Register" at 0xF4 3308bd5741eSChristian Lamparter */ 3318bd5741eSChristian Lamparter err = pci_write_config_byte(pdev, RENESAS_FW_STATUS, 3328bd5741eSChristian Lamparter RENESAS_FW_STATUS_DOWNLOAD_ENABLE); 3338bd5741eSChristian Lamparter if (err) 3348bd5741eSChristian Lamparter return pcibios_err_to_errno(err); 3358bd5741eSChristian Lamparter 3368bd5741eSChristian Lamparter /* 1 - 10 follow one step after the other. */ 3378bd5741eSChristian Lamparter for (i = 0; i < fw->size / 4; i++) { 3382478be82SVinod Koul err = renesas_fw_download_image(pdev, fw_data, i, false); 3398bd5741eSChristian Lamparter if (err) { 3408bd5741eSChristian Lamparter dev_err(&pdev->dev, 3418bd5741eSChristian Lamparter "Firmware Download Step %zd failed at position %zd bytes with (%d).", 3428bd5741eSChristian Lamparter i, i * 4, err); 3438bd5741eSChristian Lamparter return err; 3448bd5741eSChristian Lamparter } 3458bd5741eSChristian Lamparter } 3468bd5741eSChristian Lamparter 3478bd5741eSChristian Lamparter /* 3488bd5741eSChristian Lamparter * This sequence continues until the last data is written to 3498bd5741eSChristian Lamparter * "DATA0" or "DATA1". Naturally, we wait until "SET DATA0/1" 3508bd5741eSChristian Lamparter * is cleared by the hardware beforehand. 3518bd5741eSChristian Lamparter */ 3528bd5741eSChristian Lamparter for (i = 0; i < RENESAS_RETRY; i++) { 3538bd5741eSChristian Lamparter err = pci_read_config_byte(pdev, RENESAS_FW_STATUS_MSB, 3548bd5741eSChristian Lamparter &fw_status); 3558bd5741eSChristian Lamparter if (err) 3568bd5741eSChristian Lamparter return pcibios_err_to_errno(err); 3578bd5741eSChristian Lamparter if (!(fw_status & (BIT(0) | BIT(1)))) 3588bd5741eSChristian Lamparter break; 3598bd5741eSChristian Lamparter 3608bd5741eSChristian Lamparter udelay(RENESAS_DELAY); 3618bd5741eSChristian Lamparter } 3628bd5741eSChristian Lamparter if (i == RENESAS_RETRY) 3638bd5741eSChristian Lamparter dev_warn(&pdev->dev, "Final Firmware Download step timed out."); 3648bd5741eSChristian Lamparter 3658bd5741eSChristian Lamparter /* 3668bd5741eSChristian Lamparter * 11. After finishing writing the last data of FW, the 3678bd5741eSChristian Lamparter * System Software must clear "FW Download Enable" 3688bd5741eSChristian Lamparter */ 3698bd5741eSChristian Lamparter err = pci_write_config_byte(pdev, RENESAS_FW_STATUS, 0); 3708bd5741eSChristian Lamparter if (err) 3718bd5741eSChristian Lamparter return pcibios_err_to_errno(err); 3728bd5741eSChristian Lamparter 3738bd5741eSChristian Lamparter /* 12. Read "Result Code" and confirm it is good. */ 3748bd5741eSChristian Lamparter for (i = 0; i < RENESAS_RETRY; i++) { 3758bd5741eSChristian Lamparter err = pci_read_config_byte(pdev, RENESAS_FW_STATUS, &fw_status); 3768bd5741eSChristian Lamparter if (err) 3778bd5741eSChristian Lamparter return pcibios_err_to_errno(err); 3788bd5741eSChristian Lamparter if (fw_status & RENESAS_FW_STATUS_SUCCESS) 3798bd5741eSChristian Lamparter break; 3808bd5741eSChristian Lamparter 3818bd5741eSChristian Lamparter udelay(RENESAS_DELAY); 3828bd5741eSChristian Lamparter } 3838bd5741eSChristian Lamparter if (i == RENESAS_RETRY) { 3848bd5741eSChristian Lamparter /* Timed out / Error - let's see if we can fix this */ 3858bd5741eSChristian Lamparter err = renesas_fw_check_running(pdev); 3868bd5741eSChristian Lamparter switch (err) { 3878bd5741eSChristian Lamparter case 0: /* 3888bd5741eSChristian Lamparter * we shouldn't end up here. 3898bd5741eSChristian Lamparter * maybe it took a little bit longer. 3908bd5741eSChristian Lamparter * But all should be well? 3918bd5741eSChristian Lamparter */ 3928bd5741eSChristian Lamparter break; 3938bd5741eSChristian Lamparter 3948bd5741eSChristian Lamparter case 1: /* (No result yet! */ 3958bd5741eSChristian Lamparter dev_err(&pdev->dev, "FW Load timedout"); 3968bd5741eSChristian Lamparter return -ETIMEDOUT; 3978bd5741eSChristian Lamparter 3988bd5741eSChristian Lamparter default: 3998bd5741eSChristian Lamparter return err; 4008bd5741eSChristian Lamparter } 4018bd5741eSChristian Lamparter } 4028bd5741eSChristian Lamparter 4038bd5741eSChristian Lamparter return 0; 4048bd5741eSChristian Lamparter } 4058bd5741eSChristian Lamparter 4062478be82SVinod Koul static void renesas_rom_erase(struct pci_dev *pdev) 4072478be82SVinod Koul { 4082478be82SVinod Koul int retval, i; 4092478be82SVinod Koul u8 status; 4102478be82SVinod Koul 4112478be82SVinod Koul dev_dbg(&pdev->dev, "Performing ROM Erase...\n"); 4122478be82SVinod Koul retval = pci_write_config_dword(pdev, RENESAS_DATA0, 4132478be82SVinod Koul RENESAS_ROM_ERASE_MAGIC); 4142478be82SVinod Koul if (retval) { 4152478be82SVinod Koul dev_err(&pdev->dev, "ROM erase, magic word write failed: %d\n", 4162478be82SVinod Koul pcibios_err_to_errno(retval)); 4172478be82SVinod Koul return; 4182478be82SVinod Koul } 4192478be82SVinod Koul 4202478be82SVinod Koul retval = pci_read_config_byte(pdev, RENESAS_ROM_STATUS, &status); 4212478be82SVinod Koul if (retval) { 4222478be82SVinod Koul dev_err(&pdev->dev, "ROM status read failed: %d\n", 4232478be82SVinod Koul pcibios_err_to_errno(retval)); 4242478be82SVinod Koul return; 4252478be82SVinod Koul } 4262478be82SVinod Koul status |= RENESAS_ROM_STATUS_ERASE; 4272478be82SVinod Koul retval = pci_write_config_byte(pdev, RENESAS_ROM_STATUS, status); 4282478be82SVinod Koul if (retval) { 4292478be82SVinod Koul dev_err(&pdev->dev, "ROM erase set word write failed\n"); 4302478be82SVinod Koul return; 4312478be82SVinod Koul } 4322478be82SVinod Koul 4332478be82SVinod Koul /* sleep a bit while ROM is erased */ 4342478be82SVinod Koul msleep(20); 4352478be82SVinod Koul 4362478be82SVinod Koul for (i = 0; i < RENESAS_RETRY; i++) { 4372478be82SVinod Koul retval = pci_read_config_byte(pdev, RENESAS_ROM_STATUS, 4382478be82SVinod Koul &status); 4392478be82SVinod Koul status &= RENESAS_ROM_STATUS_ERASE; 4402478be82SVinod Koul if (!status) 4412478be82SVinod Koul break; 4422478be82SVinod Koul 4432478be82SVinod Koul mdelay(RENESAS_DELAY); 4442478be82SVinod Koul } 4452478be82SVinod Koul 4462478be82SVinod Koul if (i == RENESAS_RETRY) 4472478be82SVinod Koul dev_dbg(&pdev->dev, "Chip erase timedout: %x\n", status); 4482478be82SVinod Koul 4492478be82SVinod Koul dev_dbg(&pdev->dev, "ROM Erase... Done success\n"); 4502478be82SVinod Koul } 4512478be82SVinod Koul 4522478be82SVinod Koul static bool renesas_setup_rom(struct pci_dev *pdev, const struct firmware *fw) 4532478be82SVinod Koul { 4542478be82SVinod Koul const u32 *fw_data = (const u32 *)fw->data; 4552478be82SVinod Koul int err, i; 4562478be82SVinod Koul u8 status; 4572478be82SVinod Koul 4582478be82SVinod Koul /* 2. Write magic word to Data0 */ 4592478be82SVinod Koul err = pci_write_config_dword(pdev, RENESAS_DATA0, 4602478be82SVinod Koul RENESAS_ROM_WRITE_MAGIC); 4612478be82SVinod Koul if (err) 4622478be82SVinod Koul return false; 4632478be82SVinod Koul 4642478be82SVinod Koul /* 3. Set External ROM access */ 4652478be82SVinod Koul err = pci_write_config_byte(pdev, RENESAS_ROM_STATUS, 4662478be82SVinod Koul RENESAS_ROM_STATUS_ACCESS); 4672478be82SVinod Koul if (err) 4682478be82SVinod Koul goto remove_bypass; 4692478be82SVinod Koul 4702478be82SVinod Koul /* 4. Check the result */ 4712478be82SVinod Koul err = pci_read_config_byte(pdev, RENESAS_ROM_STATUS, &status); 4722478be82SVinod Koul if (err) 4732478be82SVinod Koul goto remove_bypass; 4742478be82SVinod Koul status &= GENMASK(6, 4); 4752478be82SVinod Koul if (status) { 4762478be82SVinod Koul dev_err(&pdev->dev, 4772478be82SVinod Koul "setting external rom failed: %x\n", status); 4782478be82SVinod Koul goto remove_bypass; 4792478be82SVinod Koul } 4802478be82SVinod Koul 4812478be82SVinod Koul /* 5 to 16 Write FW to DATA0/1 while checking SetData0/1 */ 4822478be82SVinod Koul for (i = 0; i < fw->size / 4; i++) { 4832478be82SVinod Koul err = renesas_fw_download_image(pdev, fw_data, i, true); 4842478be82SVinod Koul if (err) { 4852478be82SVinod Koul dev_err(&pdev->dev, 4862478be82SVinod Koul "ROM Download Step %d failed at position %d bytes with (%d)\n", 4872478be82SVinod Koul i, i * 4, err); 4882478be82SVinod Koul goto remove_bypass; 4892478be82SVinod Koul } 4902478be82SVinod Koul } 4912478be82SVinod Koul 4922478be82SVinod Koul /* 4932478be82SVinod Koul * wait till DATA0/1 is cleared 4942478be82SVinod Koul */ 4952478be82SVinod Koul for (i = 0; i < RENESAS_RETRY; i++) { 4962478be82SVinod Koul err = pci_read_config_byte(pdev, RENESAS_ROM_STATUS_MSB, 4972478be82SVinod Koul &status); 4982478be82SVinod Koul if (err) 4992478be82SVinod Koul goto remove_bypass; 5002478be82SVinod Koul if (!(status & (BIT(0) | BIT(1)))) 5012478be82SVinod Koul break; 5022478be82SVinod Koul 5032478be82SVinod Koul udelay(RENESAS_DELAY); 5042478be82SVinod Koul } 5052478be82SVinod Koul if (i == RENESAS_RETRY) { 5062478be82SVinod Koul dev_err(&pdev->dev, "Final Firmware ROM Download step timed out\n"); 5072478be82SVinod Koul goto remove_bypass; 5082478be82SVinod Koul } 5092478be82SVinod Koul 5102478be82SVinod Koul /* 17. Remove bypass */ 5112478be82SVinod Koul err = pci_write_config_byte(pdev, RENESAS_ROM_STATUS, 0); 5122478be82SVinod Koul if (err) 5132478be82SVinod Koul return false; 5142478be82SVinod Koul 5152478be82SVinod Koul udelay(10); 5162478be82SVinod Koul 5172478be82SVinod Koul /* 18. check result */ 5182478be82SVinod Koul for (i = 0; i < RENESAS_RETRY; i++) { 5192478be82SVinod Koul err = pci_read_config_byte(pdev, RENESAS_ROM_STATUS, &status); 5202478be82SVinod Koul if (err) { 5212478be82SVinod Koul dev_err(&pdev->dev, "Read ROM status failed:%d\n", 5222478be82SVinod Koul pcibios_err_to_errno(err)); 5232478be82SVinod Koul return false; 5242478be82SVinod Koul } 5252478be82SVinod Koul status &= RENESAS_ROM_STATUS_RESULT; 5262478be82SVinod Koul if (status == RENESAS_ROM_STATUS_SUCCESS) { 5272478be82SVinod Koul dev_dbg(&pdev->dev, "Download ROM success\n"); 5282478be82SVinod Koul break; 5292478be82SVinod Koul } 5302478be82SVinod Koul udelay(RENESAS_DELAY); 5312478be82SVinod Koul } 5322478be82SVinod Koul if (i == RENESAS_RETRY) { /* Timed out */ 5332478be82SVinod Koul dev_err(&pdev->dev, 5342478be82SVinod Koul "Download to external ROM TO: %x\n", status); 5352478be82SVinod Koul return false; 5362478be82SVinod Koul } 5372478be82SVinod Koul 5382478be82SVinod Koul dev_dbg(&pdev->dev, "Download to external ROM succeeded\n"); 5392478be82SVinod Koul 5402478be82SVinod Koul /* Last step set Reload */ 5412478be82SVinod Koul err = pci_write_config_byte(pdev, RENESAS_ROM_STATUS, 5422478be82SVinod Koul RENESAS_ROM_STATUS_RELOAD); 5432478be82SVinod Koul if (err) { 5442478be82SVinod Koul dev_err(&pdev->dev, "Set ROM execute failed: %d\n", 5452478be82SVinod Koul pcibios_err_to_errno(err)); 5462478be82SVinod Koul return false; 5472478be82SVinod Koul } 5482478be82SVinod Koul 5492478be82SVinod Koul /* 5502478be82SVinod Koul * wait till Reload is cleared 5512478be82SVinod Koul */ 5522478be82SVinod Koul for (i = 0; i < RENESAS_RETRY; i++) { 5532478be82SVinod Koul err = pci_read_config_byte(pdev, RENESAS_ROM_STATUS, &status); 5542478be82SVinod Koul if (err) 5552478be82SVinod Koul return false; 5562478be82SVinod Koul if (!(status & RENESAS_ROM_STATUS_RELOAD)) 5572478be82SVinod Koul break; 5582478be82SVinod Koul 5592478be82SVinod Koul udelay(RENESAS_DELAY); 5602478be82SVinod Koul } 5612478be82SVinod Koul if (i == RENESAS_RETRY) { 5622478be82SVinod Koul dev_err(&pdev->dev, "ROM Exec timed out: %x\n", status); 5632478be82SVinod Koul return false; 5642478be82SVinod Koul } 5652478be82SVinod Koul 5662478be82SVinod Koul return true; 5672478be82SVinod Koul 5682478be82SVinod Koul remove_bypass: 5692478be82SVinod Koul pci_write_config_byte(pdev, RENESAS_ROM_STATUS, 0); 5702478be82SVinod Koul return false; 5712478be82SVinod Koul } 5722478be82SVinod Koul 5738bd5741eSChristian Lamparter static int renesas_load_fw(struct pci_dev *pdev, const struct firmware *fw) 5748bd5741eSChristian Lamparter { 5758bd5741eSChristian Lamparter int err = 0; 5762478be82SVinod Koul bool rom; 5772478be82SVinod Koul 5782478be82SVinod Koul /* Check if the device has external ROM */ 5792478be82SVinod Koul rom = renesas_check_rom(pdev); 5802478be82SVinod Koul if (rom) { 5812478be82SVinod Koul /* perform chip erase first */ 5822478be82SVinod Koul renesas_rom_erase(pdev); 5832478be82SVinod Koul 5842478be82SVinod Koul /* lets try loading fw on ROM first */ 5852478be82SVinod Koul rom = renesas_setup_rom(pdev, fw); 5862478be82SVinod Koul if (!rom) { 5872478be82SVinod Koul dev_dbg(&pdev->dev, 5882478be82SVinod Koul "ROM load failed, falling back on FW load\n"); 5892478be82SVinod Koul } else { 5902478be82SVinod Koul dev_dbg(&pdev->dev, 5912478be82SVinod Koul "ROM load success\n"); 5922478be82SVinod Koul goto exit; 5932478be82SVinod Koul } 5942478be82SVinod Koul } 5958bd5741eSChristian Lamparter 5968bd5741eSChristian Lamparter err = renesas_fw_download(pdev, fw); 5972478be82SVinod Koul 5982478be82SVinod Koul exit: 5998bd5741eSChristian Lamparter if (err) 6008bd5741eSChristian Lamparter dev_err(&pdev->dev, "firmware failed to download (%d).", err); 6018bd5741eSChristian Lamparter return err; 6028bd5741eSChristian Lamparter } 6038bd5741eSChristian Lamparter 6048bd5741eSChristian Lamparter int renesas_xhci_check_request_fw(struct pci_dev *pdev, 6058bd5741eSChristian Lamparter const struct pci_device_id *id) 6068bd5741eSChristian Lamparter { 6078bd5741eSChristian Lamparter struct xhci_driver_data *driver_data = 6088bd5741eSChristian Lamparter (struct xhci_driver_data *)id->driver_data; 6098bd5741eSChristian Lamparter const char *fw_name = driver_data->firmware; 6108bd5741eSChristian Lamparter const struct firmware *fw; 6118bd5741eSChristian Lamparter int err; 6128bd5741eSChristian Lamparter 6138bd5741eSChristian Lamparter err = renesas_fw_check_running(pdev); 6148bd5741eSChristian Lamparter /* Continue ahead, if the firmware is already running. */ 6158bd5741eSChristian Lamparter if (err == 0) 6168bd5741eSChristian Lamparter return 0; 6178bd5741eSChristian Lamparter 6188bd5741eSChristian Lamparter if (err != 1) 6198bd5741eSChristian Lamparter return err; 6208bd5741eSChristian Lamparter 6218bd5741eSChristian Lamparter pci_dev_get(pdev); 6228bd5741eSChristian Lamparter err = request_firmware(&fw, fw_name, &pdev->dev); 6238bd5741eSChristian Lamparter pci_dev_put(pdev); 6248bd5741eSChristian Lamparter if (err) { 6258bd5741eSChristian Lamparter dev_err(&pdev->dev, "request_firmware failed: %d\n", err); 6268bd5741eSChristian Lamparter return err; 6278bd5741eSChristian Lamparter } 6288bd5741eSChristian Lamparter 6298bd5741eSChristian Lamparter err = renesas_fw_verify(fw->data, fw->size); 6308bd5741eSChristian Lamparter if (err) 6318bd5741eSChristian Lamparter goto exit; 6328bd5741eSChristian Lamparter 6338bd5741eSChristian Lamparter err = renesas_load_fw(pdev, fw); 6348bd5741eSChristian Lamparter exit: 6358bd5741eSChristian Lamparter release_firmware(fw); 6368bd5741eSChristian Lamparter return err; 6378bd5741eSChristian Lamparter } 6388bd5741eSChristian Lamparter EXPORT_SYMBOL_GPL(renesas_xhci_check_request_fw); 6398bd5741eSChristian Lamparter 6408bd5741eSChristian Lamparter void renesas_xhci_pci_exit(struct pci_dev *dev) 6418bd5741eSChristian Lamparter { 6428bd5741eSChristian Lamparter } 6438bd5741eSChristian Lamparter EXPORT_SYMBOL_GPL(renesas_xhci_pci_exit); 6448bd5741eSChristian Lamparter 6458bd5741eSChristian Lamparter MODULE_LICENSE("GPL v2"); 646