162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * altera-comp.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * altera FPGA driver 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Copyright (C) Altera Corporation 1998-2001 862306a36Sopenharmony_ci * Copyright (C) 2010 NetUP Inc. 962306a36Sopenharmony_ci * Copyright (C) 2010 Igor M. Liplianin <liplianin@netup.ru> 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include <linux/kernel.h> 1362306a36Sopenharmony_ci#include "altera-exprt.h" 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#define SHORT_BITS 16 1662306a36Sopenharmony_ci#define CHAR_BITS 8 1762306a36Sopenharmony_ci#define DATA_BLOB_LENGTH 3 1862306a36Sopenharmony_ci#define MATCH_DATA_LENGTH 8192 1962306a36Sopenharmony_ci#define ALTERA_REQUEST_SIZE 1024 2062306a36Sopenharmony_ci#define ALTERA_BUFFER_SIZE (MATCH_DATA_LENGTH + ALTERA_REQUEST_SIZE) 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_cistatic u32 altera_bits_req(u32 n) 2362306a36Sopenharmony_ci{ 2462306a36Sopenharmony_ci u32 result = SHORT_BITS; 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci if (n == 0) 2762306a36Sopenharmony_ci result = 1; 2862306a36Sopenharmony_ci else { 2962306a36Sopenharmony_ci /* Look for the highest non-zero bit position */ 3062306a36Sopenharmony_ci while ((n & (1 << (SHORT_BITS - 1))) == 0) { 3162306a36Sopenharmony_ci n <<= 1; 3262306a36Sopenharmony_ci --result; 3362306a36Sopenharmony_ci } 3462306a36Sopenharmony_ci } 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci return result; 3762306a36Sopenharmony_ci} 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_cistatic u32 altera_read_packed(u8 *buffer, u32 bits, u32 *bits_avail, 4062306a36Sopenharmony_ci u32 *in_index) 4162306a36Sopenharmony_ci{ 4262306a36Sopenharmony_ci u32 result = 0; 4362306a36Sopenharmony_ci u32 shift = 0; 4462306a36Sopenharmony_ci u32 databyte = 0; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci while (bits > 0) { 4762306a36Sopenharmony_ci databyte = buffer[*in_index]; 4862306a36Sopenharmony_ci result |= (((databyte >> (CHAR_BITS - *bits_avail)) 4962306a36Sopenharmony_ci & (0xff >> (CHAR_BITS - *bits_avail))) << shift); 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci if (bits <= *bits_avail) { 5262306a36Sopenharmony_ci result &= (0xffff >> (SHORT_BITS - (bits + shift))); 5362306a36Sopenharmony_ci *bits_avail -= bits; 5462306a36Sopenharmony_ci bits = 0; 5562306a36Sopenharmony_ci } else { 5662306a36Sopenharmony_ci ++(*in_index); 5762306a36Sopenharmony_ci shift += *bits_avail; 5862306a36Sopenharmony_ci bits -= *bits_avail; 5962306a36Sopenharmony_ci *bits_avail = CHAR_BITS; 6062306a36Sopenharmony_ci } 6162306a36Sopenharmony_ci } 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci return result; 6462306a36Sopenharmony_ci} 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ciu32 altera_shrink(u8 *in, u32 in_length, u8 *out, u32 out_length, s32 version) 6762306a36Sopenharmony_ci{ 6862306a36Sopenharmony_ci u32 i, j, data_length = 0L; 6962306a36Sopenharmony_ci u32 offset, length; 7062306a36Sopenharmony_ci u32 match_data_length = MATCH_DATA_LENGTH; 7162306a36Sopenharmony_ci u32 bits_avail = CHAR_BITS; 7262306a36Sopenharmony_ci u32 in_index = 0L; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci if (version > 0) 7562306a36Sopenharmony_ci --match_data_length; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci for (i = 0; i < out_length; ++i) 7862306a36Sopenharmony_ci out[i] = 0; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci /* Read number of bytes in data. */ 8162306a36Sopenharmony_ci for (i = 0; i < sizeof(in_length); ++i) { 8262306a36Sopenharmony_ci data_length = data_length | ( 8362306a36Sopenharmony_ci altera_read_packed(in, 8462306a36Sopenharmony_ci CHAR_BITS, 8562306a36Sopenharmony_ci &bits_avail, 8662306a36Sopenharmony_ci &in_index) << (i * CHAR_BITS)); 8762306a36Sopenharmony_ci } 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci if (data_length > out_length) { 9062306a36Sopenharmony_ci data_length = 0L; 9162306a36Sopenharmony_ci return data_length; 9262306a36Sopenharmony_ci } 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci i = 0; 9562306a36Sopenharmony_ci while (i < data_length) { 9662306a36Sopenharmony_ci /* A 0 bit indicates literal data. */ 9762306a36Sopenharmony_ci if (altera_read_packed(in, 1, &bits_avail, 9862306a36Sopenharmony_ci &in_index) == 0) { 9962306a36Sopenharmony_ci for (j = 0; j < DATA_BLOB_LENGTH; ++j) { 10062306a36Sopenharmony_ci if (i < data_length) { 10162306a36Sopenharmony_ci out[i] = (u8)altera_read_packed(in, 10262306a36Sopenharmony_ci CHAR_BITS, 10362306a36Sopenharmony_ci &bits_avail, 10462306a36Sopenharmony_ci &in_index); 10562306a36Sopenharmony_ci i++; 10662306a36Sopenharmony_ci } 10762306a36Sopenharmony_ci } 10862306a36Sopenharmony_ci } else { 10962306a36Sopenharmony_ci /* A 1 bit indicates offset/length to follow. */ 11062306a36Sopenharmony_ci offset = altera_read_packed(in, altera_bits_req((s16) 11162306a36Sopenharmony_ci (i > match_data_length ? 11262306a36Sopenharmony_ci match_data_length : i)), 11362306a36Sopenharmony_ci &bits_avail, 11462306a36Sopenharmony_ci &in_index); 11562306a36Sopenharmony_ci length = altera_read_packed(in, CHAR_BITS, 11662306a36Sopenharmony_ci &bits_avail, 11762306a36Sopenharmony_ci &in_index); 11862306a36Sopenharmony_ci for (j = 0; j < length; ++j) { 11962306a36Sopenharmony_ci if (i < data_length) { 12062306a36Sopenharmony_ci out[i] = out[i - offset]; 12162306a36Sopenharmony_ci i++; 12262306a36Sopenharmony_ci } 12362306a36Sopenharmony_ci } 12462306a36Sopenharmony_ci } 12562306a36Sopenharmony_ci } 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci return data_length; 12862306a36Sopenharmony_ci} 129