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 2003-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 "buffer_icap.h" 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci/* Indicates how many bytes will fit in a buffer. (1 BRAM) */ 368c2ecf20Sopenharmony_ci#define XHI_MAX_BUFFER_BYTES 2048 378c2ecf20Sopenharmony_ci#define XHI_MAX_BUFFER_INTS (XHI_MAX_BUFFER_BYTES >> 2) 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci/* File access and error constants */ 408c2ecf20Sopenharmony_ci#define XHI_DEVICE_READ_ERROR -1 418c2ecf20Sopenharmony_ci#define XHI_DEVICE_WRITE_ERROR -2 428c2ecf20Sopenharmony_ci#define XHI_BUFFER_OVERFLOW_ERROR -3 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci#define XHI_DEVICE_READ 0x1 458c2ecf20Sopenharmony_ci#define XHI_DEVICE_WRITE 0x0 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci/* Constants for checking transfer status */ 488c2ecf20Sopenharmony_ci#define XHI_CYCLE_DONE 0 498c2ecf20Sopenharmony_ci#define XHI_CYCLE_EXECUTING 1 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci/* buffer_icap register offsets */ 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci/* Size of transfer, read & write */ 548c2ecf20Sopenharmony_ci#define XHI_SIZE_REG_OFFSET 0x800L 558c2ecf20Sopenharmony_ci/* offset into bram, read & write */ 568c2ecf20Sopenharmony_ci#define XHI_BRAM_OFFSET_REG_OFFSET 0x804L 578c2ecf20Sopenharmony_ci/* Read not Configure, direction of transfer. Write only */ 588c2ecf20Sopenharmony_ci#define XHI_RNC_REG_OFFSET 0x808L 598c2ecf20Sopenharmony_ci/* Indicates transfer complete. Read only */ 608c2ecf20Sopenharmony_ci#define XHI_STATUS_REG_OFFSET 0x80CL 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci/* Constants for setting the RNC register */ 638c2ecf20Sopenharmony_ci#define XHI_CONFIGURE 0x0UL 648c2ecf20Sopenharmony_ci#define XHI_READBACK 0x1UL 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci/* Constants for the Done register */ 678c2ecf20Sopenharmony_ci#define XHI_NOT_FINISHED 0x0UL 688c2ecf20Sopenharmony_ci#define XHI_FINISHED 0x1UL 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci#define XHI_BUFFER_START 0 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci/** 738c2ecf20Sopenharmony_ci * buffer_icap_get_status - Get the contents of the status register. 748c2ecf20Sopenharmony_ci * @drvdata: a pointer to the drvdata. 758c2ecf20Sopenharmony_ci * 768c2ecf20Sopenharmony_ci * The status register contains the ICAP status and the done bit. 778c2ecf20Sopenharmony_ci * 788c2ecf20Sopenharmony_ci * D8 - cfgerr 798c2ecf20Sopenharmony_ci * D7 - dalign 808c2ecf20Sopenharmony_ci * D6 - rip 818c2ecf20Sopenharmony_ci * D5 - in_abort_l 828c2ecf20Sopenharmony_ci * D4 - Always 1 838c2ecf20Sopenharmony_ci * D3 - Always 1 848c2ecf20Sopenharmony_ci * D2 - Always 1 858c2ecf20Sopenharmony_ci * D1 - Always 1 868c2ecf20Sopenharmony_ci * D0 - Done bit 878c2ecf20Sopenharmony_ci **/ 888c2ecf20Sopenharmony_ciu32 buffer_icap_get_status(struct hwicap_drvdata *drvdata) 898c2ecf20Sopenharmony_ci{ 908c2ecf20Sopenharmony_ci return in_be32(drvdata->base_address + XHI_STATUS_REG_OFFSET); 918c2ecf20Sopenharmony_ci} 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci/** 948c2ecf20Sopenharmony_ci * buffer_icap_get_bram - Reads data from the storage buffer bram. 958c2ecf20Sopenharmony_ci * @base_address: contains the base address of the component. 968c2ecf20Sopenharmony_ci * @offset: The word offset from which the data should be read. 978c2ecf20Sopenharmony_ci * 988c2ecf20Sopenharmony_ci * A bram is used as a configuration memory cache. One frame of data can 998c2ecf20Sopenharmony_ci * be stored in this "storage buffer". 1008c2ecf20Sopenharmony_ci **/ 1018c2ecf20Sopenharmony_cistatic inline u32 buffer_icap_get_bram(void __iomem *base_address, 1028c2ecf20Sopenharmony_ci u32 offset) 1038c2ecf20Sopenharmony_ci{ 1048c2ecf20Sopenharmony_ci return in_be32(base_address + (offset << 2)); 1058c2ecf20Sopenharmony_ci} 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci/** 1088c2ecf20Sopenharmony_ci * buffer_icap_busy - Return true if the icap device is busy 1098c2ecf20Sopenharmony_ci * @base_address: is the base address of the device 1108c2ecf20Sopenharmony_ci * 1118c2ecf20Sopenharmony_ci * The queries the low order bit of the status register, which 1128c2ecf20Sopenharmony_ci * indicates whether the current configuration or readback operation 1138c2ecf20Sopenharmony_ci * has completed. 1148c2ecf20Sopenharmony_ci **/ 1158c2ecf20Sopenharmony_cistatic inline bool buffer_icap_busy(void __iomem *base_address) 1168c2ecf20Sopenharmony_ci{ 1178c2ecf20Sopenharmony_ci u32 status = in_be32(base_address + XHI_STATUS_REG_OFFSET); 1188c2ecf20Sopenharmony_ci return (status & 1) == XHI_NOT_FINISHED; 1198c2ecf20Sopenharmony_ci} 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci/** 1228c2ecf20Sopenharmony_ci * buffer_icap_set_size - Set the size register. 1238c2ecf20Sopenharmony_ci * @base_address: is the base address of the device 1248c2ecf20Sopenharmony_ci * @data: The size in bytes. 1258c2ecf20Sopenharmony_ci * 1268c2ecf20Sopenharmony_ci * The size register holds the number of 8 bit bytes to transfer between 1278c2ecf20Sopenharmony_ci * bram and the icap (or icap to bram). 1288c2ecf20Sopenharmony_ci **/ 1298c2ecf20Sopenharmony_cistatic inline void buffer_icap_set_size(void __iomem *base_address, 1308c2ecf20Sopenharmony_ci u32 data) 1318c2ecf20Sopenharmony_ci{ 1328c2ecf20Sopenharmony_ci out_be32(base_address + XHI_SIZE_REG_OFFSET, data); 1338c2ecf20Sopenharmony_ci} 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci/** 1368c2ecf20Sopenharmony_ci * buffer_icap_set_offset - Set the bram offset register. 1378c2ecf20Sopenharmony_ci * @base_address: contains the base address of the device. 1388c2ecf20Sopenharmony_ci * @data: is the value to be written to the data register. 1398c2ecf20Sopenharmony_ci * 1408c2ecf20Sopenharmony_ci * The bram offset register holds the starting bram address to transfer 1418c2ecf20Sopenharmony_ci * data from during configuration or write data to during readback. 1428c2ecf20Sopenharmony_ci **/ 1438c2ecf20Sopenharmony_cistatic inline void buffer_icap_set_offset(void __iomem *base_address, 1448c2ecf20Sopenharmony_ci u32 data) 1458c2ecf20Sopenharmony_ci{ 1468c2ecf20Sopenharmony_ci out_be32(base_address + XHI_BRAM_OFFSET_REG_OFFSET, data); 1478c2ecf20Sopenharmony_ci} 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci/** 1508c2ecf20Sopenharmony_ci * buffer_icap_set_rnc - Set the RNC (Readback not Configure) register. 1518c2ecf20Sopenharmony_ci * @base_address: contains the base address of the device. 1528c2ecf20Sopenharmony_ci * @data: is the value to be written to the data register. 1538c2ecf20Sopenharmony_ci * 1548c2ecf20Sopenharmony_ci * The RNC register determines the direction of the data transfer. It 1558c2ecf20Sopenharmony_ci * controls whether a configuration or readback take place. Writing to 1568c2ecf20Sopenharmony_ci * this register initiates the transfer. A value of 1 initiates a 1578c2ecf20Sopenharmony_ci * readback while writing a value of 0 initiates a configuration. 1588c2ecf20Sopenharmony_ci **/ 1598c2ecf20Sopenharmony_cistatic inline void buffer_icap_set_rnc(void __iomem *base_address, 1608c2ecf20Sopenharmony_ci u32 data) 1618c2ecf20Sopenharmony_ci{ 1628c2ecf20Sopenharmony_ci out_be32(base_address + XHI_RNC_REG_OFFSET, data); 1638c2ecf20Sopenharmony_ci} 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci/** 1668c2ecf20Sopenharmony_ci * buffer_icap_set_bram - Write data to the storage buffer bram. 1678c2ecf20Sopenharmony_ci * @base_address: contains the base address of the component. 1688c2ecf20Sopenharmony_ci * @offset: The word offset at which the data should be written. 1698c2ecf20Sopenharmony_ci * @data: The value to be written to the bram offset. 1708c2ecf20Sopenharmony_ci * 1718c2ecf20Sopenharmony_ci * A bram is used as a configuration memory cache. One frame of data can 1728c2ecf20Sopenharmony_ci * be stored in this "storage buffer". 1738c2ecf20Sopenharmony_ci **/ 1748c2ecf20Sopenharmony_cistatic inline void buffer_icap_set_bram(void __iomem *base_address, 1758c2ecf20Sopenharmony_ci u32 offset, u32 data) 1768c2ecf20Sopenharmony_ci{ 1778c2ecf20Sopenharmony_ci out_be32(base_address + (offset << 2), data); 1788c2ecf20Sopenharmony_ci} 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci/** 1818c2ecf20Sopenharmony_ci * buffer_icap_device_read - Transfer bytes from ICAP to the storage buffer. 1828c2ecf20Sopenharmony_ci * @drvdata: a pointer to the drvdata. 1838c2ecf20Sopenharmony_ci * @offset: The storage buffer start address. 1848c2ecf20Sopenharmony_ci * @count: The number of words (32 bit) to read from the 1858c2ecf20Sopenharmony_ci * device (ICAP). 1868c2ecf20Sopenharmony_ci **/ 1878c2ecf20Sopenharmony_cistatic int buffer_icap_device_read(struct hwicap_drvdata *drvdata, 1888c2ecf20Sopenharmony_ci u32 offset, u32 count) 1898c2ecf20Sopenharmony_ci{ 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci s32 retries = 0; 1928c2ecf20Sopenharmony_ci void __iomem *base_address = drvdata->base_address; 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci if (buffer_icap_busy(base_address)) 1958c2ecf20Sopenharmony_ci return -EBUSY; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci if ((offset + count) > XHI_MAX_BUFFER_INTS) 1988c2ecf20Sopenharmony_ci return -EINVAL; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci /* setSize count*4 to get bytes. */ 2018c2ecf20Sopenharmony_ci buffer_icap_set_size(base_address, (count << 2)); 2028c2ecf20Sopenharmony_ci buffer_icap_set_offset(base_address, offset); 2038c2ecf20Sopenharmony_ci buffer_icap_set_rnc(base_address, XHI_READBACK); 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci while (buffer_icap_busy(base_address)) { 2068c2ecf20Sopenharmony_ci retries++; 2078c2ecf20Sopenharmony_ci if (retries > XHI_MAX_RETRIES) 2088c2ecf20Sopenharmony_ci return -EBUSY; 2098c2ecf20Sopenharmony_ci } 2108c2ecf20Sopenharmony_ci return 0; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci}; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci/** 2158c2ecf20Sopenharmony_ci * buffer_icap_device_write - Transfer bytes from ICAP to the storage buffer. 2168c2ecf20Sopenharmony_ci * @drvdata: a pointer to the drvdata. 2178c2ecf20Sopenharmony_ci * @offset: The storage buffer start address. 2188c2ecf20Sopenharmony_ci * @count: The number of words (32 bit) to read from the 2198c2ecf20Sopenharmony_ci * device (ICAP). 2208c2ecf20Sopenharmony_ci **/ 2218c2ecf20Sopenharmony_cistatic int buffer_icap_device_write(struct hwicap_drvdata *drvdata, 2228c2ecf20Sopenharmony_ci u32 offset, u32 count) 2238c2ecf20Sopenharmony_ci{ 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci s32 retries = 0; 2268c2ecf20Sopenharmony_ci void __iomem *base_address = drvdata->base_address; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci if (buffer_icap_busy(base_address)) 2298c2ecf20Sopenharmony_ci return -EBUSY; 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci if ((offset + count) > XHI_MAX_BUFFER_INTS) 2328c2ecf20Sopenharmony_ci return -EINVAL; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci /* setSize count*4 to get bytes. */ 2358c2ecf20Sopenharmony_ci buffer_icap_set_size(base_address, count << 2); 2368c2ecf20Sopenharmony_ci buffer_icap_set_offset(base_address, offset); 2378c2ecf20Sopenharmony_ci buffer_icap_set_rnc(base_address, XHI_CONFIGURE); 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci while (buffer_icap_busy(base_address)) { 2408c2ecf20Sopenharmony_ci retries++; 2418c2ecf20Sopenharmony_ci if (retries > XHI_MAX_RETRIES) 2428c2ecf20Sopenharmony_ci return -EBUSY; 2438c2ecf20Sopenharmony_ci } 2448c2ecf20Sopenharmony_ci return 0; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci}; 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci/** 2498c2ecf20Sopenharmony_ci * buffer_icap_reset - Reset the logic of the icap device. 2508c2ecf20Sopenharmony_ci * @drvdata: a pointer to the drvdata. 2518c2ecf20Sopenharmony_ci * 2528c2ecf20Sopenharmony_ci * Writing to the status register resets the ICAP logic in an internal 2538c2ecf20Sopenharmony_ci * version of the core. For the version of the core published in EDK, 2548c2ecf20Sopenharmony_ci * this is a noop. 2558c2ecf20Sopenharmony_ci **/ 2568c2ecf20Sopenharmony_civoid buffer_icap_reset(struct hwicap_drvdata *drvdata) 2578c2ecf20Sopenharmony_ci{ 2588c2ecf20Sopenharmony_ci out_be32(drvdata->base_address + XHI_STATUS_REG_OFFSET, 0xFEFE); 2598c2ecf20Sopenharmony_ci} 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci/** 2628c2ecf20Sopenharmony_ci * buffer_icap_set_configuration - Load a partial bitstream from system memory. 2638c2ecf20Sopenharmony_ci * @drvdata: a pointer to the drvdata. 2648c2ecf20Sopenharmony_ci * @data: Kernel address of the partial bitstream. 2658c2ecf20Sopenharmony_ci * @size: the size of the partial bitstream in 32 bit words. 2668c2ecf20Sopenharmony_ci **/ 2678c2ecf20Sopenharmony_ciint buffer_icap_set_configuration(struct hwicap_drvdata *drvdata, u32 *data, 2688c2ecf20Sopenharmony_ci u32 size) 2698c2ecf20Sopenharmony_ci{ 2708c2ecf20Sopenharmony_ci int status; 2718c2ecf20Sopenharmony_ci s32 buffer_count = 0; 2728c2ecf20Sopenharmony_ci bool dirty = false; 2738c2ecf20Sopenharmony_ci u32 i; 2748c2ecf20Sopenharmony_ci void __iomem *base_address = drvdata->base_address; 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci /* Loop through all the data */ 2778c2ecf20Sopenharmony_ci for (i = 0, buffer_count = 0; i < size; i++) { 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci /* Copy data to bram */ 2808c2ecf20Sopenharmony_ci buffer_icap_set_bram(base_address, buffer_count, data[i]); 2818c2ecf20Sopenharmony_ci dirty = true; 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci if (buffer_count < XHI_MAX_BUFFER_INTS - 1) { 2848c2ecf20Sopenharmony_ci buffer_count++; 2858c2ecf20Sopenharmony_ci continue; 2868c2ecf20Sopenharmony_ci } 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci /* Write data to ICAP */ 2898c2ecf20Sopenharmony_ci status = buffer_icap_device_write( 2908c2ecf20Sopenharmony_ci drvdata, 2918c2ecf20Sopenharmony_ci XHI_BUFFER_START, 2928c2ecf20Sopenharmony_ci XHI_MAX_BUFFER_INTS); 2938c2ecf20Sopenharmony_ci if (status != 0) { 2948c2ecf20Sopenharmony_ci /* abort. */ 2958c2ecf20Sopenharmony_ci buffer_icap_reset(drvdata); 2968c2ecf20Sopenharmony_ci return status; 2978c2ecf20Sopenharmony_ci } 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci buffer_count = 0; 3008c2ecf20Sopenharmony_ci dirty = false; 3018c2ecf20Sopenharmony_ci } 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci /* Write unwritten data to ICAP */ 3048c2ecf20Sopenharmony_ci if (dirty) { 3058c2ecf20Sopenharmony_ci /* Write data to ICAP */ 3068c2ecf20Sopenharmony_ci status = buffer_icap_device_write(drvdata, XHI_BUFFER_START, 3078c2ecf20Sopenharmony_ci buffer_count); 3088c2ecf20Sopenharmony_ci if (status != 0) { 3098c2ecf20Sopenharmony_ci /* abort. */ 3108c2ecf20Sopenharmony_ci buffer_icap_reset(drvdata); 3118c2ecf20Sopenharmony_ci } 3128c2ecf20Sopenharmony_ci return status; 3138c2ecf20Sopenharmony_ci } 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci return 0; 3168c2ecf20Sopenharmony_ci}; 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci/** 3198c2ecf20Sopenharmony_ci * buffer_icap_get_configuration - Read configuration data from the device. 3208c2ecf20Sopenharmony_ci * @drvdata: a pointer to the drvdata. 3218c2ecf20Sopenharmony_ci * @data: Address of the data representing the partial bitstream 3228c2ecf20Sopenharmony_ci * @size: the size of the partial bitstream in 32 bit words. 3238c2ecf20Sopenharmony_ci **/ 3248c2ecf20Sopenharmony_ciint buffer_icap_get_configuration(struct hwicap_drvdata *drvdata, u32 *data, 3258c2ecf20Sopenharmony_ci u32 size) 3268c2ecf20Sopenharmony_ci{ 3278c2ecf20Sopenharmony_ci int status; 3288c2ecf20Sopenharmony_ci s32 buffer_count = 0; 3298c2ecf20Sopenharmony_ci u32 i; 3308c2ecf20Sopenharmony_ci void __iomem *base_address = drvdata->base_address; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci /* Loop through all the data */ 3338c2ecf20Sopenharmony_ci for (i = 0, buffer_count = XHI_MAX_BUFFER_INTS; i < size; i++) { 3348c2ecf20Sopenharmony_ci if (buffer_count == XHI_MAX_BUFFER_INTS) { 3358c2ecf20Sopenharmony_ci u32 words_remaining = size - i; 3368c2ecf20Sopenharmony_ci u32 words_to_read = 3378c2ecf20Sopenharmony_ci words_remaining < 3388c2ecf20Sopenharmony_ci XHI_MAX_BUFFER_INTS ? words_remaining : 3398c2ecf20Sopenharmony_ci XHI_MAX_BUFFER_INTS; 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci /* Read data from ICAP */ 3428c2ecf20Sopenharmony_ci status = buffer_icap_device_read( 3438c2ecf20Sopenharmony_ci drvdata, 3448c2ecf20Sopenharmony_ci XHI_BUFFER_START, 3458c2ecf20Sopenharmony_ci words_to_read); 3468c2ecf20Sopenharmony_ci if (status != 0) { 3478c2ecf20Sopenharmony_ci /* abort. */ 3488c2ecf20Sopenharmony_ci buffer_icap_reset(drvdata); 3498c2ecf20Sopenharmony_ci return status; 3508c2ecf20Sopenharmony_ci } 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci buffer_count = 0; 3538c2ecf20Sopenharmony_ci } 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci /* Copy data from bram */ 3568c2ecf20Sopenharmony_ci data[i] = buffer_icap_get_bram(base_address, buffer_count); 3578c2ecf20Sopenharmony_ci buffer_count++; 3588c2ecf20Sopenharmony_ci } 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci return 0; 3618c2ecf20Sopenharmony_ci}; 362