1 /*
2  * Copyright (c) 2016, NVIDIA CORPORATION.
3  *
4  * SPDX-License-Identifier: GPL-2.0
5  */
6 
7 #include <common.h>
8 #include <dm.h>
9 #include <i2c.h>
10 #include <misc.h>
11 #include <asm/arch-tegra/bpmp_abi.h>
12 
13 DECLARE_GLOBAL_DATA_PTR;
14 
15 struct tegra186_bpmp_i2c {
16 	uint32_t bpmp_bus_id;
17 };
18 
19 static inline void serialize_u16(uint8_t **p, uint16_t val)
20 {
21 	(*p)[0] = val & 0xff;
22 	(*p)[1] = val >> 8;
23 	(*p) += 2;
24 }
25 
26 /* These just happen to have the same values as I2C_M_* and SERIALI2C_* */
27 #define SUPPORTED_FLAGS \
28 	(I2C_M_TEN | \
29 	I2C_M_RD | \
30 	I2C_M_STOP | \
31 	I2C_M_NOSTART | \
32 	I2C_M_REV_DIR_ADDR | \
33 	I2C_M_IGNORE_NAK | \
34 	I2C_M_NO_RD_ACK | \
35 	I2C_M_RECV_LEN)
36 
37 static int tegra186_bpmp_i2c_xfer(struct udevice *dev, struct i2c_msg *msg,
38 				  int nmsgs)
39 {
40 	struct tegra186_bpmp_i2c *priv = dev_get_priv(dev);
41 	struct mrq_i2c_request req;
42 	struct mrq_i2c_response resp;
43 	uint8_t *p;
44 	int left, i, ret;
45 
46 	req.cmd = CMD_I2C_XFER;
47 	req.xfer.bus_id = priv->bpmp_bus_id;
48 	p = &req.xfer.data_buf[0];
49 	left = ARRAY_SIZE(req.xfer.data_buf);
50 	for (i = 0; i < nmsgs; i++) {
51 		int len = 6;
52 		if (!(msg[i].flags & I2C_M_RD))
53 			len += msg[i].len;
54 		if ((len >= BIT(16)) || (len > left))
55 			return -ENOSPC;
56 
57 		if (msg[i].flags & ~SUPPORTED_FLAGS)
58 			return -EINVAL;
59 
60 		serialize_u16(&p, msg[i].addr);
61 		serialize_u16(&p, msg[i].flags);
62 		serialize_u16(&p, msg[i].len);
63 		if (!(msg[i].flags & I2C_M_RD)) {
64 			memcpy(p, msg[i].buf, msg[i].len);
65 			p += msg[i].len;
66 		}
67 	}
68 	req.xfer.data_size = p - &req.xfer.data_buf[0];
69 
70 	ret = misc_call(dev->parent, MRQ_I2C, &req, sizeof(req), &resp,
71 			sizeof(resp));
72 	if (ret < 0)
73 		return ret;
74 
75 	p = &resp.xfer.data_buf[0];
76 	left = resp.xfer.data_size;
77 	if (left > ARRAY_SIZE(resp.xfer.data_buf))
78 		return -EINVAL;
79 	for (i = 0; i < nmsgs; i++) {
80 		if (msg[i].flags & I2C_M_RD) {
81 			memcpy(msg[i].buf, p, msg[i].len);
82 			p += msg[i].len;
83 		}
84 	}
85 
86 	return 0;
87 }
88 
89 static int tegra186_bpmp_i2c_probe(struct udevice *dev)
90 {
91 	struct tegra186_bpmp_i2c *priv = dev_get_priv(dev);
92 	int ret;
93 	struct fdtdec_phandle_args args;
94 
95 	ret = fdtdec_parse_phandle_with_args(gd->fdt_blob, dev->of_offset,
96 					     "nvidia,bpmp", NULL, 0, 0, &args);
97 	if (ret < 0) {
98 		debug("%s: fdtdec_parse_phandle_with_args() failed: %d\n",
99 		      __func__, ret);
100 		return ret;
101 	}
102 
103 	priv->bpmp_bus_id = fdtdec_get_uint(gd->fdt_blob, dev->of_offset,
104 					    "nvidia,bpmp-bus-id", U32_MAX);
105 	if (priv->bpmp_bus_id == U32_MAX) {
106 		debug("%s: could not parse nvidia,bpmp-bus-id\n", __func__);
107 		return -ENODEV;
108 	}
109 
110 	return 0;
111 }
112 
113 static const struct dm_i2c_ops tegra186_bpmp_i2c_ops = {
114 	.xfer = tegra186_bpmp_i2c_xfer,
115 };
116 
117 static const struct udevice_id tegra186_bpmp_i2c_ids[] = {
118 	{ .compatible = "nvidia,tegra186-bpmp-i2c" },
119 	{ }
120 };
121 
122 U_BOOT_DRIVER(i2c_gpio) = {
123 	.name	= "tegra186_bpmp_i2c",
124 	.id	= UCLASS_I2C,
125 	.of_match = tegra186_bpmp_i2c_ids,
126 	.probe	= tegra186_bpmp_i2c_probe,
127 	.priv_auto_alloc_size = sizeof(struct tegra186_bpmp_i2c),
128 	.ops	= &tegra186_bpmp_i2c_ops,
129 };
130