cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

fbtft-bus.c (7736B)


      1// SPDX-License-Identifier: GPL-2.0
      2#include <linux/export.h>
      3#include <linux/errno.h>
      4#include <linux/gpio/consumer.h>
      5#include <linux/spi/spi.h>
      6#include "fbtft.h"
      7
      8/*****************************************************************************
      9 *
     10 *   void (*write_reg)(struct fbtft_par *par, int len, ...);
     11 *
     12 *****************************************************************************/
     13
     14#define define_fbtft_write_reg(func, buffer_type, data_type, modifier)        \
     15void func(struct fbtft_par *par, int len, ...)                                \
     16{                                                                             \
     17	va_list args;                                                         \
     18	int i, ret;                                                           \
     19	int offset = 0;                                                       \
     20	buffer_type *buf = (buffer_type *)par->buf;                           \
     21									      \
     22	if (unlikely(par->debug & DEBUG_WRITE_REGISTER)) {                    \
     23		va_start(args, len);                                          \
     24		for (i = 0; i < len; i++) {                                   \
     25			buf[i] = modifier((data_type)va_arg(args,             \
     26							    unsigned int));   \
     27		}                                                             \
     28		va_end(args);                                                 \
     29		fbtft_par_dbg_hex(DEBUG_WRITE_REGISTER, par,                  \
     30				  par->info->device, buffer_type, buf, len,   \
     31				  "%s: ", __func__);                          \
     32	}                                                                     \
     33									      \
     34	va_start(args, len);                                                  \
     35									      \
     36	if (par->startbyte) {                                                 \
     37		*(u8 *)par->buf = par->startbyte;                             \
     38		buf = (buffer_type *)(par->buf + 1);                          \
     39		offset = 1;                                                   \
     40	}                                                                     \
     41									      \
     42	*buf = modifier((data_type)va_arg(args, unsigned int));               \
     43	ret = fbtft_write_buf_dc(par, par->buf, sizeof(data_type) + offset,   \
     44				 0);                                          \
     45	if (ret < 0)							      \
     46		goto out;						      \
     47	len--;                                                                \
     48									      \
     49	if (par->startbyte)                                                   \
     50		*(u8 *)par->buf = par->startbyte | 0x2;                       \
     51									      \
     52	if (len) {                                                            \
     53		i = len;                                                      \
     54		while (i--)						      \
     55			*buf++ = modifier((data_type)va_arg(args,             \
     56							    unsigned int));   \
     57		fbtft_write_buf_dc(par, par->buf,			      \
     58				   len * (sizeof(data_type) + offset), 1);    \
     59	}                                                                     \
     60out:									      \
     61	va_end(args);                                                         \
     62}                                                                             \
     63EXPORT_SYMBOL(func);
     64
     65define_fbtft_write_reg(fbtft_write_reg8_bus8, u8, u8, )
     66define_fbtft_write_reg(fbtft_write_reg16_bus8, __be16, u16, cpu_to_be16)
     67define_fbtft_write_reg(fbtft_write_reg16_bus16, u16, u16, )
     68
     69void fbtft_write_reg8_bus9(struct fbtft_par *par, int len, ...)
     70{
     71	va_list args;
     72	int i, ret;
     73	int pad = 0;
     74	u16 *buf = (u16 *)par->buf;
     75
     76	if (unlikely(par->debug & DEBUG_WRITE_REGISTER)) {
     77		va_start(args, len);
     78		for (i = 0; i < len; i++)
     79			*(((u8 *)buf) + i) = (u8)va_arg(args, unsigned int);
     80		va_end(args);
     81		fbtft_par_dbg_hex(DEBUG_WRITE_REGISTER, par,
     82				  par->info->device, u8, buf, len, "%s: ",
     83				  __func__);
     84	}
     85	if (len <= 0)
     86		return;
     87
     88	if (par->spi && (par->spi->bits_per_word == 8)) {
     89		/* we're emulating 9-bit, pad start of buffer with no-ops
     90		 * (assuming here that zero is a no-op)
     91		 */
     92		pad = (len % 4) ? 4 - (len % 4) : 0;
     93		for (i = 0; i < pad; i++)
     94			*buf++ = 0x000;
     95	}
     96
     97	va_start(args, len);
     98	*buf++ = (u8)va_arg(args, unsigned int);
     99	i = len - 1;
    100	while (i--) {
    101		*buf = (u8)va_arg(args, unsigned int);
    102		*buf++ |= 0x100; /* dc=1 */
    103	}
    104	va_end(args);
    105	ret = par->fbtftops.write(par, par->buf, (len + pad) * sizeof(u16));
    106	if (ret < 0) {
    107		dev_err(par->info->device,
    108			"write() failed and returned %d\n", ret);
    109		return;
    110	}
    111}
    112EXPORT_SYMBOL(fbtft_write_reg8_bus9);
    113
    114/*****************************************************************************
    115 *
    116 *   int (*write_vmem)(struct fbtft_par *par);
    117 *
    118 *****************************************************************************/
    119
    120/* 16 bit pixel over 8-bit databus */
    121int fbtft_write_vmem16_bus8(struct fbtft_par *par, size_t offset, size_t len)
    122{
    123	u16 *vmem16;
    124	__be16 *txbuf16 = par->txbuf.buf;
    125	size_t remain;
    126	size_t to_copy;
    127	size_t tx_array_size;
    128	int i;
    129	int ret = 0;
    130	size_t startbyte_size = 0;
    131
    132	fbtft_par_dbg(DEBUG_WRITE_VMEM, par, "%s(offset=%zu, len=%zu)\n",
    133		      __func__, offset, len);
    134
    135	remain = len / 2;
    136	vmem16 = (u16 *)(par->info->screen_buffer + offset);
    137
    138	gpiod_set_value(par->gpio.dc, 1);
    139
    140	/* non buffered write */
    141	if (!par->txbuf.buf)
    142		return par->fbtftops.write(par, vmem16, len);
    143
    144	/* buffered write */
    145	tx_array_size = par->txbuf.len / 2;
    146
    147	if (par->startbyte) {
    148		txbuf16 = par->txbuf.buf + 1;
    149		tx_array_size -= 2;
    150		*(u8 *)(par->txbuf.buf) = par->startbyte | 0x2;
    151		startbyte_size = 1;
    152	}
    153
    154	while (remain) {
    155		to_copy = min(tx_array_size, remain);
    156		dev_dbg(par->info->device, "to_copy=%zu, remain=%zu\n",
    157			to_copy, remain - to_copy);
    158
    159		for (i = 0; i < to_copy; i++)
    160			txbuf16[i] = cpu_to_be16(vmem16[i]);
    161
    162		vmem16 = vmem16 + to_copy;
    163		ret = par->fbtftops.write(par, par->txbuf.buf,
    164						startbyte_size + to_copy * 2);
    165		if (ret < 0)
    166			return ret;
    167		remain -= to_copy;
    168	}
    169
    170	return ret;
    171}
    172EXPORT_SYMBOL(fbtft_write_vmem16_bus8);
    173
    174/* 16 bit pixel over 9-bit SPI bus: dc + high byte, dc + low byte */
    175int fbtft_write_vmem16_bus9(struct fbtft_par *par, size_t offset, size_t len)
    176{
    177	u8 *vmem8;
    178	u16 *txbuf16 = par->txbuf.buf;
    179	size_t remain;
    180	size_t to_copy;
    181	size_t tx_array_size;
    182	int i;
    183	int ret = 0;
    184
    185	fbtft_par_dbg(DEBUG_WRITE_VMEM, par, "%s(offset=%zu, len=%zu)\n",
    186		      __func__, offset, len);
    187
    188	if (!par->txbuf.buf) {
    189		dev_err(par->info->device, "%s: txbuf.buf is NULL\n", __func__);
    190		return -1;
    191	}
    192
    193	remain = len;
    194	vmem8 = par->info->screen_buffer + offset;
    195
    196	tx_array_size = par->txbuf.len / 2;
    197
    198	while (remain) {
    199		to_copy = min(tx_array_size, remain);
    200		dev_dbg(par->info->device, "to_copy=%zu, remain=%zu\n",
    201			to_copy, remain - to_copy);
    202
    203#ifdef __LITTLE_ENDIAN
    204		for (i = 0; i < to_copy; i += 2) {
    205			txbuf16[i]     = 0x0100 | vmem8[i + 1];
    206			txbuf16[i + 1] = 0x0100 | vmem8[i];
    207		}
    208#else
    209		for (i = 0; i < to_copy; i++)
    210			txbuf16[i]   = 0x0100 | vmem8[i];
    211#endif
    212		vmem8 = vmem8 + to_copy;
    213		ret = par->fbtftops.write(par, par->txbuf.buf, to_copy * 2);
    214		if (ret < 0)
    215			return ret;
    216		remain -= to_copy;
    217	}
    218
    219	return ret;
    220}
    221EXPORT_SYMBOL(fbtft_write_vmem16_bus9);
    222
    223int fbtft_write_vmem8_bus8(struct fbtft_par *par, size_t offset, size_t len)
    224{
    225	dev_err(par->info->device, "%s: function not implemented\n", __func__);
    226	return -1;
    227}
    228EXPORT_SYMBOL(fbtft_write_vmem8_bus8);
    229
    230/* 16 bit pixel over 16-bit databus */
    231int fbtft_write_vmem16_bus16(struct fbtft_par *par, size_t offset, size_t len)
    232{
    233	u16 *vmem16;
    234
    235	fbtft_par_dbg(DEBUG_WRITE_VMEM, par, "%s(offset=%zu, len=%zu)\n",
    236		      __func__, offset, len);
    237
    238	vmem16 = (u16 *)(par->info->screen_buffer + offset);
    239
    240	/* no need for buffered write with 16-bit bus */
    241	return fbtft_write_buf_dc(par, vmem16, len, 1);
    242}
    243EXPORT_SYMBOL(fbtft_write_vmem16_bus16);