Subject: [PATCH 2/6 v3] spmi: msm: add arbiter version 5 support

Ramon Fried rfried.dev at gmail.com
Thu Sep 9 21:30:05 CEST 2021


On Thu, Sep 9, 2021 at 6:03 PM Dzmitry Sankouski <dsankouski at gmail.com> wrote:
>
> From b65826c49fee93dd7ded11a848814d8fa79fdb2e Mon Sep 17 00:00:00 2001
> From: Dzmitry Sankouski <dsankouski at gmail.com>
> Date: Sat, 28 Aug 2021 13:53:42 +0300
> Subject: [PATCH 2/6 v3] spmi: msm: add arbiter version 5 support
>
> Currently driver supports only version 1 and 2.
> Version 5 has slightly different registers structure
>
> Signed-off-by: Dzmitry Sankouski <dsankouski at gmail.com>
> Cc: Ramon Fried <rfried.dev at gmail.com>
> ---
> Changes for v2:
> - change string formats in debug statements
> Changes for v3
> - remove if else braces where possible
>
>  MAINTAINERS             |   1 +
>  drivers/spmi/spmi-msm.c | 154 +++++++++++++++++++++++++++-------------
>  2 files changed, 105 insertions(+), 50 deletions(-)
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 52ddc99cda..6b8b0783d2 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -392,6 +392,7 @@ F: drivers/phy/msm8916-usbh-phy.c
>  F: drivers/serial/serial_msm.c
>  F: drivers/serial/serial_msm_geni.c
>  F: drivers/smem/msm_smem.c
> +F: drivers/spmi/spmi-msm.c
>  F: drivers/usb/host/ehci-msm.c
>
>  ARM STI
> diff --git a/drivers/spmi/spmi-msm.c b/drivers/spmi/spmi-msm.c
> index 5a335e50aa..442cb44e82 100644
> --- a/drivers/spmi/spmi-msm.c
> +++ b/drivers/spmi/spmi-msm.c
> @@ -19,39 +19,63 @@
>  DECLARE_GLOBAL_DATA_PTR;
>
>  /* PMIC Arbiter configuration registers */
> -#define PMIC_ARB_VERSION 0x0000
> -#define PMIC_ARB_VERSION_V2_MIN 0x20010000
> -
> -#define ARB_CHANNEL_OFFSET(n) (0x4 * (n))
> -#define SPMI_CH_OFFSET(chnl) ((chnl) * 0x8000)
> -
> -#define SPMI_REG_CMD0 0x0
> -#define SPMI_REG_CONFIG 0x4
> -#define SPMI_REG_STATUS 0x8
> -#define SPMI_REG_WDATA 0x10
> -#define SPMI_REG_RDATA 0x18
> -
> -#define SPMI_CMD_OPCODE_SHIFT 27
> -#define SPMI_CMD_SLAVE_ID_SHIFT 20
> -#define SPMI_CMD_ADDR_SHIFT 12
> -#define SPMI_CMD_ADDR_OFFSET_SHIFT 4
> -#define SPMI_CMD_BYTE_CNT_SHIFT 0
> -
> -#define SPMI_CMD_EXT_REG_WRITE_LONG 0x00
> -#define SPMI_CMD_EXT_REG_READ_LONG 0x01
> -
> -#define SPMI_STATUS_DONE 0x1
> +#define PMIC_ARB_VERSION 0x0000
> +#define PMIC_ARB_VERSION_V2_MIN 0x20010000
> +#define PMIC_ARB_VERSION_V3_MIN 0x30000000
> +#define PMIC_ARB_VERSION_V5_MIN 0x50000000
> +
> +#define APID_MAP_OFFSET_V1_V2_V3 (0x800)
> +#define APID_MAP_OFFSET_V5 (0x900)
> +#define ARB_CHANNEL_OFFSET(n) (0x4 * (n))
> +#define SPMI_CH_OFFSET(chnl) ((chnl) * 0x8000)
> +#define SPMI_V5_OBS_CH_OFFSET(chnl) ((chnl) * 0x80)
> +#define SPMI_V5_RW_CH_OFFSET(chnl) ((chnl) * 0x10000)
> +
> +#define SPMI_REG_CMD0 0x0
> +#define SPMI_REG_CONFIG 0x4
> +#define SPMI_REG_STATUS 0x8
> +#define SPMI_REG_WDATA 0x10
> +#define SPMI_REG_RDATA 0x18
> +
> +#define SPMI_CMD_OPCODE_SHIFT 27
> +#define SPMI_CMD_SLAVE_ID_SHIFT 20
> +#define SPMI_CMD_ADDR_SHIFT 12
> +#define SPMI_CMD_ADDR_OFFSET_SHIFT 4
> +#define SPMI_CMD_BYTE_CNT_SHIFT 0
> +
> +#define SPMI_CMD_EXT_REG_WRITE_LONG 0x00
> +#define SPMI_CMD_EXT_REG_READ_LONG 0x01
> +
> +#define SPMI_STATUS_DONE 0x1
> +
> +#define SPMI_MAX_CHANNELS 128
> +#define SPMI_MAX_SLAVES 16
> +#define SPMI_MAX_PERIPH 256
> +
> +enum arb_ver {
> + V1 = 1,
> + V2,
> + V3,
> + V5 = 5
> +};
>
> -#define SPMI_MAX_CHANNELS 128
> -#define SPMI_MAX_SLAVES 16
> -#define SPMI_MAX_PERIPH 256
> +/*
> + * PMIC arbiter version 5 uses different register offsets for read/write vs
> + * observer channels.
> + */
> +enum pmic_arb_channel {
> + PMIC_ARB_CHANNEL_RW,
> + PMIC_ARB_CHANNEL_OBS,
> +};
>
>  struct msm_spmi_priv {
> - phys_addr_t arb_chnl; /* ARB channel mapping base */
> + phys_addr_t arb_chnl;  /* ARB channel mapping base */
>   phys_addr_t spmi_core; /* SPMI core */
> - phys_addr_t spmi_obs; /* SPMI observer */
> + phys_addr_t spmi_obs;  /* SPMI observer */
>   /* SPMI channel map */
>   uint8_t channel_map[SPMI_MAX_SLAVES][SPMI_MAX_PERIPH];
> + /* SPMI bus arbiter version */
> + u32 arb_ver;
>  };
>
>  static int msm_spmi_write(struct udevice *dev, int usid, int pid, int off,
> @@ -59,6 +83,7 @@ static int msm_spmi_write(struct udevice *dev, int usid, int pid, int off,
>  {
>   struct msm_spmi_priv *priv = dev_get_priv(dev);
>   unsigned channel;
> + unsigned int ch_offset;
>   uint32_t reg = 0;
>
>   if (usid >= SPMI_MAX_SLAVES)
> @@ -69,8 +94,8 @@ static int msm_spmi_write(struct udevice *dev, int usid, int pid, int off,
>   channel = priv->channel_map[usid][pid];
>
>   /* Disable IRQ mode for the current channel*/
> - writel(0x0, priv->spmi_core + SPMI_CH_OFFSET(channel) +
> -       SPMI_REG_CONFIG);
> + writel(0x0,
> +       priv->spmi_core + SPMI_CH_OFFSET(channel) + SPMI_REG_CONFIG);
>
>   /* Write single byte */
>   writel(val, priv->spmi_core + SPMI_CH_OFFSET(channel) + SPMI_REG_WDATA);
> @@ -82,6 +107,11 @@ static int msm_spmi_write(struct udevice *dev, int usid, int pid, int off,
>   reg |= (off << SPMI_CMD_ADDR_OFFSET_SHIFT);
>   reg |= 1; /* byte count */
>
> + if (priv->arb_ver == V5)
> + ch_offset = SPMI_V5_RW_CH_OFFSET(channel);
> + else
> + ch_offset = SPMI_CH_OFFSET(channel);
> +
>   /* Send write command */
>   writel(reg, priv->spmi_core + SPMI_CH_OFFSET(channel) + SPMI_REG_CMD0);
>
> @@ -104,6 +134,7 @@ static int msm_spmi_read(struct udevice *dev, int usid, int pid, int off)
>  {
>   struct msm_spmi_priv *priv = dev_get_priv(dev);
>   unsigned channel;
> + unsigned int ch_offset;
>   uint32_t reg = 0;
>
>   if (usid >= SPMI_MAX_SLAVES)
> @@ -113,8 +144,13 @@ static int msm_spmi_read(struct udevice *dev, int usid, int pid, int off)
>
>   channel = priv->channel_map[usid][pid];
>
> + if (priv->arb_ver == V5)
> + ch_offset = SPMI_V5_OBS_CH_OFFSET(channel);
> + else
> + ch_offset = SPMI_CH_OFFSET(channel);
> +
>   /* Disable IRQ mode for the current channel*/
> - writel(0x0, priv->spmi_obs + SPMI_CH_OFFSET(channel) + SPMI_REG_CONFIG);
> + writel(0x0, priv->spmi_obs + ch_offset + SPMI_REG_CONFIG);
>
>   /* Prepare read command */
>   reg |= SPMI_CMD_EXT_REG_READ_LONG << SPMI_CMD_OPCODE_SHIFT;
> @@ -124,13 +160,12 @@ static int msm_spmi_read(struct udevice *dev, int usid, int pid, int off)
>   reg |= 1; /* byte count */
>
>   /* Request read */
> - writel(reg, priv->spmi_obs + SPMI_CH_OFFSET(channel) + SPMI_REG_CMD0);
> + writel(reg, priv->spmi_obs + ch_offset + SPMI_REG_CMD0);
>
>   /* Wait till CMD DONE status */
>   reg = 0;
>   while (!reg) {
> - reg = readl(priv->spmi_obs + SPMI_CH_OFFSET(channel) +
> -    SPMI_REG_STATUS);
> + reg = readl(priv->spmi_obs + ch_offset + SPMI_REG_STATUS);
>   }
>
>   if (reg ^ SPMI_STATUS_DONE) {
> @@ -139,8 +174,8 @@ static int msm_spmi_read(struct udevice *dev, int usid, int pid, int off)
>   }
>
>   /* Read the data */
> - return readl(priv->spmi_obs + SPMI_CH_OFFSET(channel) +
> -     SPMI_REG_RDATA) & 0xFF;
> + return readl(priv->spmi_obs + ch_offset +
> + SPMI_REG_RDATA) & 0xFF;
>  }
>
>  static struct dm_spmi_ops msm_spmi_ops = {
> @@ -150,31 +185,50 @@ static struct dm_spmi_ops msm_spmi_ops = {
>
>  static int msm_spmi_probe(struct udevice *dev)
>  {
> - struct udevice *parent = dev->parent;
>   struct msm_spmi_priv *priv = dev_get_priv(dev);
> - int node = dev_of_offset(dev);
> + u32 config_addr;
>   u32 hw_ver;
> - bool is_v1;
> + u32 version;
>   int i;
> + int err;
> +
> + config_addr = dev_read_addr_index(dev, 0);
> + priv->spmi_core = dev_read_addr_index(dev, 1);
> + priv->spmi_obs = dev_read_addr_index(dev, 2);
> +
> + hw_ver = readl(config_addr + PMIC_ARB_VERSION);
> +
> + if (hw_ver < PMIC_ARB_VERSION_V3_MIN) {
> + priv->arb_ver = V2;
> + version = 2;
> + priv->arb_chnl = config_addr + APID_MAP_OFFSET_V1_V2_V3;
> + } else if (hw_ver < PMIC_ARB_VERSION_V5_MIN) {
> + priv->arb_ver = V3;
> + version = 3;
> + priv->arb_chnl = config_addr + APID_MAP_OFFSET_V1_V2_V3;
> + } else {
> + priv->arb_ver = V5;
> + version = 5;
> + priv->arb_chnl = config_addr + APID_MAP_OFFSET_V5;
> +
> + if (err) {
> + dev_err(dev, "could not read APID->PPID mapping table, rc= %d\n", err);
> + return -1;
> + }
> + }
>
> - priv->arb_chnl = dev_read_addr(dev);
> - priv->spmi_core = fdtdec_get_addr_size_auto_parent(gd->fdt_blob,
> - dev_of_offset(parent), node, "reg", 1, NULL, false);
> - priv->spmi_obs = fdtdec_get_addr_size_auto_parent(gd->fdt_blob,
> - dev_of_offset(parent), node, "reg", 2, NULL, false);
> -
> - hw_ver = readl(priv->arb_chnl + PMIC_ARB_VERSION - 0x800);
> - is_v1  = (hw_ver < PMIC_ARB_VERSION_V2_MIN);
> -
> - dev_dbg(dev, "PMIC Arb Version-%d (0x%x)\n", (is_v1 ? 1 : 2), hw_ver);
> + dev_dbg(dev, "PMIC Arb Version-%d (0x%x)\n", version, hw_ver);
>
>   if (priv->arb_chnl == FDT_ADDR_T_NONE ||
>      priv->spmi_core == FDT_ADDR_T_NONE ||
>      priv->spmi_obs == FDT_ADDR_T_NONE)
>   return -EINVAL;
>
> + dev_dbg(dev, "priv->arb_chnl address (%llu)\n", priv->arb_chnl);
> + dev_dbg(dev, "priv->spmi_core address (%llu)\n", priv->spmi_core);
> + dev_dbg(dev, "priv->spmi_obs address (%llu)\n", priv->spmi_obs);
>   /* Scan peripherals connected to each SPMI channel */
> - for (i = 0; i < SPMI_MAX_PERIPH ; i++) {
> + for (i = 0; i < SPMI_MAX_PERIPH; i++) {
>   uint32_t periph = readl(priv->arb_chnl + ARB_CHANNEL_OFFSET(i));
>   uint8_t slave_id = (periph & 0xf0000) >> 16;
>   uint8_t pid = (periph & 0xff00) >> 8;
> @@ -195,5 +249,5 @@ U_BOOT_DRIVER(msm_spmi) = {
>   .of_match = msm_spmi_ids,
>   .ops = &msm_spmi_ops,
>   .probe = msm_spmi_probe,
> - .priv_auto = sizeof(struct msm_spmi_priv),
> + .priv_auto = sizeof(struct msm_spmi_priv),
>  };
> --
> 2.20.1
>
Reviewed-by: Ramon Fried <rfried.dev at gmail.com>


More information about the U-Boot mailing list