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