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

encx24j600-regmap.c (11734B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Register map access API - ENCX24J600 support
      4 *
      5 * Copyright 2015 Gridpoint
      6 *
      7 * Author: Jon Ringle <jringle@gridpoint.com>
      8 */
      9
     10#include <linux/delay.h>
     11#include <linux/errno.h>
     12#include <linux/init.h>
     13#include <linux/module.h>
     14#include <linux/netdevice.h>
     15#include <linux/regmap.h>
     16#include <linux/spi/spi.h>
     17
     18#include "encx24j600_hw.h"
     19
     20static int encx24j600_switch_bank(struct encx24j600_context *ctx,
     21				  int bank)
     22{
     23	int ret = 0;
     24	int bank_opcode = BANK_SELECT(bank);
     25
     26	ret = spi_write(ctx->spi, &bank_opcode, 1);
     27	if (ret == 0)
     28		ctx->bank = bank;
     29
     30	return ret;
     31}
     32
     33static int encx24j600_cmdn(struct encx24j600_context *ctx, u8 opcode,
     34			   const void *buf, size_t len)
     35{
     36	struct spi_message m;
     37	struct spi_transfer t[2] = { { .tx_buf = &opcode, .len = 1, },
     38				     { .tx_buf = buf, .len = len }, };
     39	spi_message_init(&m);
     40	spi_message_add_tail(&t[0], &m);
     41	spi_message_add_tail(&t[1], &m);
     42
     43	return spi_sync(ctx->spi, &m);
     44}
     45
     46static void regmap_lock_mutex(void *context)
     47{
     48	struct encx24j600_context *ctx = context;
     49
     50	mutex_lock(&ctx->mutex);
     51}
     52
     53static void regmap_unlock_mutex(void *context)
     54{
     55	struct encx24j600_context *ctx = context;
     56
     57	mutex_unlock(&ctx->mutex);
     58}
     59
     60static int regmap_encx24j600_sfr_read(void *context, u8 reg, u8 *val,
     61				      size_t len)
     62{
     63	struct encx24j600_context *ctx = context;
     64	u8 banked_reg = reg & ADDR_MASK;
     65	u8 bank = ((reg & BANK_MASK) >> BANK_SHIFT);
     66	u8 cmd = RCRU;
     67	int ret = 0;
     68	int i = 0;
     69	u8 tx_buf[2];
     70
     71	if (reg < 0x80) {
     72		cmd = RCRCODE | banked_reg;
     73		if ((banked_reg < 0x16) && (ctx->bank != bank))
     74			ret = encx24j600_switch_bank(ctx, bank);
     75		if (unlikely(ret))
     76			return ret;
     77	} else {
     78		/* Translate registers that are more effecient using
     79		 * 3-byte SPI commands
     80		 */
     81		switch (reg) {
     82		case EGPRDPT:
     83			cmd = RGPRDPT; break;
     84		case EGPWRPT:
     85			cmd = RGPWRPT; break;
     86		case ERXRDPT:
     87			cmd = RRXRDPT; break;
     88		case ERXWRPT:
     89			cmd = RRXWRPT; break;
     90		case EUDARDPT:
     91			cmd = RUDARDPT; break;
     92		case EUDAWRPT:
     93			cmd = RUDAWRPT; break;
     94		case EGPDATA:
     95		case ERXDATA:
     96		case EUDADATA:
     97		default:
     98			return -EINVAL;
     99		}
    100	}
    101
    102	tx_buf[i++] = cmd;
    103	if (cmd == RCRU)
    104		tx_buf[i++] = reg;
    105
    106	ret = spi_write_then_read(ctx->spi, tx_buf, i, val, len);
    107
    108	return ret;
    109}
    110
    111static int regmap_encx24j600_sfr_update(struct encx24j600_context *ctx,
    112					u8 reg, u8 *val, size_t len,
    113					u8 unbanked_cmd, u8 banked_code)
    114{
    115	u8 banked_reg = reg & ADDR_MASK;
    116	u8 bank = ((reg & BANK_MASK) >> BANK_SHIFT);
    117	u8 cmd = unbanked_cmd;
    118	struct spi_message m;
    119	struct spi_transfer t[3] = { { .tx_buf = &cmd, .len = sizeof(cmd), },
    120				     { .tx_buf = &reg, .len = sizeof(reg), },
    121				     { .tx_buf = val, .len = len }, };
    122
    123	if (reg < 0x80) {
    124		int ret = 0;
    125
    126		cmd = banked_code | banked_reg;
    127		if ((banked_reg < 0x16) && (ctx->bank != bank))
    128			ret = encx24j600_switch_bank(ctx, bank);
    129		if (unlikely(ret))
    130			return ret;
    131	} else {
    132		/* Translate registers that are more effecient using
    133		 * 3-byte SPI commands
    134		 */
    135		switch (reg) {
    136		case EGPRDPT:
    137			cmd = WGPRDPT; break;
    138		case EGPWRPT:
    139			cmd = WGPWRPT; break;
    140		case ERXRDPT:
    141			cmd = WRXRDPT; break;
    142		case ERXWRPT:
    143			cmd = WRXWRPT; break;
    144		case EUDARDPT:
    145			cmd = WUDARDPT; break;
    146		case EUDAWRPT:
    147			cmd = WUDAWRPT; break;
    148		case EGPDATA:
    149		case ERXDATA:
    150		case EUDADATA:
    151		default:
    152			return -EINVAL;
    153		}
    154	}
    155
    156	spi_message_init(&m);
    157	spi_message_add_tail(&t[0], &m);
    158
    159	if (cmd == unbanked_cmd) {
    160		t[1].tx_buf = &reg;
    161		spi_message_add_tail(&t[1], &m);
    162	}
    163
    164	spi_message_add_tail(&t[2], &m);
    165	return spi_sync(ctx->spi, &m);
    166}
    167
    168static int regmap_encx24j600_sfr_write(void *context, u8 reg, u8 *val,
    169				       size_t len)
    170{
    171	struct encx24j600_context *ctx = context;
    172
    173	return regmap_encx24j600_sfr_update(ctx, reg, val, len, WCRU, WCRCODE);
    174}
    175
    176static int regmap_encx24j600_sfr_set_bits(struct encx24j600_context *ctx,
    177					  u8 reg, u8 val)
    178{
    179	return regmap_encx24j600_sfr_update(ctx, reg, &val, 1, BFSU, BFSCODE);
    180}
    181
    182static int regmap_encx24j600_sfr_clr_bits(struct encx24j600_context *ctx,
    183					  u8 reg, u8 val)
    184{
    185	return regmap_encx24j600_sfr_update(ctx, reg, &val, 1, BFCU, BFCCODE);
    186}
    187
    188static int regmap_encx24j600_reg_update_bits(void *context, unsigned int reg,
    189					     unsigned int mask,
    190					     unsigned int val)
    191{
    192	struct encx24j600_context *ctx = context;
    193
    194	int ret = 0;
    195	unsigned int set_mask = mask & val;
    196	unsigned int clr_mask = mask & ~val;
    197
    198	if ((reg >= 0x40 && reg < 0x6c) || reg >= 0x80)
    199		return -EINVAL;
    200
    201	if (set_mask & 0xff)
    202		ret = regmap_encx24j600_sfr_set_bits(ctx, reg, set_mask);
    203
    204	set_mask = (set_mask & 0xff00) >> 8;
    205
    206	if ((set_mask & 0xff) && (ret == 0))
    207		ret = regmap_encx24j600_sfr_set_bits(ctx, reg + 1, set_mask);
    208
    209	if ((clr_mask & 0xff) && (ret == 0))
    210		ret = regmap_encx24j600_sfr_clr_bits(ctx, reg, clr_mask);
    211
    212	clr_mask = (clr_mask & 0xff00) >> 8;
    213
    214	if ((clr_mask & 0xff) && (ret == 0))
    215		ret = regmap_encx24j600_sfr_clr_bits(ctx, reg + 1, clr_mask);
    216
    217	return ret;
    218}
    219
    220int regmap_encx24j600_spi_write(void *context, u8 reg, const u8 *data,
    221				size_t count)
    222{
    223	struct encx24j600_context *ctx = context;
    224
    225	if (reg < 0xc0)
    226		return encx24j600_cmdn(ctx, reg, data, count);
    227
    228	/* SPI 1-byte command. Ignore data */
    229	return spi_write(ctx->spi, &reg, 1);
    230}
    231EXPORT_SYMBOL_GPL(regmap_encx24j600_spi_write);
    232
    233int regmap_encx24j600_spi_read(void *context, u8 reg, u8 *data, size_t count)
    234{
    235	struct encx24j600_context *ctx = context;
    236
    237	if (reg == RBSEL && count > 1)
    238		count = 1;
    239
    240	return spi_write_then_read(ctx->spi, &reg, sizeof(reg), data, count);
    241}
    242EXPORT_SYMBOL_GPL(regmap_encx24j600_spi_read);
    243
    244static int regmap_encx24j600_write(void *context, const void *data,
    245				   size_t len)
    246{
    247	u8 *dout = (u8 *)data;
    248	u8 reg = dout[0];
    249	++dout;
    250	--len;
    251
    252	if (reg > 0xa0)
    253		return regmap_encx24j600_spi_write(context, reg, dout, len);
    254
    255	if (len > 2)
    256		return -EINVAL;
    257
    258	return regmap_encx24j600_sfr_write(context, reg, dout, len);
    259}
    260
    261static int regmap_encx24j600_read(void *context,
    262				  const void *reg_buf, size_t reg_size,
    263				  void *val, size_t val_size)
    264{
    265	u8 reg = *(const u8 *)reg_buf;
    266
    267	if (reg_size != 1) {
    268		pr_err("%s: reg=%02x reg_size=%zu\n", __func__, reg, reg_size);
    269		return -EINVAL;
    270	}
    271
    272	if (reg > 0xa0)
    273		return regmap_encx24j600_spi_read(context, reg, val, val_size);
    274
    275	if (val_size > 2) {
    276		pr_err("%s: reg=%02x val_size=%zu\n", __func__, reg, val_size);
    277		return -EINVAL;
    278	}
    279
    280	return regmap_encx24j600_sfr_read(context, reg, val, val_size);
    281}
    282
    283static bool encx24j600_regmap_readable(struct device *dev, unsigned int reg)
    284{
    285	if ((reg < 0x36) ||
    286	    ((reg >= 0x40) && (reg < 0x4c)) ||
    287	    ((reg >= 0x52) && (reg < 0x56)) ||
    288	    ((reg >= 0x60) && (reg < 0x66)) ||
    289	    ((reg >= 0x68) && (reg < 0x80)) ||
    290	    ((reg >= 0x86) && (reg < 0x92)) ||
    291	    (reg == 0xc8))
    292		return true;
    293	else
    294		return false;
    295}
    296
    297static bool encx24j600_regmap_writeable(struct device *dev, unsigned int reg)
    298{
    299	if ((reg < 0x12) ||
    300	    ((reg >= 0x14) && (reg < 0x1a)) ||
    301	    ((reg >= 0x1c) && (reg < 0x36)) ||
    302	    ((reg >= 0x40) && (reg < 0x4c)) ||
    303	    ((reg >= 0x52) && (reg < 0x56)) ||
    304	    ((reg >= 0x60) && (reg < 0x68)) ||
    305	    ((reg >= 0x6c) && (reg < 0x80)) ||
    306	    ((reg >= 0x86) && (reg < 0x92)) ||
    307	    ((reg >= 0xc0) && (reg < 0xc8)) ||
    308	    ((reg >= 0xca) && (reg < 0xf0)))
    309		return true;
    310	else
    311		return false;
    312}
    313
    314static bool encx24j600_regmap_volatile(struct device *dev, unsigned int reg)
    315{
    316	switch (reg) {
    317	case ERXHEAD:
    318	case EDMACS:
    319	case ETXSTAT:
    320	case ETXWIRE:
    321	case ECON1:	/* Can be modified via single byte cmds */
    322	case ECON2:	/* Can be modified via single byte cmds */
    323	case ESTAT:
    324	case EIR:	/* Can be modified via single byte cmds */
    325	case MIRD:
    326	case MISTAT:
    327		return true;
    328	default:
    329		break;
    330	}
    331
    332	return false;
    333}
    334
    335static bool encx24j600_regmap_precious(struct device *dev, unsigned int reg)
    336{
    337	/* single byte cmds are precious */
    338	if (((reg >= 0xc0) && (reg < 0xc8)) ||
    339	    ((reg >= 0xca) && (reg < 0xf0)))
    340		return true;
    341	else
    342		return false;
    343}
    344
    345static int regmap_encx24j600_phy_reg_read(void *context, unsigned int reg,
    346					  unsigned int *val)
    347{
    348	struct encx24j600_context *ctx = context;
    349	int ret;
    350	unsigned int mistat;
    351
    352	reg = MIREGADR_VAL | (reg & PHREG_MASK);
    353	ret = regmap_write(ctx->regmap, MIREGADR, reg);
    354	if (unlikely(ret))
    355		goto err_out;
    356
    357	ret = regmap_write(ctx->regmap, MICMD, MIIRD);
    358	if (unlikely(ret))
    359		goto err_out;
    360
    361	usleep_range(26, 100);
    362	while ((ret = regmap_read(ctx->regmap, MISTAT, &mistat) != 0) &&
    363	       (mistat & BUSY))
    364		cpu_relax();
    365
    366	if (unlikely(ret))
    367		goto err_out;
    368
    369	ret = regmap_write(ctx->regmap, MICMD, 0);
    370	if (unlikely(ret))
    371		goto err_out;
    372
    373	ret = regmap_read(ctx->regmap, MIRD, val);
    374
    375err_out:
    376	if (ret)
    377		pr_err("%s: error %d reading reg %02x\n", __func__, ret,
    378		       reg & PHREG_MASK);
    379
    380	return ret;
    381}
    382
    383static int regmap_encx24j600_phy_reg_write(void *context, unsigned int reg,
    384					   unsigned int val)
    385{
    386	struct encx24j600_context *ctx = context;
    387	int ret;
    388	unsigned int mistat;
    389
    390	reg = MIREGADR_VAL | (reg & PHREG_MASK);
    391	ret = regmap_write(ctx->regmap, MIREGADR, reg);
    392	if (unlikely(ret))
    393		goto err_out;
    394
    395	ret = regmap_write(ctx->regmap, MIWR, val);
    396	if (unlikely(ret))
    397		goto err_out;
    398
    399	usleep_range(26, 100);
    400	while ((ret = regmap_read(ctx->regmap, MISTAT, &mistat) != 0) &&
    401	       (mistat & BUSY))
    402		cpu_relax();
    403
    404err_out:
    405	if (ret)
    406		pr_err("%s: error %d writing reg %02x=%04x\n", __func__, ret,
    407		       reg & PHREG_MASK, val);
    408
    409	return ret;
    410}
    411
    412static bool encx24j600_phymap_readable(struct device *dev, unsigned int reg)
    413{
    414	switch (reg) {
    415	case PHCON1:
    416	case PHSTAT1:
    417	case PHANA:
    418	case PHANLPA:
    419	case PHANE:
    420	case PHCON2:
    421	case PHSTAT2:
    422	case PHSTAT3:
    423		return true;
    424	default:
    425		return false;
    426	}
    427}
    428
    429static bool encx24j600_phymap_writeable(struct device *dev, unsigned int reg)
    430{
    431	switch (reg) {
    432	case PHCON1:
    433	case PHCON2:
    434	case PHANA:
    435		return true;
    436	case PHSTAT1:
    437	case PHSTAT2:
    438	case PHSTAT3:
    439	case PHANLPA:
    440	case PHANE:
    441	default:
    442		return false;
    443	}
    444}
    445
    446static bool encx24j600_phymap_volatile(struct device *dev, unsigned int reg)
    447{
    448	switch (reg) {
    449	case PHSTAT1:
    450	case PHSTAT2:
    451	case PHSTAT3:
    452	case PHANLPA:
    453	case PHANE:
    454	case PHCON2:
    455		return true;
    456	default:
    457		return false;
    458	}
    459}
    460
    461static struct regmap_config regcfg = {
    462	.name = "reg",
    463	.reg_bits = 8,
    464	.val_bits = 16,
    465	.max_register = 0xee,
    466	.reg_stride = 2,
    467	.cache_type = REGCACHE_RBTREE,
    468	.val_format_endian = REGMAP_ENDIAN_LITTLE,
    469	.readable_reg = encx24j600_regmap_readable,
    470	.writeable_reg = encx24j600_regmap_writeable,
    471	.volatile_reg = encx24j600_regmap_volatile,
    472	.precious_reg = encx24j600_regmap_precious,
    473	.lock = regmap_lock_mutex,
    474	.unlock = regmap_unlock_mutex,
    475};
    476
    477static struct regmap_bus regmap_encx24j600 = {
    478	.write = regmap_encx24j600_write,
    479	.read = regmap_encx24j600_read,
    480	.reg_update_bits = regmap_encx24j600_reg_update_bits,
    481};
    482
    483static struct regmap_config phycfg = {
    484	.name = "phy",
    485	.reg_bits = 8,
    486	.val_bits = 16,
    487	.max_register = 0x1f,
    488	.cache_type = REGCACHE_RBTREE,
    489	.val_format_endian = REGMAP_ENDIAN_LITTLE,
    490	.readable_reg = encx24j600_phymap_readable,
    491	.writeable_reg = encx24j600_phymap_writeable,
    492	.volatile_reg = encx24j600_phymap_volatile,
    493};
    494
    495static struct regmap_bus phymap_encx24j600 = {
    496	.reg_write = regmap_encx24j600_phy_reg_write,
    497	.reg_read = regmap_encx24j600_phy_reg_read,
    498};
    499
    500int devm_regmap_init_encx24j600(struct device *dev,
    501				struct encx24j600_context *ctx)
    502{
    503	mutex_init(&ctx->mutex);
    504	regcfg.lock_arg = ctx;
    505	ctx->regmap = devm_regmap_init(dev, &regmap_encx24j600, ctx, &regcfg);
    506	if (IS_ERR(ctx->regmap))
    507		return PTR_ERR(ctx->regmap);
    508	ctx->phymap = devm_regmap_init(dev, &phymap_encx24j600, ctx, &phycfg);
    509	if (IS_ERR(ctx->phymap))
    510		return PTR_ERR(ctx->phymap);
    511
    512	return 0;
    513}
    514EXPORT_SYMBOL_GPL(devm_regmap_init_encx24j600);
    515
    516MODULE_LICENSE("GPL");