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