18c2ecf20Sopenharmony_ci/*****************************************************************************
28c2ecf20Sopenharmony_ci *
38c2ecf20Sopenharmony_ci *     Author: Xilinx, Inc.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci *     This program is free software; you can redistribute it and/or modify it
68c2ecf20Sopenharmony_ci *     under the terms of the GNU General Public License as published by the
78c2ecf20Sopenharmony_ci *     Free Software Foundation; either version 2 of the License, or (at your
88c2ecf20Sopenharmony_ci *     option) any later version.
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci *     XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS"
118c2ecf20Sopenharmony_ci *     AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND
128c2ecf20Sopenharmony_ci *     SOLUTIONS FOR XILINX DEVICES.  BY PROVIDING THIS DESIGN, CODE,
138c2ecf20Sopenharmony_ci *     OR INFORMATION AS ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE,
148c2ecf20Sopenharmony_ci *     APPLICATION OR STANDARD, XILINX IS MAKING NO REPRESENTATION
158c2ecf20Sopenharmony_ci *     THAT THIS IMPLEMENTATION IS FREE FROM ANY CLAIMS OF INFRINGEMENT,
168c2ecf20Sopenharmony_ci *     AND YOU ARE RESPONSIBLE FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE
178c2ecf20Sopenharmony_ci *     FOR YOUR IMPLEMENTATION.  XILINX EXPRESSLY DISCLAIMS ANY
188c2ecf20Sopenharmony_ci *     WARRANTY WHATSOEVER WITH RESPECT TO THE ADEQUACY OF THE
198c2ecf20Sopenharmony_ci *     IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OR
208c2ecf20Sopenharmony_ci *     REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE FROM CLAIMS OF
218c2ecf20Sopenharmony_ci *     INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
228c2ecf20Sopenharmony_ci *     FOR A PARTICULAR PURPOSE.
238c2ecf20Sopenharmony_ci *
248c2ecf20Sopenharmony_ci *     (c) Copyright 2007-2008 Xilinx Inc.
258c2ecf20Sopenharmony_ci *     All rights reserved.
268c2ecf20Sopenharmony_ci *
278c2ecf20Sopenharmony_ci *     You should have received a copy of the GNU General Public License along
288c2ecf20Sopenharmony_ci *     with this program; if not, write to the Free Software Foundation, Inc.,
298c2ecf20Sopenharmony_ci *     675 Mass Ave, Cambridge, MA 02139, USA.
308c2ecf20Sopenharmony_ci *
318c2ecf20Sopenharmony_ci *****************************************************************************/
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci#include "fifo_icap.h"
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci/* Register offsets for the XHwIcap device. */
368c2ecf20Sopenharmony_ci#define XHI_GIER_OFFSET	0x1C  /* Device Global Interrupt Enable Reg */
378c2ecf20Sopenharmony_ci#define XHI_IPISR_OFFSET 0x20  /* Interrupt Status Register */
388c2ecf20Sopenharmony_ci#define XHI_IPIER_OFFSET 0x28  /* Interrupt Enable Register */
398c2ecf20Sopenharmony_ci#define XHI_WF_OFFSET 0x100 /* Write FIFO */
408c2ecf20Sopenharmony_ci#define XHI_RF_OFFSET 0x104 /* Read FIFO */
418c2ecf20Sopenharmony_ci#define XHI_SZ_OFFSET 0x108 /* Size Register */
428c2ecf20Sopenharmony_ci#define XHI_CR_OFFSET 0x10C /* Control Register */
438c2ecf20Sopenharmony_ci#define XHI_SR_OFFSET 0x110 /* Status Register */
448c2ecf20Sopenharmony_ci#define XHI_WFV_OFFSET 0x114 /* Write FIFO Vacancy Register */
458c2ecf20Sopenharmony_ci#define XHI_RFO_OFFSET 0x118 /* Read FIFO Occupancy Register */
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci/* Device Global Interrupt Enable Register (GIER) bit definitions */
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci#define XHI_GIER_GIE_MASK 0x80000000 /* Global Interrupt enable Mask */
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci/**
528c2ecf20Sopenharmony_ci * HwIcap Device Interrupt Status/Enable Registers
538c2ecf20Sopenharmony_ci *
548c2ecf20Sopenharmony_ci * Interrupt Status Register (IPISR) : This register holds the
558c2ecf20Sopenharmony_ci * interrupt status flags for the device. These bits are toggle on
568c2ecf20Sopenharmony_ci * write.
578c2ecf20Sopenharmony_ci *
588c2ecf20Sopenharmony_ci * Interrupt Enable Register (IPIER) : This register is used to enable
598c2ecf20Sopenharmony_ci * interrupt sources for the device.
608c2ecf20Sopenharmony_ci * Writing a '1' to a bit enables the corresponding interrupt.
618c2ecf20Sopenharmony_ci * Writing a '0' to a bit disables the corresponding interrupt.
628c2ecf20Sopenharmony_ci *
638c2ecf20Sopenharmony_ci * IPISR/IPIER registers have the same bit definitions and are only defined
648c2ecf20Sopenharmony_ci * once.
658c2ecf20Sopenharmony_ci */
668c2ecf20Sopenharmony_ci#define XHI_IPIXR_RFULL_MASK 0x00000008 /* Read FIFO Full */
678c2ecf20Sopenharmony_ci#define XHI_IPIXR_WEMPTY_MASK 0x00000004 /* Write FIFO Empty */
688c2ecf20Sopenharmony_ci#define XHI_IPIXR_RDP_MASK 0x00000002 /* Read FIFO half full */
698c2ecf20Sopenharmony_ci#define XHI_IPIXR_WRP_MASK 0x00000001 /* Write FIFO half full */
708c2ecf20Sopenharmony_ci#define XHI_IPIXR_ALL_MASK 0x0000000F /* Mask of all interrupts */
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci/* Control Register (CR) */
738c2ecf20Sopenharmony_ci#define XHI_CR_SW_RESET_MASK 0x00000008 /* SW Reset Mask */
748c2ecf20Sopenharmony_ci#define XHI_CR_FIFO_CLR_MASK 0x00000004 /* FIFO Clear Mask */
758c2ecf20Sopenharmony_ci#define XHI_CR_READ_MASK 0x00000002 /* Read from ICAP to FIFO */
768c2ecf20Sopenharmony_ci#define XHI_CR_WRITE_MASK 0x00000001 /* Write from FIFO to ICAP */
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci#define XHI_WFO_MAX_VACANCY 1024 /* Max Write FIFO Vacancy, in words */
808c2ecf20Sopenharmony_ci#define XHI_RFO_MAX_OCCUPANCY 256 /* Max Read FIFO Occupancy, in words */
818c2ecf20Sopenharmony_ci/* The maximum amount we can request from fifo_icap_get_configuration
828c2ecf20Sopenharmony_ci   at once, in bytes. */
838c2ecf20Sopenharmony_ci#define XHI_MAX_READ_TRANSACTION_WORDS 0xFFF
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci/**
878c2ecf20Sopenharmony_ci * fifo_icap_fifo_write - Write data to the write FIFO.
888c2ecf20Sopenharmony_ci * @drvdata: a pointer to the drvdata.
898c2ecf20Sopenharmony_ci * @data: the 32-bit value to be written to the FIFO.
908c2ecf20Sopenharmony_ci *
918c2ecf20Sopenharmony_ci * This function will silently fail if the fifo is full.
928c2ecf20Sopenharmony_ci **/
938c2ecf20Sopenharmony_cistatic inline void fifo_icap_fifo_write(struct hwicap_drvdata *drvdata,
948c2ecf20Sopenharmony_ci		u32 data)
958c2ecf20Sopenharmony_ci{
968c2ecf20Sopenharmony_ci	dev_dbg(drvdata->dev, "fifo_write: %x\n", data);
978c2ecf20Sopenharmony_ci	out_be32(drvdata->base_address + XHI_WF_OFFSET, data);
988c2ecf20Sopenharmony_ci}
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci/**
1018c2ecf20Sopenharmony_ci * fifo_icap_fifo_read - Read data from the Read FIFO.
1028c2ecf20Sopenharmony_ci * @drvdata: a pointer to the drvdata.
1038c2ecf20Sopenharmony_ci *
1048c2ecf20Sopenharmony_ci * This function will silently fail if the fifo is empty.
1058c2ecf20Sopenharmony_ci **/
1068c2ecf20Sopenharmony_cistatic inline u32 fifo_icap_fifo_read(struct hwicap_drvdata *drvdata)
1078c2ecf20Sopenharmony_ci{
1088c2ecf20Sopenharmony_ci	u32 data = in_be32(drvdata->base_address + XHI_RF_OFFSET);
1098c2ecf20Sopenharmony_ci	dev_dbg(drvdata->dev, "fifo_read: %x\n", data);
1108c2ecf20Sopenharmony_ci	return data;
1118c2ecf20Sopenharmony_ci}
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci/**
1148c2ecf20Sopenharmony_ci * fifo_icap_set_read_size - Set the the size register.
1158c2ecf20Sopenharmony_ci * @drvdata: a pointer to the drvdata.
1168c2ecf20Sopenharmony_ci * @data: the size of the following read transaction, in words.
1178c2ecf20Sopenharmony_ci **/
1188c2ecf20Sopenharmony_cistatic inline void fifo_icap_set_read_size(struct hwicap_drvdata *drvdata,
1198c2ecf20Sopenharmony_ci		u32 data)
1208c2ecf20Sopenharmony_ci{
1218c2ecf20Sopenharmony_ci	out_be32(drvdata->base_address + XHI_SZ_OFFSET, data);
1228c2ecf20Sopenharmony_ci}
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci/**
1258c2ecf20Sopenharmony_ci * fifo_icap_start_config - Initiate a configuration (write) to the device.
1268c2ecf20Sopenharmony_ci * @drvdata: a pointer to the drvdata.
1278c2ecf20Sopenharmony_ci **/
1288c2ecf20Sopenharmony_cistatic inline void fifo_icap_start_config(struct hwicap_drvdata *drvdata)
1298c2ecf20Sopenharmony_ci{
1308c2ecf20Sopenharmony_ci	out_be32(drvdata->base_address + XHI_CR_OFFSET, XHI_CR_WRITE_MASK);
1318c2ecf20Sopenharmony_ci	dev_dbg(drvdata->dev, "configuration started\n");
1328c2ecf20Sopenharmony_ci}
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci/**
1358c2ecf20Sopenharmony_ci * fifo_icap_start_readback - Initiate a readback from the device.
1368c2ecf20Sopenharmony_ci * @drvdata: a pointer to the drvdata.
1378c2ecf20Sopenharmony_ci **/
1388c2ecf20Sopenharmony_cistatic inline void fifo_icap_start_readback(struct hwicap_drvdata *drvdata)
1398c2ecf20Sopenharmony_ci{
1408c2ecf20Sopenharmony_ci	out_be32(drvdata->base_address + XHI_CR_OFFSET, XHI_CR_READ_MASK);
1418c2ecf20Sopenharmony_ci	dev_dbg(drvdata->dev, "readback started\n");
1428c2ecf20Sopenharmony_ci}
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci/**
1458c2ecf20Sopenharmony_ci * fifo_icap_get_status - Get the contents of the status register.
1468c2ecf20Sopenharmony_ci * @drvdata: a pointer to the drvdata.
1478c2ecf20Sopenharmony_ci *
1488c2ecf20Sopenharmony_ci * The status register contains the ICAP status and the done bit.
1498c2ecf20Sopenharmony_ci *
1508c2ecf20Sopenharmony_ci * D8 - cfgerr
1518c2ecf20Sopenharmony_ci * D7 - dalign
1528c2ecf20Sopenharmony_ci * D6 - rip
1538c2ecf20Sopenharmony_ci * D5 - in_abort_l
1548c2ecf20Sopenharmony_ci * D4 - Always 1
1558c2ecf20Sopenharmony_ci * D3 - Always 1
1568c2ecf20Sopenharmony_ci * D2 - Always 1
1578c2ecf20Sopenharmony_ci * D1 - Always 1
1588c2ecf20Sopenharmony_ci * D0 - Done bit
1598c2ecf20Sopenharmony_ci **/
1608c2ecf20Sopenharmony_ciu32 fifo_icap_get_status(struct hwicap_drvdata *drvdata)
1618c2ecf20Sopenharmony_ci{
1628c2ecf20Sopenharmony_ci	u32 status = in_be32(drvdata->base_address + XHI_SR_OFFSET);
1638c2ecf20Sopenharmony_ci	dev_dbg(drvdata->dev, "Getting status = %x\n", status);
1648c2ecf20Sopenharmony_ci	return status;
1658c2ecf20Sopenharmony_ci}
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci/**
1688c2ecf20Sopenharmony_ci * fifo_icap_busy - Return true if the ICAP is still processing a transaction.
1698c2ecf20Sopenharmony_ci * @drvdata: a pointer to the drvdata.
1708c2ecf20Sopenharmony_ci **/
1718c2ecf20Sopenharmony_cistatic inline u32 fifo_icap_busy(struct hwicap_drvdata *drvdata)
1728c2ecf20Sopenharmony_ci{
1738c2ecf20Sopenharmony_ci	u32 status = in_be32(drvdata->base_address + XHI_SR_OFFSET);
1748c2ecf20Sopenharmony_ci	return (status & XHI_SR_DONE_MASK) ? 0 : 1;
1758c2ecf20Sopenharmony_ci}
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci/**
1788c2ecf20Sopenharmony_ci * fifo_icap_write_fifo_vacancy - Query the write fifo available space.
1798c2ecf20Sopenharmony_ci * @drvdata: a pointer to the drvdata.
1808c2ecf20Sopenharmony_ci *
1818c2ecf20Sopenharmony_ci * Return the number of words that can be safely pushed into the write fifo.
1828c2ecf20Sopenharmony_ci **/
1838c2ecf20Sopenharmony_cistatic inline u32 fifo_icap_write_fifo_vacancy(
1848c2ecf20Sopenharmony_ci		struct hwicap_drvdata *drvdata)
1858c2ecf20Sopenharmony_ci{
1868c2ecf20Sopenharmony_ci	return in_be32(drvdata->base_address + XHI_WFV_OFFSET);
1878c2ecf20Sopenharmony_ci}
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci/**
1908c2ecf20Sopenharmony_ci * fifo_icap_read_fifo_occupancy - Query the read fifo available data.
1918c2ecf20Sopenharmony_ci * @drvdata: a pointer to the drvdata.
1928c2ecf20Sopenharmony_ci *
1938c2ecf20Sopenharmony_ci * Return the number of words that can be safely read from the read fifo.
1948c2ecf20Sopenharmony_ci **/
1958c2ecf20Sopenharmony_cistatic inline u32 fifo_icap_read_fifo_occupancy(
1968c2ecf20Sopenharmony_ci		struct hwicap_drvdata *drvdata)
1978c2ecf20Sopenharmony_ci{
1988c2ecf20Sopenharmony_ci	return in_be32(drvdata->base_address + XHI_RFO_OFFSET);
1998c2ecf20Sopenharmony_ci}
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci/**
2028c2ecf20Sopenharmony_ci * fifo_icap_set_configuration - Send configuration data to the ICAP.
2038c2ecf20Sopenharmony_ci * @drvdata: a pointer to the drvdata.
2048c2ecf20Sopenharmony_ci * @frame_buffer: a pointer to the data to be written to the
2058c2ecf20Sopenharmony_ci *		ICAP device.
2068c2ecf20Sopenharmony_ci * @num_words: the number of words (32 bit) to write to the ICAP
2078c2ecf20Sopenharmony_ci *		device.
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci * This function writes the given user data to the Write FIFO in
2108c2ecf20Sopenharmony_ci * polled mode and starts the transfer of the data to
2118c2ecf20Sopenharmony_ci * the ICAP device.
2128c2ecf20Sopenharmony_ci **/
2138c2ecf20Sopenharmony_ciint fifo_icap_set_configuration(struct hwicap_drvdata *drvdata,
2148c2ecf20Sopenharmony_ci		u32 *frame_buffer, u32 num_words)
2158c2ecf20Sopenharmony_ci{
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci	u32 write_fifo_vacancy = 0;
2188c2ecf20Sopenharmony_ci	u32 retries = 0;
2198c2ecf20Sopenharmony_ci	u32 remaining_words;
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci	dev_dbg(drvdata->dev, "fifo_set_configuration\n");
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci	/*
2248c2ecf20Sopenharmony_ci	 * Check if the ICAP device is Busy with the last Read/Write
2258c2ecf20Sopenharmony_ci	 */
2268c2ecf20Sopenharmony_ci	if (fifo_icap_busy(drvdata))
2278c2ecf20Sopenharmony_ci		return -EBUSY;
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci	/*
2308c2ecf20Sopenharmony_ci	 * Set up the buffer pointer and the words to be transferred.
2318c2ecf20Sopenharmony_ci	 */
2328c2ecf20Sopenharmony_ci	remaining_words = num_words;
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci	while (remaining_words > 0) {
2358c2ecf20Sopenharmony_ci		/*
2368c2ecf20Sopenharmony_ci		 * Wait until we have some data in the fifo.
2378c2ecf20Sopenharmony_ci		 */
2388c2ecf20Sopenharmony_ci		while (write_fifo_vacancy == 0) {
2398c2ecf20Sopenharmony_ci			write_fifo_vacancy =
2408c2ecf20Sopenharmony_ci				fifo_icap_write_fifo_vacancy(drvdata);
2418c2ecf20Sopenharmony_ci			retries++;
2428c2ecf20Sopenharmony_ci			if (retries > XHI_MAX_RETRIES)
2438c2ecf20Sopenharmony_ci				return -EIO;
2448c2ecf20Sopenharmony_ci		}
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci		/*
2478c2ecf20Sopenharmony_ci		 * Write data into the Write FIFO.
2488c2ecf20Sopenharmony_ci		 */
2498c2ecf20Sopenharmony_ci		while ((write_fifo_vacancy != 0) &&
2508c2ecf20Sopenharmony_ci				(remaining_words > 0)) {
2518c2ecf20Sopenharmony_ci			fifo_icap_fifo_write(drvdata, *frame_buffer);
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci			remaining_words--;
2548c2ecf20Sopenharmony_ci			write_fifo_vacancy--;
2558c2ecf20Sopenharmony_ci			frame_buffer++;
2568c2ecf20Sopenharmony_ci		}
2578c2ecf20Sopenharmony_ci		/* Start pushing whatever is in the FIFO into the ICAP. */
2588c2ecf20Sopenharmony_ci		fifo_icap_start_config(drvdata);
2598c2ecf20Sopenharmony_ci	}
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci	/* Wait until the write has finished. */
2628c2ecf20Sopenharmony_ci	while (fifo_icap_busy(drvdata)) {
2638c2ecf20Sopenharmony_ci		retries++;
2648c2ecf20Sopenharmony_ci		if (retries > XHI_MAX_RETRIES)
2658c2ecf20Sopenharmony_ci			break;
2668c2ecf20Sopenharmony_ci	}
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci	dev_dbg(drvdata->dev, "done fifo_set_configuration\n");
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci	/*
2718c2ecf20Sopenharmony_ci	 * If the requested number of words have not been read from
2728c2ecf20Sopenharmony_ci	 * the device then indicate failure.
2738c2ecf20Sopenharmony_ci	 */
2748c2ecf20Sopenharmony_ci	if (remaining_words != 0)
2758c2ecf20Sopenharmony_ci		return -EIO;
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci	return 0;
2788c2ecf20Sopenharmony_ci}
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci/**
2818c2ecf20Sopenharmony_ci * fifo_icap_get_configuration - Read configuration data from the device.
2828c2ecf20Sopenharmony_ci * @drvdata: a pointer to the drvdata.
2838c2ecf20Sopenharmony_ci * @data: Address of the data representing the partial bitstream
2848c2ecf20Sopenharmony_ci * @size: the size of the partial bitstream in 32 bit words.
2858c2ecf20Sopenharmony_ci *
2868c2ecf20Sopenharmony_ci * This function reads the specified number of words from the ICAP device in
2878c2ecf20Sopenharmony_ci * the polled mode.
2888c2ecf20Sopenharmony_ci */
2898c2ecf20Sopenharmony_ciint fifo_icap_get_configuration(struct hwicap_drvdata *drvdata,
2908c2ecf20Sopenharmony_ci		u32 *frame_buffer, u32 num_words)
2918c2ecf20Sopenharmony_ci{
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci	u32 read_fifo_occupancy = 0;
2948c2ecf20Sopenharmony_ci	u32 retries = 0;
2958c2ecf20Sopenharmony_ci	u32 *data = frame_buffer;
2968c2ecf20Sopenharmony_ci	u32 remaining_words;
2978c2ecf20Sopenharmony_ci	u32 words_to_read;
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci	dev_dbg(drvdata->dev, "fifo_get_configuration\n");
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci	/*
3028c2ecf20Sopenharmony_ci	 * Check if the ICAP device is Busy with the last Write/Read
3038c2ecf20Sopenharmony_ci	 */
3048c2ecf20Sopenharmony_ci	if (fifo_icap_busy(drvdata))
3058c2ecf20Sopenharmony_ci		return -EBUSY;
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci	remaining_words = num_words;
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci	while (remaining_words > 0) {
3108c2ecf20Sopenharmony_ci		words_to_read = remaining_words;
3118c2ecf20Sopenharmony_ci		/* The hardware has a limit on the number of words
3128c2ecf20Sopenharmony_ci		   that can be read at one time.  */
3138c2ecf20Sopenharmony_ci		if (words_to_read > XHI_MAX_READ_TRANSACTION_WORDS)
3148c2ecf20Sopenharmony_ci			words_to_read = XHI_MAX_READ_TRANSACTION_WORDS;
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci		remaining_words -= words_to_read;
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci		fifo_icap_set_read_size(drvdata, words_to_read);
3198c2ecf20Sopenharmony_ci		fifo_icap_start_readback(drvdata);
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci		while (words_to_read > 0) {
3228c2ecf20Sopenharmony_ci			/* Wait until we have some data in the fifo. */
3238c2ecf20Sopenharmony_ci			while (read_fifo_occupancy == 0) {
3248c2ecf20Sopenharmony_ci				read_fifo_occupancy =
3258c2ecf20Sopenharmony_ci					fifo_icap_read_fifo_occupancy(drvdata);
3268c2ecf20Sopenharmony_ci				retries++;
3278c2ecf20Sopenharmony_ci				if (retries > XHI_MAX_RETRIES)
3288c2ecf20Sopenharmony_ci					return -EIO;
3298c2ecf20Sopenharmony_ci			}
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci			if (read_fifo_occupancy > words_to_read)
3328c2ecf20Sopenharmony_ci				read_fifo_occupancy = words_to_read;
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci			words_to_read -= read_fifo_occupancy;
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ci			/* Read the data from the Read FIFO. */
3378c2ecf20Sopenharmony_ci			while (read_fifo_occupancy != 0) {
3388c2ecf20Sopenharmony_ci				*data++ = fifo_icap_fifo_read(drvdata);
3398c2ecf20Sopenharmony_ci				read_fifo_occupancy--;
3408c2ecf20Sopenharmony_ci			}
3418c2ecf20Sopenharmony_ci		}
3428c2ecf20Sopenharmony_ci	}
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ci	dev_dbg(drvdata->dev, "done fifo_get_configuration\n");
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci	return 0;
3478c2ecf20Sopenharmony_ci}
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci/**
3508c2ecf20Sopenharmony_ci * buffer_icap_reset - Reset the logic of the icap device.
3518c2ecf20Sopenharmony_ci * @drvdata: a pointer to the drvdata.
3528c2ecf20Sopenharmony_ci *
3538c2ecf20Sopenharmony_ci * This function forces the software reset of the complete HWICAP device.
3548c2ecf20Sopenharmony_ci * All the registers will return to the default value and the FIFO is also
3558c2ecf20Sopenharmony_ci * flushed as a part of this software reset.
3568c2ecf20Sopenharmony_ci */
3578c2ecf20Sopenharmony_civoid fifo_icap_reset(struct hwicap_drvdata *drvdata)
3588c2ecf20Sopenharmony_ci{
3598c2ecf20Sopenharmony_ci	u32 reg_data;
3608c2ecf20Sopenharmony_ci	/*
3618c2ecf20Sopenharmony_ci	 * Reset the device by setting/clearing the RESET bit in the
3628c2ecf20Sopenharmony_ci	 * Control Register.
3638c2ecf20Sopenharmony_ci	 */
3648c2ecf20Sopenharmony_ci	reg_data = in_be32(drvdata->base_address + XHI_CR_OFFSET);
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci	out_be32(drvdata->base_address + XHI_CR_OFFSET,
3678c2ecf20Sopenharmony_ci				reg_data | XHI_CR_SW_RESET_MASK);
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci	out_be32(drvdata->base_address + XHI_CR_OFFSET,
3708c2ecf20Sopenharmony_ci				reg_data & (~XHI_CR_SW_RESET_MASK));
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_ci}
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci/**
3758c2ecf20Sopenharmony_ci * fifo_icap_flush_fifo - This function flushes the FIFOs in the device.
3768c2ecf20Sopenharmony_ci * @drvdata: a pointer to the drvdata.
3778c2ecf20Sopenharmony_ci */
3788c2ecf20Sopenharmony_civoid fifo_icap_flush_fifo(struct hwicap_drvdata *drvdata)
3798c2ecf20Sopenharmony_ci{
3808c2ecf20Sopenharmony_ci	u32 reg_data;
3818c2ecf20Sopenharmony_ci	/*
3828c2ecf20Sopenharmony_ci	 * Flush the FIFO by setting/clearing the FIFO Clear bit in the
3838c2ecf20Sopenharmony_ci	 * Control Register.
3848c2ecf20Sopenharmony_ci	 */
3858c2ecf20Sopenharmony_ci	reg_data = in_be32(drvdata->base_address + XHI_CR_OFFSET);
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci	out_be32(drvdata->base_address + XHI_CR_OFFSET,
3888c2ecf20Sopenharmony_ci				reg_data | XHI_CR_FIFO_CLR_MASK);
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ci	out_be32(drvdata->base_address + XHI_CR_OFFSET,
3918c2ecf20Sopenharmony_ci				reg_data & (~XHI_CR_FIFO_CLR_MASK));
3928c2ecf20Sopenharmony_ci}
3938c2ecf20Sopenharmony_ci
394