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

bbc_i2c.c (9754B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/* bbc_i2c.c: I2C low-level driver for BBC device on UltraSPARC-III
      3 *            platforms.
      4 *
      5 * Copyright (C) 2001, 2008 David S. Miller (davem@davemloft.net)
      6 */
      7
      8#include <linux/module.h>
      9#include <linux/kernel.h>
     10#include <linux/types.h>
     11#include <linux/slab.h>
     12#include <linux/sched.h>
     13#include <linux/wait.h>
     14#include <linux/delay.h>
     15#include <linux/interrupt.h>
     16#include <linux/of.h>
     17#include <linux/of_device.h>
     18#include <asm/bbc.h>
     19#include <asm/io.h>
     20
     21#include "bbc_i2c.h"
     22
     23/* Convert this driver to use i2c bus layer someday... */
     24#define I2C_PCF_PIN	0x80
     25#define I2C_PCF_ESO	0x40
     26#define I2C_PCF_ES1	0x20
     27#define I2C_PCF_ES2	0x10
     28#define I2C_PCF_ENI	0x08
     29#define I2C_PCF_STA	0x04
     30#define I2C_PCF_STO	0x02
     31#define I2C_PCF_ACK	0x01
     32
     33#define I2C_PCF_START    (I2C_PCF_PIN | I2C_PCF_ESO | I2C_PCF_ENI | I2C_PCF_STA | I2C_PCF_ACK)
     34#define I2C_PCF_STOP     (I2C_PCF_PIN | I2C_PCF_ESO | I2C_PCF_STO | I2C_PCF_ACK)
     35#define I2C_PCF_REPSTART (              I2C_PCF_ESO | I2C_PCF_STA | I2C_PCF_ACK)
     36#define I2C_PCF_IDLE     (I2C_PCF_PIN | I2C_PCF_ESO               | I2C_PCF_ACK)
     37
     38#define I2C_PCF_INI 0x40   /* 1 if not initialized */
     39#define I2C_PCF_STS 0x20
     40#define I2C_PCF_BER 0x10
     41#define I2C_PCF_AD0 0x08
     42#define I2C_PCF_LRB 0x08
     43#define I2C_PCF_AAS 0x04
     44#define I2C_PCF_LAB 0x02
     45#define I2C_PCF_BB  0x01
     46
     47/* The BBC devices have two I2C controllers.  The first I2C controller
     48 * connects mainly to configuration proms (NVRAM, cpu configuration,
     49 * dimm types, etc.).  Whereas the second I2C controller connects to
     50 * environmental control devices such as fans and temperature sensors.
     51 * The second controller also connects to the smartcard reader, if present.
     52 */
     53
     54static void set_device_claimage(struct bbc_i2c_bus *bp, struct platform_device *op, int val)
     55{
     56	int i;
     57
     58	for (i = 0; i < NUM_CHILDREN; i++) {
     59		if (bp->devs[i].device == op) {
     60			bp->devs[i].client_claimed = val;
     61			return;
     62		}
     63	}
     64}
     65
     66#define claim_device(BP,ECHILD)		set_device_claimage(BP,ECHILD,1)
     67#define release_device(BP,ECHILD)	set_device_claimage(BP,ECHILD,0)
     68
     69struct platform_device *bbc_i2c_getdev(struct bbc_i2c_bus *bp, int index)
     70{
     71	struct platform_device *op = NULL;
     72	int curidx = 0, i;
     73
     74	for (i = 0; i < NUM_CHILDREN; i++) {
     75		if (!(op = bp->devs[i].device))
     76			break;
     77		if (curidx == index)
     78			goto out;
     79		op = NULL;
     80		curidx++;
     81	}
     82
     83out:
     84	if (curidx == index)
     85		return op;
     86	return NULL;
     87}
     88
     89struct bbc_i2c_client *bbc_i2c_attach(struct bbc_i2c_bus *bp, struct platform_device *op)
     90{
     91	struct bbc_i2c_client *client;
     92	const u32 *reg;
     93
     94	client = kzalloc(sizeof(*client), GFP_KERNEL);
     95	if (!client)
     96		return NULL;
     97	client->bp = bp;
     98	client->op = op;
     99
    100	reg = of_get_property(op->dev.of_node, "reg", NULL);
    101	if (!reg) {
    102		kfree(client);
    103		return NULL;
    104	}
    105
    106	client->bus = reg[0];
    107	client->address = reg[1];
    108
    109	claim_device(bp, op);
    110
    111	return client;
    112}
    113
    114void bbc_i2c_detach(struct bbc_i2c_client *client)
    115{
    116	struct bbc_i2c_bus *bp = client->bp;
    117	struct platform_device *op = client->op;
    118
    119	release_device(bp, op);
    120	kfree(client);
    121}
    122
    123static int wait_for_pin(struct bbc_i2c_bus *bp, u8 *status)
    124{
    125	DECLARE_WAITQUEUE(wait, current);
    126	int limit = 32;
    127	int ret = 1;
    128
    129	bp->waiting = 1;
    130	add_wait_queue(&bp->wq, &wait);
    131	while (limit-- > 0) {
    132		long val;
    133
    134		val = wait_event_interruptible_timeout(
    135				bp->wq,
    136				(((*status = readb(bp->i2c_control_regs + 0))
    137				  & I2C_PCF_PIN) == 0),
    138				msecs_to_jiffies(250));
    139		if (val > 0) {
    140			ret = 0;
    141			break;
    142		}
    143	}
    144	remove_wait_queue(&bp->wq, &wait);
    145	bp->waiting = 0;
    146
    147	return ret;
    148}
    149
    150int bbc_i2c_writeb(struct bbc_i2c_client *client, unsigned char val, int off)
    151{
    152	struct bbc_i2c_bus *bp = client->bp;
    153	int address = client->address;
    154	u8 status;
    155	int ret = -1;
    156
    157	if (bp->i2c_bussel_reg != NULL)
    158		writeb(client->bus, bp->i2c_bussel_reg);
    159
    160	writeb(address, bp->i2c_control_regs + 0x1);
    161	writeb(I2C_PCF_START, bp->i2c_control_regs + 0x0);
    162	if (wait_for_pin(bp, &status))
    163		goto out;
    164
    165	writeb(off, bp->i2c_control_regs + 0x1);
    166	if (wait_for_pin(bp, &status) ||
    167	    (status & I2C_PCF_LRB) != 0)
    168		goto out;
    169
    170	writeb(val, bp->i2c_control_regs + 0x1);
    171	if (wait_for_pin(bp, &status))
    172		goto out;
    173
    174	ret = 0;
    175
    176out:
    177	writeb(I2C_PCF_STOP, bp->i2c_control_regs + 0x0);
    178	return ret;
    179}
    180
    181int bbc_i2c_readb(struct bbc_i2c_client *client, unsigned char *byte, int off)
    182{
    183	struct bbc_i2c_bus *bp = client->bp;
    184	unsigned char address = client->address, status;
    185	int ret = -1;
    186
    187	if (bp->i2c_bussel_reg != NULL)
    188		writeb(client->bus, bp->i2c_bussel_reg);
    189
    190	writeb(address, bp->i2c_control_regs + 0x1);
    191	writeb(I2C_PCF_START, bp->i2c_control_regs + 0x0);
    192	if (wait_for_pin(bp, &status))
    193		goto out;
    194
    195	writeb(off, bp->i2c_control_regs + 0x1);
    196	if (wait_for_pin(bp, &status) ||
    197	    (status & I2C_PCF_LRB) != 0)
    198		goto out;
    199
    200	writeb(I2C_PCF_STOP, bp->i2c_control_regs + 0x0);
    201
    202	address |= 0x1; /* READ */
    203
    204	writeb(address, bp->i2c_control_regs + 0x1);
    205	writeb(I2C_PCF_START, bp->i2c_control_regs + 0x0);
    206	if (wait_for_pin(bp, &status))
    207		goto out;
    208
    209	/* Set PIN back to one so the device sends the first
    210	 * byte.
    211	 */
    212	(void) readb(bp->i2c_control_regs + 0x1);
    213	if (wait_for_pin(bp, &status))
    214		goto out;
    215
    216	writeb(I2C_PCF_ESO | I2C_PCF_ENI, bp->i2c_control_regs + 0x0);
    217	*byte = readb(bp->i2c_control_regs + 0x1);
    218	if (wait_for_pin(bp, &status))
    219		goto out;
    220
    221	ret = 0;
    222
    223out:
    224	writeb(I2C_PCF_STOP, bp->i2c_control_regs + 0x0);
    225	(void) readb(bp->i2c_control_regs + 0x1);
    226
    227	return ret;
    228}
    229
    230int bbc_i2c_write_buf(struct bbc_i2c_client *client,
    231		      char *buf, int len, int off)
    232{
    233	int ret = 0;
    234
    235	while (len > 0) {
    236		ret = bbc_i2c_writeb(client, *buf, off);
    237		if (ret < 0)
    238			break;
    239		len--;
    240		buf++;
    241		off++;
    242	}
    243	return ret;
    244}
    245
    246int bbc_i2c_read_buf(struct bbc_i2c_client *client,
    247		     char *buf, int len, int off)
    248{
    249	int ret = 0;
    250
    251	while (len > 0) {
    252		ret = bbc_i2c_readb(client, buf, off);
    253		if (ret < 0)
    254			break;
    255		len--;
    256		buf++;
    257		off++;
    258	}
    259
    260	return ret;
    261}
    262
    263EXPORT_SYMBOL(bbc_i2c_getdev);
    264EXPORT_SYMBOL(bbc_i2c_attach);
    265EXPORT_SYMBOL(bbc_i2c_detach);
    266EXPORT_SYMBOL(bbc_i2c_writeb);
    267EXPORT_SYMBOL(bbc_i2c_readb);
    268EXPORT_SYMBOL(bbc_i2c_write_buf);
    269EXPORT_SYMBOL(bbc_i2c_read_buf);
    270
    271static irqreturn_t bbc_i2c_interrupt(int irq, void *dev_id)
    272{
    273	struct bbc_i2c_bus *bp = dev_id;
    274
    275	/* PIN going from set to clear is the only event which
    276	 * makes the i2c assert an interrupt.
    277	 */
    278	if (bp->waiting &&
    279	    !(readb(bp->i2c_control_regs + 0x0) & I2C_PCF_PIN))
    280		wake_up_interruptible(&bp->wq);
    281
    282	return IRQ_HANDLED;
    283}
    284
    285static void reset_one_i2c(struct bbc_i2c_bus *bp)
    286{
    287	writeb(I2C_PCF_PIN, bp->i2c_control_regs + 0x0);
    288	writeb(bp->own, bp->i2c_control_regs + 0x1);
    289	writeb(I2C_PCF_PIN | I2C_PCF_ES1, bp->i2c_control_regs + 0x0);
    290	writeb(bp->clock, bp->i2c_control_regs + 0x1);
    291	writeb(I2C_PCF_IDLE, bp->i2c_control_regs + 0x0);
    292}
    293
    294static struct bbc_i2c_bus * attach_one_i2c(struct platform_device *op, int index)
    295{
    296	struct bbc_i2c_bus *bp;
    297	struct device_node *dp;
    298	int entry;
    299
    300	bp = kzalloc(sizeof(*bp), GFP_KERNEL);
    301	if (!bp)
    302		return NULL;
    303
    304	INIT_LIST_HEAD(&bp->temps);
    305	INIT_LIST_HEAD(&bp->fans);
    306
    307	bp->i2c_control_regs = of_ioremap(&op->resource[0], 0, 0x2, "bbc_i2c_regs");
    308	if (!bp->i2c_control_regs)
    309		goto fail;
    310
    311	if (op->num_resources == 2) {
    312		bp->i2c_bussel_reg = of_ioremap(&op->resource[1], 0, 0x1, "bbc_i2c_bussel");
    313		if (!bp->i2c_bussel_reg)
    314			goto fail;
    315	}
    316
    317	bp->waiting = 0;
    318	init_waitqueue_head(&bp->wq);
    319	if (request_irq(op->archdata.irqs[0], bbc_i2c_interrupt,
    320			IRQF_SHARED, "bbc_i2c", bp))
    321		goto fail;
    322
    323	bp->index = index;
    324	bp->op = op;
    325
    326	spin_lock_init(&bp->lock);
    327
    328	entry = 0;
    329	for (dp = op->dev.of_node->child;
    330	     dp && entry < 8;
    331	     dp = dp->sibling, entry++) {
    332		struct platform_device *child_op;
    333
    334		child_op = of_find_device_by_node(dp);
    335		bp->devs[entry].device = child_op;
    336		bp->devs[entry].client_claimed = 0;
    337	}
    338
    339	writeb(I2C_PCF_PIN, bp->i2c_control_regs + 0x0);
    340	bp->own = readb(bp->i2c_control_regs + 0x01);
    341	writeb(I2C_PCF_PIN | I2C_PCF_ES1, bp->i2c_control_regs + 0x0);
    342	bp->clock = readb(bp->i2c_control_regs + 0x01);
    343
    344	printk(KERN_INFO "i2c-%d: Regs at %p, %d devices, own %02x, clock %02x.\n",
    345	       bp->index, bp->i2c_control_regs, entry, bp->own, bp->clock);
    346
    347	reset_one_i2c(bp);
    348
    349	return bp;
    350
    351fail:
    352	if (bp->i2c_bussel_reg)
    353		of_iounmap(&op->resource[1], bp->i2c_bussel_reg, 1);
    354	if (bp->i2c_control_regs)
    355		of_iounmap(&op->resource[0], bp->i2c_control_regs, 2);
    356	kfree(bp);
    357	return NULL;
    358}
    359
    360extern int bbc_envctrl_init(struct bbc_i2c_bus *bp);
    361extern void bbc_envctrl_cleanup(struct bbc_i2c_bus *bp);
    362
    363static int bbc_i2c_probe(struct platform_device *op)
    364{
    365	struct bbc_i2c_bus *bp;
    366	int err, index = 0;
    367
    368	bp = attach_one_i2c(op, index);
    369	if (!bp)
    370		return -EINVAL;
    371
    372	err = bbc_envctrl_init(bp);
    373	if (err) {
    374		free_irq(op->archdata.irqs[0], bp);
    375		if (bp->i2c_bussel_reg)
    376			of_iounmap(&op->resource[0], bp->i2c_bussel_reg, 1);
    377		if (bp->i2c_control_regs)
    378			of_iounmap(&op->resource[1], bp->i2c_control_regs, 2);
    379		kfree(bp);
    380	} else {
    381		dev_set_drvdata(&op->dev, bp);
    382	}
    383
    384	return err;
    385}
    386
    387static int bbc_i2c_remove(struct platform_device *op)
    388{
    389	struct bbc_i2c_bus *bp = dev_get_drvdata(&op->dev);
    390
    391	bbc_envctrl_cleanup(bp);
    392
    393	free_irq(op->archdata.irqs[0], bp);
    394
    395	if (bp->i2c_bussel_reg)
    396		of_iounmap(&op->resource[0], bp->i2c_bussel_reg, 1);
    397	if (bp->i2c_control_regs)
    398		of_iounmap(&op->resource[1], bp->i2c_control_regs, 2);
    399
    400	kfree(bp);
    401
    402	return 0;
    403}
    404
    405static const struct of_device_id bbc_i2c_match[] = {
    406	{
    407		.name = "i2c",
    408		.compatible = "SUNW,bbc-i2c",
    409	},
    410	{},
    411};
    412MODULE_DEVICE_TABLE(of, bbc_i2c_match);
    413
    414static struct platform_driver bbc_i2c_driver = {
    415	.driver = {
    416		.name = "bbc_i2c",
    417		.of_match_table = bbc_i2c_match,
    418	},
    419	.probe		= bbc_i2c_probe,
    420	.remove		= bbc_i2c_remove,
    421};
    422
    423module_platform_driver(bbc_i2c_driver);
    424
    425MODULE_LICENSE("GPL");