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 
renesas_fw_download_image(struct pci_dev * dev,const u32 * fw,size_t step,bool rom)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 
renesas_fw_verify(const void * fw_data,size_t length)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 
1248bd5741eSChristian Lamparter 	/*
1258bd5741eSChristian Lamparter 	 * The Firmware's Data Format is describe in
1268bd5741eSChristian Lamparter 	 * "6.3 Data Format" R19UH0078EJ0500 Rev.5.00 page 124
1278bd5741eSChristian Lamparter 	 */
1288bd5741eSChristian Lamparter 
1298bd5741eSChristian Lamparter 	/*
1308bd5741eSChristian Lamparter 	 * The bootrom chips of the big brother have sizes up to 64k, let's
1318bd5741eSChristian Lamparter 	 * assume that's the biggest the firmware can get.
1328bd5741eSChristian Lamparter 	 */
1338bd5741eSChristian Lamparter 	if (length < 0x1000 || length >= 0x10000) {
1348bd5741eSChristian Lamparter 		pr_err("firmware is size %zd is not (4k - 64k).",
1358bd5741eSChristian Lamparter 			length);
1368bd5741eSChristian Lamparter 		return -EINVAL;
1378bd5741eSChristian Lamparter 	}
1388bd5741eSChristian Lamparter 
1398bd5741eSChristian Lamparter 	/* The First 2 bytes are fixed value (55aa). "LSB on Left" */
1408bd5741eSChristian Lamparter 	if (get_unaligned_le16(fw_data) != 0x55aa) {
1418bd5741eSChristian Lamparter 		pr_err("no valid firmware header found.");
1428bd5741eSChristian Lamparter 		return -EINVAL;
1438bd5741eSChristian Lamparter 	}
1448bd5741eSChristian Lamparter 
1458bd5741eSChristian Lamparter 	/* verify the firmware version position and print it. */
1468bd5741eSChristian Lamparter 	fw_version_pointer = get_unaligned_le16(fw_data + 4);
1478bd5741eSChristian Lamparter 	if (fw_version_pointer + 2 >= length) {
1488bd5741eSChristian Lamparter 		pr_err("fw ver pointer is outside of the firmware image");
1498bd5741eSChristian Lamparter 		return -EINVAL;
1508bd5741eSChristian Lamparter 	}
1518bd5741eSChristian Lamparter 
1528bd5741eSChristian Lamparter 	return 0;
1538bd5741eSChristian Lamparter }
1548bd5741eSChristian Lamparter 
renesas_check_rom(struct pci_dev * pdev)1552478be82SVinod Koul static bool renesas_check_rom(struct pci_dev *pdev)
1562478be82SVinod Koul {
1572478be82SVinod Koul 	u16 rom_status;
1582478be82SVinod Koul 	int retval;
1592478be82SVinod Koul 
1602478be82SVinod Koul 	/* Check if external ROM exists */
1612478be82SVinod Koul 	retval = pci_read_config_word(pdev, RENESAS_ROM_STATUS, &rom_status);
1622478be82SVinod Koul 	if (retval)
1632478be82SVinod Koul 		return false;
1642478be82SVinod Koul 
1652478be82SVinod Koul 	rom_status &= RENESAS_ROM_STATUS_ROM_EXISTS;
1662478be82SVinod Koul 	if (rom_status) {
1672478be82SVinod Koul 		dev_dbg(&pdev->dev, "External ROM exists\n");
1682478be82SVinod Koul 		return true; /* External ROM exists */
1692478be82SVinod Koul 	}
1702478be82SVinod Koul 
1712478be82SVinod Koul 	return false;
1722478be82SVinod Koul }
1732478be82SVinod Koul 
renesas_check_rom_state(struct pci_dev * pdev)1742478be82SVinod Koul static int renesas_check_rom_state(struct pci_dev *pdev)
1752478be82SVinod Koul {
1762478be82SVinod Koul 	u16 rom_state;
1772478be82SVinod Koul 	u32 version;
1782478be82SVinod Koul 	int err;
1792478be82SVinod Koul 
1802478be82SVinod Koul 	/* check FW version */
1812478be82SVinod Koul 	err = pci_read_config_dword(pdev, RENESAS_FW_VERSION, &version);
1822478be82SVinod Koul 	if (err)
1832478be82SVinod Koul 		return pcibios_err_to_errno(err);
1842478be82SVinod Koul 
1852478be82SVinod Koul 	version &= RENESAS_FW_VERSION_FIELD;
1862478be82SVinod Koul 	version = version >> RENESAS_FW_VERSION_OFFSET;
187d66a57beSVinod Koul 	dev_dbg(&pdev->dev, "Found ROM version: %x\n", version);
1882478be82SVinod Koul 
1892478be82SVinod Koul 	/*
1902478be82SVinod Koul 	 * Test if ROM is present and loaded, if so we can skip everything
1912478be82SVinod Koul 	 */
1922478be82SVinod Koul 	err = pci_read_config_word(pdev, RENESAS_ROM_STATUS, &rom_state);
1932478be82SVinod Koul 	if (err)
1942478be82SVinod Koul 		return pcibios_err_to_errno(err);
1952478be82SVinod Koul 
196e90f9cebSMoritz Fischer 	if (rom_state & RENESAS_ROM_STATUS_ROM_EXISTS) {
1972478be82SVinod Koul 		/* ROM exists */
1982478be82SVinod Koul 		dev_dbg(&pdev->dev, "ROM exists\n");
1992478be82SVinod Koul 
2002478be82SVinod Koul 		/* Check the "Result Code" Bits (6:4) and act accordingly */
2012478be82SVinod Koul 		switch (rom_state & RENESAS_ROM_STATUS_RESULT) {
2022478be82SVinod Koul 		case RENESAS_ROM_STATUS_SUCCESS:
2032478be82SVinod Koul 			return 0;
2042478be82SVinod Koul 
2052478be82SVinod Koul 		case RENESAS_ROM_STATUS_NO_RESULT: /* No result yet */
206*c82cacd2STakashi Iwai 			dev_dbg(&pdev->dev, "Unknown ROM status ...\n");
207*c82cacd2STakashi Iwai 			return -ENOENT;
2082478be82SVinod Koul 
2092478be82SVinod Koul 		case RENESAS_ROM_STATUS_ERROR: /* Error State */
2102478be82SVinod Koul 		default: /* All other states are marked as "Reserved states" */
2112478be82SVinod Koul 			dev_err(&pdev->dev, "Invalid ROM..");
2122478be82SVinod Koul 			break;
2132478be82SVinod Koul 		}
2142478be82SVinod Koul 	}
2152478be82SVinod Koul 
2162478be82SVinod Koul 	return -EIO;
2172478be82SVinod Koul }
2182478be82SVinod Koul 
renesas_fw_check_running(struct pci_dev * pdev)2198bd5741eSChristian Lamparter static int renesas_fw_check_running(struct pci_dev *pdev)
2208bd5741eSChristian Lamparter {
2218bd5741eSChristian Lamparter 	u8 fw_state;
2222478be82SVinod Koul 	int err;
2232478be82SVinod Koul 
2248bd5741eSChristian Lamparter 	/*
2258bd5741eSChristian Lamparter 	 * Test if the device is actually needing the firmware. As most
2268bd5741eSChristian Lamparter 	 * BIOSes will initialize the device for us. If the device is
2278bd5741eSChristian Lamparter 	 * initialized.
2288bd5741eSChristian Lamparter 	 */
2298bd5741eSChristian Lamparter 	err = pci_read_config_byte(pdev, RENESAS_FW_STATUS, &fw_state);
2308bd5741eSChristian Lamparter 	if (err)
2318bd5741eSChristian Lamparter 		return pcibios_err_to_errno(err);
2328bd5741eSChristian Lamparter 
2338bd5741eSChristian Lamparter 	/*
2348bd5741eSChristian Lamparter 	 * Check if "FW Download Lock" is locked. If it is and the FW is
2358bd5741eSChristian Lamparter 	 * ready we can simply continue. If the FW is not ready, we have
2368bd5741eSChristian Lamparter 	 * to give up.
2378bd5741eSChristian Lamparter 	 */
2388bd5741eSChristian Lamparter 	if (fw_state & RENESAS_FW_STATUS_LOCK) {
2398bd5741eSChristian Lamparter 		dev_dbg(&pdev->dev, "FW Download Lock is engaged.");
2408bd5741eSChristian Lamparter 
2418bd5741eSChristian Lamparter 		if (fw_state & RENESAS_FW_STATUS_SUCCESS)
2428bd5741eSChristian Lamparter 			return 0;
2438bd5741eSChristian Lamparter 
2448bd5741eSChristian Lamparter 		dev_err(&pdev->dev,
2458bd5741eSChristian Lamparter 			"FW Download Lock is set and FW is not ready. Giving Up.");
2468bd5741eSChristian Lamparter 		return -EIO;
2478bd5741eSChristian Lamparter 	}
2488bd5741eSChristian Lamparter 
2498bd5741eSChristian Lamparter 	/*
2508bd5741eSChristian Lamparter 	 * Check if "FW Download Enable" is set. If someone (us?) tampered
2518bd5741eSChristian Lamparter 	 * with it and it can't be reset, we have to give up too... and
2528bd5741eSChristian Lamparter 	 * ask for a forgiveness and a reboot.
2538bd5741eSChristian Lamparter 	 */
2548bd5741eSChristian Lamparter 	if (fw_state & RENESAS_FW_STATUS_DOWNLOAD_ENABLE) {
2558bd5741eSChristian Lamparter 		dev_err(&pdev->dev,
2568bd5741eSChristian Lamparter 			"FW Download Enable is stale. Giving Up (poweroff/reboot needed).");
2578bd5741eSChristian Lamparter 		return -EIO;
2588bd5741eSChristian Lamparter 	}
2598bd5741eSChristian Lamparter 
2608bd5741eSChristian Lamparter 	/* Otherwise, Check the "Result Code" Bits (6:4) and act accordingly */
2618bd5741eSChristian Lamparter 	switch (fw_state & RENESAS_FW_STATUS_RESULT) {
2628bd5741eSChristian Lamparter 	case 0: /* No result yet */
2638bd5741eSChristian Lamparter 		dev_dbg(&pdev->dev, "FW is not ready/loaded yet.");
2648bd5741eSChristian Lamparter 
2658bd5741eSChristian Lamparter 		/* tell the caller, that this device needs the firmware. */
2668bd5741eSChristian Lamparter 		return 1;
2678bd5741eSChristian Lamparter 
2688bd5741eSChristian Lamparter 	case RENESAS_FW_STATUS_SUCCESS: /* Success, device should be working. */
2698bd5741eSChristian Lamparter 		dev_dbg(&pdev->dev, "FW is ready.");
2708bd5741eSChristian Lamparter 		return 0;
2718bd5741eSChristian Lamparter 
2728bd5741eSChristian Lamparter 	case RENESAS_FW_STATUS_ERROR: /* Error State */
2738bd5741eSChristian Lamparter 		dev_err(&pdev->dev,
2748bd5741eSChristian Lamparter 			"hardware is in an error state. Giving up (poweroff/reboot needed).");
2758bd5741eSChristian Lamparter 		return -ENODEV;
2768bd5741eSChristian Lamparter 
2778bd5741eSChristian Lamparter 	default: /* All other states are marked as "Reserved states" */
2788bd5741eSChristian Lamparter 		dev_err(&pdev->dev,
2798bd5741eSChristian Lamparter 			"hardware is in an invalid state %lx. Giving up (poweroff/reboot needed).",
2808bd5741eSChristian Lamparter 			(fw_state & RENESAS_FW_STATUS_RESULT) >> 4);
2818bd5741eSChristian Lamparter 		return -EINVAL;
2828bd5741eSChristian Lamparter 	}
2838bd5741eSChristian Lamparter }
2848bd5741eSChristian Lamparter 
renesas_fw_download(struct pci_dev * pdev,const struct firmware * fw)2858bd5741eSChristian Lamparter static int renesas_fw_download(struct pci_dev *pdev,
2868bd5741eSChristian Lamparter 			       const struct firmware *fw)
2878bd5741eSChristian Lamparter {
2888bd5741eSChristian Lamparter 	const u32 *fw_data = (const u32 *)fw->data;
2898bd5741eSChristian Lamparter 	size_t i;
2908bd5741eSChristian Lamparter 	int err;
2918bd5741eSChristian Lamparter 	u8 fw_status;
2928bd5741eSChristian Lamparter 
2938bd5741eSChristian Lamparter 	/*
2948bd5741eSChristian Lamparter 	 * For more information and the big picture: please look at the
2958bd5741eSChristian Lamparter 	 * "Firmware Download Sequence" in "7.1 FW Download Interface"
2968bd5741eSChristian Lamparter 	 * of R19UH0078EJ0500 Rev.5.00 page 131
2978bd5741eSChristian Lamparter 	 */
2988bd5741eSChristian Lamparter 
2998bd5741eSChristian Lamparter 	/*
3008bd5741eSChristian Lamparter 	 * 0. Set "FW Download Enable" bit in the
3018bd5741eSChristian Lamparter 	 * "FW Download Control & Status Register" at 0xF4
3028bd5741eSChristian Lamparter 	 */
3038bd5741eSChristian Lamparter 	err = pci_write_config_byte(pdev, RENESAS_FW_STATUS,
3048bd5741eSChristian Lamparter 				    RENESAS_FW_STATUS_DOWNLOAD_ENABLE);
3058bd5741eSChristian Lamparter 	if (err)
3068bd5741eSChristian Lamparter 		return pcibios_err_to_errno(err);
3078bd5741eSChristian Lamparter 
3088bd5741eSChristian Lamparter 	/* 1 - 10 follow one step after the other. */
3098bd5741eSChristian Lamparter 	for (i = 0; i < fw->size / 4; i++) {
3102478be82SVinod Koul 		err = renesas_fw_download_image(pdev, fw_data, i, false);
3118bd5741eSChristian Lamparter 		if (err) {
3128bd5741eSChristian Lamparter 			dev_err(&pdev->dev,
3138bd5741eSChristian Lamparter 				"Firmware Download Step %zd failed at position %zd bytes with (%d).",
3148bd5741eSChristian Lamparter 				i, i * 4, err);
3158bd5741eSChristian Lamparter 			return err;
3168bd5741eSChristian Lamparter 		}
3178bd5741eSChristian Lamparter 	}
3188bd5741eSChristian Lamparter 
3198bd5741eSChristian Lamparter 	/*
3208bd5741eSChristian Lamparter 	 * This sequence continues until the last data is written to
3218bd5741eSChristian Lamparter 	 * "DATA0" or "DATA1". Naturally, we wait until "SET DATA0/1"
3228bd5741eSChristian Lamparter 	 * is cleared by the hardware beforehand.
3238bd5741eSChristian Lamparter 	 */
3248bd5741eSChristian Lamparter 	for (i = 0; i < RENESAS_RETRY; i++) {
3258bd5741eSChristian Lamparter 		err = pci_read_config_byte(pdev, RENESAS_FW_STATUS_MSB,
3268bd5741eSChristian Lamparter 					   &fw_status);
3278bd5741eSChristian Lamparter 		if (err)
3288bd5741eSChristian Lamparter 			return pcibios_err_to_errno(err);
3298bd5741eSChristian Lamparter 		if (!(fw_status & (BIT(0) | BIT(1))))
3308bd5741eSChristian Lamparter 			break;
3318bd5741eSChristian Lamparter 
3328bd5741eSChristian Lamparter 		udelay(RENESAS_DELAY);
3338bd5741eSChristian Lamparter 	}
3348bd5741eSChristian Lamparter 	if (i == RENESAS_RETRY)
3358bd5741eSChristian Lamparter 		dev_warn(&pdev->dev, "Final Firmware Download step timed out.");
3368bd5741eSChristian Lamparter 
3378bd5741eSChristian Lamparter 	/*
3388bd5741eSChristian Lamparter 	 * 11. After finishing writing the last data of FW, the
3398bd5741eSChristian Lamparter 	 * System Software must clear "FW Download Enable"
3408bd5741eSChristian Lamparter 	 */
3418bd5741eSChristian Lamparter 	err = pci_write_config_byte(pdev, RENESAS_FW_STATUS, 0);
3428bd5741eSChristian Lamparter 	if (err)
3438bd5741eSChristian Lamparter 		return pcibios_err_to_errno(err);
3448bd5741eSChristian Lamparter 
3458bd5741eSChristian Lamparter 	/* 12. Read "Result Code" and confirm it is good. */
3468bd5741eSChristian Lamparter 	for (i = 0; i < RENESAS_RETRY; i++) {
3478bd5741eSChristian Lamparter 		err = pci_read_config_byte(pdev, RENESAS_FW_STATUS, &fw_status);
3488bd5741eSChristian Lamparter 		if (err)
3498bd5741eSChristian Lamparter 			return pcibios_err_to_errno(err);
3508bd5741eSChristian Lamparter 		if (fw_status & RENESAS_FW_STATUS_SUCCESS)
3518bd5741eSChristian Lamparter 			break;
3528bd5741eSChristian Lamparter 
3538bd5741eSChristian Lamparter 		udelay(RENESAS_DELAY);
3548bd5741eSChristian Lamparter 	}
3558bd5741eSChristian Lamparter 	if (i == RENESAS_RETRY) {
3568bd5741eSChristian Lamparter 		/* Timed out / Error - let's see if we can fix this */
3578bd5741eSChristian Lamparter 		err = renesas_fw_check_running(pdev);
3588bd5741eSChristian Lamparter 		switch (err) {
3598bd5741eSChristian Lamparter 		case 0: /*
3608bd5741eSChristian Lamparter 			 * we shouldn't end up here.
3618bd5741eSChristian Lamparter 			 * maybe it took a little bit longer.
3628bd5741eSChristian Lamparter 			 * But all should be well?
3638bd5741eSChristian Lamparter 			 */
3648bd5741eSChristian Lamparter 			break;
3658bd5741eSChristian Lamparter 
3668bd5741eSChristian Lamparter 		case 1: /* (No result yet! */
3678bd5741eSChristian Lamparter 			dev_err(&pdev->dev, "FW Load timedout");
3688bd5741eSChristian Lamparter 			return -ETIMEDOUT;
3698bd5741eSChristian Lamparter 
3708bd5741eSChristian Lamparter 		default:
3718bd5741eSChristian Lamparter 			return err;
3728bd5741eSChristian Lamparter 		}
3738bd5741eSChristian Lamparter 	}
3748bd5741eSChristian Lamparter 
3758bd5741eSChristian Lamparter 	return 0;
3768bd5741eSChristian Lamparter }
3778bd5741eSChristian Lamparter 
renesas_rom_erase(struct pci_dev * pdev)3782478be82SVinod Koul static void renesas_rom_erase(struct pci_dev *pdev)
3792478be82SVinod Koul {
3802478be82SVinod Koul 	int retval, i;
3812478be82SVinod Koul 	u8 status;
3822478be82SVinod Koul 
3832478be82SVinod Koul 	dev_dbg(&pdev->dev, "Performing ROM Erase...\n");
3842478be82SVinod Koul 	retval = pci_write_config_dword(pdev, RENESAS_DATA0,
3852478be82SVinod Koul 					RENESAS_ROM_ERASE_MAGIC);
3862478be82SVinod Koul 	if (retval) {
3872478be82SVinod Koul 		dev_err(&pdev->dev, "ROM erase, magic word write failed: %d\n",
3882478be82SVinod Koul 			pcibios_err_to_errno(retval));
3892478be82SVinod Koul 		return;
3902478be82SVinod Koul 	}
3912478be82SVinod Koul 
3922478be82SVinod Koul 	retval = pci_read_config_byte(pdev, RENESAS_ROM_STATUS, &status);
3932478be82SVinod Koul 	if (retval) {
3942478be82SVinod Koul 		dev_err(&pdev->dev, "ROM status read failed: %d\n",
3952478be82SVinod Koul 			pcibios_err_to_errno(retval));
3962478be82SVinod Koul 		return;
3972478be82SVinod Koul 	}
3982478be82SVinod Koul 	status |= RENESAS_ROM_STATUS_ERASE;
3992478be82SVinod Koul 	retval = pci_write_config_byte(pdev, RENESAS_ROM_STATUS, status);
4002478be82SVinod Koul 	if (retval) {
4012478be82SVinod Koul 		dev_err(&pdev->dev, "ROM erase set word write failed\n");
4022478be82SVinod Koul 		return;
4032478be82SVinod Koul 	}
4042478be82SVinod Koul 
4052478be82SVinod Koul 	/* sleep a bit while ROM is erased */
4062478be82SVinod Koul 	msleep(20);
4072478be82SVinod Koul 
4082478be82SVinod Koul 	for (i = 0; i < RENESAS_RETRY; i++) {
4092478be82SVinod Koul 		retval = pci_read_config_byte(pdev, RENESAS_ROM_STATUS,
4102478be82SVinod Koul 					      &status);
4112478be82SVinod Koul 		status &= RENESAS_ROM_STATUS_ERASE;
4122478be82SVinod Koul 		if (!status)
4132478be82SVinod Koul 			break;
4142478be82SVinod Koul 
4152478be82SVinod Koul 		mdelay(RENESAS_DELAY);
4162478be82SVinod Koul 	}
4172478be82SVinod Koul 
4182478be82SVinod Koul 	if (i == RENESAS_RETRY)
4192478be82SVinod Koul 		dev_dbg(&pdev->dev, "Chip erase timedout: %x\n", status);
4202478be82SVinod Koul 
4212478be82SVinod Koul 	dev_dbg(&pdev->dev, "ROM Erase... Done success\n");
4222478be82SVinod Koul }
4232478be82SVinod Koul 
renesas_setup_rom(struct pci_dev * pdev,const struct firmware * fw)4242478be82SVinod Koul static bool renesas_setup_rom(struct pci_dev *pdev, const struct firmware *fw)
4252478be82SVinod Koul {
4262478be82SVinod Koul 	const u32 *fw_data = (const u32 *)fw->data;
4272478be82SVinod Koul 	int err, i;
4282478be82SVinod Koul 	u8 status;
4292478be82SVinod Koul 
4302478be82SVinod Koul 	/* 2. Write magic word to Data0 */
4312478be82SVinod Koul 	err = pci_write_config_dword(pdev, RENESAS_DATA0,
4322478be82SVinod Koul 				     RENESAS_ROM_WRITE_MAGIC);
4332478be82SVinod Koul 	if (err)
4342478be82SVinod Koul 		return false;
4352478be82SVinod Koul 
4362478be82SVinod Koul 	/* 3. Set External ROM access */
4372478be82SVinod Koul 	err = pci_write_config_byte(pdev, RENESAS_ROM_STATUS,
4382478be82SVinod Koul 				    RENESAS_ROM_STATUS_ACCESS);
4392478be82SVinod Koul 	if (err)
4402478be82SVinod Koul 		goto remove_bypass;
4412478be82SVinod Koul 
4422478be82SVinod Koul 	/* 4. Check the result */
4432478be82SVinod Koul 	err = pci_read_config_byte(pdev, RENESAS_ROM_STATUS, &status);
4442478be82SVinod Koul 	if (err)
4452478be82SVinod Koul 		goto remove_bypass;
4462478be82SVinod Koul 	status &= GENMASK(6, 4);
4472478be82SVinod Koul 	if (status) {
4482478be82SVinod Koul 		dev_err(&pdev->dev,
4492478be82SVinod Koul 			"setting external rom failed: %x\n", status);
4502478be82SVinod Koul 		goto remove_bypass;
4512478be82SVinod Koul 	}
4522478be82SVinod Koul 
4532478be82SVinod Koul 	/* 5 to 16 Write FW to DATA0/1 while checking SetData0/1 */
4542478be82SVinod Koul 	for (i = 0; i < fw->size / 4; i++) {
4552478be82SVinod Koul 		err = renesas_fw_download_image(pdev, fw_data, i, true);
4562478be82SVinod Koul 		if (err) {
4572478be82SVinod Koul 			dev_err(&pdev->dev,
4582478be82SVinod Koul 				"ROM Download Step %d failed at position %d bytes with (%d)\n",
4592478be82SVinod Koul 				 i, i * 4, err);
4602478be82SVinod Koul 			goto remove_bypass;
4612478be82SVinod Koul 		}
4622478be82SVinod Koul 	}
4632478be82SVinod Koul 
4642478be82SVinod Koul 	/*
4652478be82SVinod Koul 	 * wait till DATA0/1 is cleared
4662478be82SVinod Koul 	 */
4672478be82SVinod Koul 	for (i = 0; i < RENESAS_RETRY; i++) {
4682478be82SVinod Koul 		err = pci_read_config_byte(pdev, RENESAS_ROM_STATUS_MSB,
4692478be82SVinod Koul 					   &status);
4702478be82SVinod Koul 		if (err)
4712478be82SVinod Koul 			goto remove_bypass;
4722478be82SVinod Koul 		if (!(status & (BIT(0) | BIT(1))))
4732478be82SVinod Koul 			break;
4742478be82SVinod Koul 
4752478be82SVinod Koul 		udelay(RENESAS_DELAY);
4762478be82SVinod Koul 	}
4772478be82SVinod Koul 	if (i == RENESAS_RETRY) {
4782478be82SVinod Koul 		dev_err(&pdev->dev, "Final Firmware ROM Download step timed out\n");
4792478be82SVinod Koul 		goto remove_bypass;
4802478be82SVinod Koul 	}
4812478be82SVinod Koul 
4822478be82SVinod Koul 	/* 17. Remove bypass */
4832478be82SVinod Koul 	err = pci_write_config_byte(pdev, RENESAS_ROM_STATUS, 0);
4842478be82SVinod Koul 	if (err)
4852478be82SVinod Koul 		return false;
4862478be82SVinod Koul 
4872478be82SVinod Koul 	udelay(10);
4882478be82SVinod Koul 
4892478be82SVinod Koul 	/* 18. check result */
4902478be82SVinod Koul 	for (i = 0; i < RENESAS_RETRY; i++) {
4912478be82SVinod Koul 		err = pci_read_config_byte(pdev, RENESAS_ROM_STATUS, &status);
4922478be82SVinod Koul 		if (err) {
4932478be82SVinod Koul 			dev_err(&pdev->dev, "Read ROM status failed:%d\n",
4942478be82SVinod Koul 				pcibios_err_to_errno(err));
4952478be82SVinod Koul 			return false;
4962478be82SVinod Koul 		}
4972478be82SVinod Koul 		status &= RENESAS_ROM_STATUS_RESULT;
4982478be82SVinod Koul 		if (status ==  RENESAS_ROM_STATUS_SUCCESS) {
4992478be82SVinod Koul 			dev_dbg(&pdev->dev, "Download ROM success\n");
5002478be82SVinod Koul 			break;
5012478be82SVinod Koul 		}
5022478be82SVinod Koul 		udelay(RENESAS_DELAY);
5032478be82SVinod Koul 	}
5042478be82SVinod Koul 	if (i == RENESAS_RETRY) { /* Timed out */
5052478be82SVinod Koul 		dev_err(&pdev->dev,
5062478be82SVinod Koul 			"Download to external ROM TO: %x\n", status);
5072478be82SVinod Koul 		return false;
5082478be82SVinod Koul 	}
5092478be82SVinod Koul 
5102478be82SVinod Koul 	dev_dbg(&pdev->dev, "Download to external ROM succeeded\n");
5112478be82SVinod Koul 
5122478be82SVinod Koul 	/* Last step set Reload */
5132478be82SVinod Koul 	err = pci_write_config_byte(pdev, RENESAS_ROM_STATUS,
5142478be82SVinod Koul 				    RENESAS_ROM_STATUS_RELOAD);
5152478be82SVinod Koul 	if (err) {
5162478be82SVinod Koul 		dev_err(&pdev->dev, "Set ROM execute failed: %d\n",
5172478be82SVinod Koul 			pcibios_err_to_errno(err));
5182478be82SVinod Koul 		return false;
5192478be82SVinod Koul 	}
5202478be82SVinod Koul 
5212478be82SVinod Koul 	/*
5222478be82SVinod Koul 	 * wait till Reload is cleared
5232478be82SVinod Koul 	 */
5242478be82SVinod Koul 	for (i = 0; i < RENESAS_RETRY; i++) {
5252478be82SVinod Koul 		err = pci_read_config_byte(pdev, RENESAS_ROM_STATUS, &status);
5262478be82SVinod Koul 		if (err)
5272478be82SVinod Koul 			return false;
5282478be82SVinod Koul 		if (!(status & RENESAS_ROM_STATUS_RELOAD))
5292478be82SVinod Koul 			break;
5302478be82SVinod Koul 
5312478be82SVinod Koul 		udelay(RENESAS_DELAY);
5322478be82SVinod Koul 	}
5332478be82SVinod Koul 	if (i == RENESAS_RETRY) {
5342478be82SVinod Koul 		dev_err(&pdev->dev, "ROM Exec timed out: %x\n", status);
5352478be82SVinod Koul 		return false;
5362478be82SVinod Koul 	}
5372478be82SVinod Koul 
5382478be82SVinod Koul 	return true;
5392478be82SVinod Koul 
5402478be82SVinod Koul remove_bypass:
5412478be82SVinod Koul 	pci_write_config_byte(pdev, RENESAS_ROM_STATUS, 0);
5422478be82SVinod Koul 	return false;
5432478be82SVinod Koul }
5442478be82SVinod Koul 
renesas_load_fw(struct pci_dev * pdev,const struct firmware * fw)5458bd5741eSChristian Lamparter static int renesas_load_fw(struct pci_dev *pdev, const struct firmware *fw)
5468bd5741eSChristian Lamparter {
5478bd5741eSChristian Lamparter 	int err = 0;
5482478be82SVinod Koul 	bool rom;
5492478be82SVinod Koul 
5502478be82SVinod Koul 	/* Check if the device has external ROM */
5512478be82SVinod Koul 	rom = renesas_check_rom(pdev);
5522478be82SVinod Koul 	if (rom) {
5532478be82SVinod Koul 		/* perform chip erase first */
5542478be82SVinod Koul 		renesas_rom_erase(pdev);
5552478be82SVinod Koul 
5562478be82SVinod Koul 		/* lets try loading fw on ROM first */
5572478be82SVinod Koul 		rom = renesas_setup_rom(pdev, fw);
5582478be82SVinod Koul 		if (!rom) {
5592478be82SVinod Koul 			dev_dbg(&pdev->dev,
5602478be82SVinod Koul 				"ROM load failed, falling back on FW load\n");
5612478be82SVinod Koul 		} else {
5622478be82SVinod Koul 			dev_dbg(&pdev->dev,
5632478be82SVinod Koul 				"ROM load success\n");
5642478be82SVinod Koul 			goto exit;
5652478be82SVinod Koul 		}
5662478be82SVinod Koul 	}
5678bd5741eSChristian Lamparter 
5688bd5741eSChristian Lamparter 	err = renesas_fw_download(pdev, fw);
5692478be82SVinod Koul 
5702478be82SVinod Koul exit:
5718bd5741eSChristian Lamparter 	if (err)
5728bd5741eSChristian Lamparter 		dev_err(&pdev->dev, "firmware failed to download (%d).", err);
5738bd5741eSChristian Lamparter 	return err;
5748bd5741eSChristian Lamparter }
5758bd5741eSChristian Lamparter 
renesas_xhci_check_request_fw(struct pci_dev * pdev,const struct pci_device_id * id)5768bd5741eSChristian Lamparter int renesas_xhci_check_request_fw(struct pci_dev *pdev,
5778bd5741eSChristian Lamparter 				  const struct pci_device_id *id)
5788bd5741eSChristian Lamparter {
5798bd5741eSChristian Lamparter 	struct xhci_driver_data *driver_data =
5808bd5741eSChristian Lamparter 			(struct xhci_driver_data *)id->driver_data;
5818bd5741eSChristian Lamparter 	const char *fw_name = driver_data->firmware;
5828bd5741eSChristian Lamparter 	const struct firmware *fw;
583*c82cacd2STakashi Iwai 	bool has_rom;
5848bd5741eSChristian Lamparter 	int err;
5858bd5741eSChristian Lamparter 
586*c82cacd2STakashi Iwai 	/* Check if device has ROM and loaded, if so skip everything */
587*c82cacd2STakashi Iwai 	has_rom = renesas_check_rom(pdev);
588*c82cacd2STakashi Iwai 	if (has_rom) {
589*c82cacd2STakashi Iwai 		err = renesas_check_rom_state(pdev);
590*c82cacd2STakashi Iwai 		if (!err)
591*c82cacd2STakashi Iwai 			return 0;
592*c82cacd2STakashi Iwai 		else if (err != -ENOENT)
593*c82cacd2STakashi Iwai 			has_rom = false;
594*c82cacd2STakashi Iwai 	}
595*c82cacd2STakashi Iwai 
5968bd5741eSChristian Lamparter 	err = renesas_fw_check_running(pdev);
5978bd5741eSChristian Lamparter 	/* Continue ahead, if the firmware is already running. */
598e13690d5SMoritz Fischer 	if (!err)
5998bd5741eSChristian Lamparter 		return 0;
6008bd5741eSChristian Lamparter 
601*c82cacd2STakashi Iwai 	/* no firmware interface available */
6028bd5741eSChristian Lamparter 	if (err != 1)
603*c82cacd2STakashi Iwai 		return has_rom ? 0 : err;
6048bd5741eSChristian Lamparter 
6058bd5741eSChristian Lamparter 	pci_dev_get(pdev);
606*c82cacd2STakashi Iwai 	err = firmware_request_nowarn(&fw, fw_name, &pdev->dev);
6078bd5741eSChristian Lamparter 	pci_dev_put(pdev);
6088bd5741eSChristian Lamparter 	if (err) {
609*c82cacd2STakashi Iwai 		if (has_rom) {
610*c82cacd2STakashi Iwai 			dev_info(&pdev->dev, "failed to load firmware %s, fallback to ROM\n",
611*c82cacd2STakashi Iwai 				 fw_name);
612*c82cacd2STakashi Iwai 			return 0;
613*c82cacd2STakashi Iwai 		}
614*c82cacd2STakashi Iwai 		dev_err(&pdev->dev, "failed to load firmware %s: %d\n",
615*c82cacd2STakashi Iwai 			fw_name, err);
6168bd5741eSChristian Lamparter 		return err;
6178bd5741eSChristian Lamparter 	}
6188bd5741eSChristian Lamparter 
6198bd5741eSChristian Lamparter 	err = renesas_fw_verify(fw->data, fw->size);
6208bd5741eSChristian Lamparter 	if (err)
6218bd5741eSChristian Lamparter 		goto exit;
6228bd5741eSChristian Lamparter 
6238bd5741eSChristian Lamparter 	err = renesas_load_fw(pdev, fw);
6248bd5741eSChristian Lamparter exit:
6258bd5741eSChristian Lamparter 	release_firmware(fw);
6268bd5741eSChristian Lamparter 	return err;
6278bd5741eSChristian Lamparter }
6288bd5741eSChristian Lamparter EXPORT_SYMBOL_GPL(renesas_xhci_check_request_fw);
6298bd5741eSChristian Lamparter 
6308bd5741eSChristian Lamparter MODULE_LICENSE("GPL v2");
631