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 
200*e90f9cebSMoritz 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 */
2102478be82SVinod Koul 			return 0;
2112478be82SVinod Koul 
2122478be82SVinod Koul 		case RENESAS_ROM_STATUS_ERROR: /* Error State */
2132478be82SVinod Koul 		default: /* All other states are marked as "Reserved states" */
2142478be82SVinod Koul 			dev_err(&pdev->dev, "Invalid ROM..");
2152478be82SVinod Koul 			break;
2162478be82SVinod Koul 		}
2172478be82SVinod Koul 	}
2182478be82SVinod Koul 
2192478be82SVinod Koul 	return -EIO;
2202478be82SVinod Koul }
2212478be82SVinod Koul 
2228bd5741eSChristian Lamparter static int renesas_fw_check_running(struct pci_dev *pdev)
2238bd5741eSChristian Lamparter {
2248bd5741eSChristian Lamparter 	u8 fw_state;
2252478be82SVinod Koul 	int err;
2262478be82SVinod Koul 
2272478be82SVinod Koul 	/* Check if device has ROM and loaded, if so skip everything */
2282478be82SVinod Koul 	err = renesas_check_rom(pdev);
2292478be82SVinod Koul 	if (err) { /* we have rom */
2302478be82SVinod Koul 		err = renesas_check_rom_state(pdev);
2312478be82SVinod Koul 		if (!err)
2322478be82SVinod Koul 			return err;
2332478be82SVinod Koul 	}
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. */
5988bd5741eSChristian Lamparter 	if (err == 0)
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