From mboxrd@z Thu Jan 1 00:00:00 1970 From: Heiko Schocher Date: Mon, 1 Aug 2016 06:25:24 +0200 Subject: [U-Boot] [PATCH 4/7] i2c: add Tegra186 BPMP driver In-Reply-To: <20160729191506.24803-4-swarren@wwwdotorg.org> References: <20160729191506.24803-1-swarren@wwwdotorg.org> <20160729191506.24803-4-swarren@wwwdotorg.org> Message-ID: <579ECF34.5060700@denx.de> List-Id: MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit To: u-boot@lists.denx.de Hello Stephen, Am 29.07.2016 um 21:15 schrieb Stephen Warren: > From: Stephen Warren > > On Tegra186, some I2C controllers are directly controlled by the main CPU, > whereas others are controlled by the BPMP, and can only be accessed by the > main CPU via IPC requests to the BPMP. This driver covers the latter case. > > Signed-off-by: Stephen Warren > --- > drivers/i2c/Kconfig | 10 ++++ > drivers/i2c/Makefile | 1 + > drivers/i2c/tegra186_bpmp_i2c.c | 129 ++++++++++++++++++++++++++++++++++++++++ > 3 files changed, 140 insertions(+) > create mode 100644 drivers/i2c/tegra186_bpmp_i2c.c Reviewed-by: Heiko Schocher bye, Heiko > > diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig > index 6e22bbadff2d..68d3956e473c 100644 > --- a/drivers/i2c/Kconfig > +++ b/drivers/i2c/Kconfig > @@ -154,6 +154,16 @@ config SYS_I2C_UNIPHIER_F > Support for UniPhier FIFO-builtin I2C controller driver. > This I2C controller is used on PH1-Pro4 or newer UniPhier SoCs. > > +config TEGRA186_BPMP_I2C > + bool "Enable Tegra186 BPMP-based I2C driver" > + depends on TEGRA186_BPMP > + help > + Support for Tegra I2C controllers managed by the BPMP (Boot and > + Power Management Processor). On Tegra186, some I2C controllers are > + directly controlled by the main CPU, whereas others are controlled > + by the BPMP, and can only be accessed by the main CPU via IPC > + requests to the BPMP. This driver covers the latter case. > + > source "drivers/i2c/muxes/Kconfig" > > endmenu > diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile > index 167424db9820..97b6bedde822 100644 > --- a/drivers/i2c/Makefile > +++ b/drivers/i2c/Makefile > @@ -41,5 +41,6 @@ obj-$(CONFIG_SYS_I2C_TEGRA) += tegra_i2c.o > obj-$(CONFIG_SYS_I2C_UNIPHIER) += i2c-uniphier.o > obj-$(CONFIG_SYS_I2C_UNIPHIER_F) += i2c-uniphier-f.o > obj-$(CONFIG_SYS_I2C_ZYNQ) += zynq_i2c.o > +obj-$(CONFIG_TEGRA186_BPMP_I2C) += tegra186_bpmp_i2c.o > > obj-$(CONFIG_I2C_MUX) += muxes/ > diff --git a/drivers/i2c/tegra186_bpmp_i2c.c b/drivers/i2c/tegra186_bpmp_i2c.c > new file mode 100644 > index 000000000000..d3b3edffb53f > --- /dev/null > +++ b/drivers/i2c/tegra186_bpmp_i2c.c > @@ -0,0 +1,129 @@ > +/* > + * Copyright (c) 2016, NVIDIA CORPORATION. > + * > + * SPDX-License-Identifier: GPL-2.0 > + */ > + > +#include > +#include > +#include > +#include > +#include > + > +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 = tegra186_bpmp_call(dev->parent, MRQ_I2C, > + &req, sizeof(req), &resp, sizeof(resp)); > + if (ret) > + 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); > + int ret; > + struct fdtdec_phandle_args args; > + > + ret = fdtdec_parse_phandle_with_args(gd->fdt_blob, dev->of_offset, > + "nvidia,bpmp", NULL, 0, 0, &args); > + if (ret < 0) { > + debug("%s: fdtdec_parse_phandle_with_args() failed: %d\n", > + __func__, ret); > + return ret; > + } > + > + priv->bpmp_bus_id = fdtdec_get_uint(gd->fdt_blob, dev->of_offset, > + "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 -ENODEV; > + } > + > + 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, > +}; > -- DENX Software Engineering GmbH, Managing Director: Wolfgang Denk HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany