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