1 // SPDX-License-Identifier: BSD-3-Clause 2 /* 3 * Qualcomm SPMI bus driver 4 * 5 * (C) Copyright 2015 Mateusz Kulikowski <mateusz.kulikowski@gmail.com> 6 * 7 * Loosely based on Little Kernel driver 8 */ 9 10 #include <common.h> 11 #include <dm.h> 12 #include <errno.h> 13 #include <fdtdec.h> 14 #include <asm/io.h> 15 #include <spmi/spmi.h> 16 17 DECLARE_GLOBAL_DATA_PTR; 18 19 /* PMIC Arbiter configuration registers */ 20 #define PMIC_ARB_VERSION 0x0000 21 #define PMIC_ARB_VERSION_V2_MIN 0x20010000 22 23 #define ARB_CHANNEL_OFFSET(n) (0x4 * (n)) 24 #define SPMI_CH_OFFSET(chnl) ((chnl) * 0x8000) 25 26 #define SPMI_REG_CMD0 0x0 27 #define SPMI_REG_CONFIG 0x4 28 #define SPMI_REG_STATUS 0x8 29 #define SPMI_REG_WDATA 0x10 30 #define SPMI_REG_RDATA 0x18 31 32 #define SPMI_CMD_OPCODE_SHIFT 27 33 #define SPMI_CMD_SLAVE_ID_SHIFT 20 34 #define SPMI_CMD_ADDR_SHIFT 12 35 #define SPMI_CMD_ADDR_OFFSET_SHIFT 4 36 #define SPMI_CMD_BYTE_CNT_SHIFT 0 37 38 #define SPMI_CMD_EXT_REG_WRITE_LONG 0x00 39 #define SPMI_CMD_EXT_REG_READ_LONG 0x01 40 41 #define SPMI_STATUS_DONE 0x1 42 43 #define SPMI_MAX_CHANNELS 128 44 #define SPMI_MAX_SLAVES 16 45 #define SPMI_MAX_PERIPH 256 46 47 struct msm_spmi_priv { 48 phys_addr_t arb_chnl; /* ARB channel mapping base */ 49 phys_addr_t spmi_core; /* SPMI core */ 50 phys_addr_t spmi_obs; /* SPMI observer */ 51 /* SPMI channel map */ 52 uint8_t channel_map[SPMI_MAX_SLAVES][SPMI_MAX_PERIPH]; 53 }; 54 55 static int msm_spmi_write(struct udevice *dev, int usid, int pid, int off, 56 uint8_t val) 57 { 58 struct msm_spmi_priv *priv = dev_get_priv(dev); 59 unsigned channel; 60 uint32_t reg = 0; 61 62 if (usid >= SPMI_MAX_SLAVES) 63 return -EIO; 64 if (pid >= SPMI_MAX_PERIPH) 65 return -EIO; 66 67 channel = priv->channel_map[usid][pid]; 68 69 /* Disable IRQ mode for the current channel*/ 70 writel(0x0, priv->spmi_core + SPMI_CH_OFFSET(channel) + 71 SPMI_REG_CONFIG); 72 73 /* Write single byte */ 74 writel(val, priv->spmi_core + SPMI_CH_OFFSET(channel) + SPMI_REG_WDATA); 75 76 /* Prepare write command */ 77 reg |= SPMI_CMD_EXT_REG_WRITE_LONG << SPMI_CMD_OPCODE_SHIFT; 78 reg |= (usid << SPMI_CMD_SLAVE_ID_SHIFT); 79 reg |= (pid << SPMI_CMD_ADDR_SHIFT); 80 reg |= (off << SPMI_CMD_ADDR_OFFSET_SHIFT); 81 reg |= 1; /* byte count */ 82 83 /* Send write command */ 84 writel(reg, priv->spmi_core + SPMI_CH_OFFSET(channel) + SPMI_REG_CMD0); 85 86 /* Wait till CMD DONE status */ 87 reg = 0; 88 while (!reg) { 89 reg = readl(priv->spmi_core + SPMI_CH_OFFSET(channel) + 90 SPMI_REG_STATUS); 91 } 92 93 if (reg ^ SPMI_STATUS_DONE) { 94 printf("SPMI write failure.\n"); 95 return -EIO; 96 } 97 98 return 0; 99 } 100 101 static int msm_spmi_read(struct udevice *dev, int usid, int pid, int off) 102 { 103 struct msm_spmi_priv *priv = dev_get_priv(dev); 104 unsigned channel; 105 uint32_t reg = 0; 106 107 if (usid >= SPMI_MAX_SLAVES) 108 return -EIO; 109 if (pid >= SPMI_MAX_PERIPH) 110 return -EIO; 111 112 channel = priv->channel_map[usid][pid]; 113 114 /* Disable IRQ mode for the current channel*/ 115 writel(0x0, priv->spmi_obs + SPMI_CH_OFFSET(channel) + SPMI_REG_CONFIG); 116 117 /* Prepare read command */ 118 reg |= SPMI_CMD_EXT_REG_READ_LONG << SPMI_CMD_OPCODE_SHIFT; 119 reg |= (usid << SPMI_CMD_SLAVE_ID_SHIFT); 120 reg |= (pid << SPMI_CMD_ADDR_SHIFT); 121 reg |= (off << SPMI_CMD_ADDR_OFFSET_SHIFT); 122 reg |= 1; /* byte count */ 123 124 /* Request read */ 125 writel(reg, priv->spmi_obs + SPMI_CH_OFFSET(channel) + SPMI_REG_CMD0); 126 127 /* Wait till CMD DONE status */ 128 reg = 0; 129 while (!reg) { 130 reg = readl(priv->spmi_obs + SPMI_CH_OFFSET(channel) + 131 SPMI_REG_STATUS); 132 } 133 134 if (reg ^ SPMI_STATUS_DONE) { 135 printf("SPMI read failure.\n"); 136 return -EIO; 137 } 138 139 /* Read the data */ 140 return readl(priv->spmi_obs + SPMI_CH_OFFSET(channel) + 141 SPMI_REG_RDATA) & 0xFF; 142 } 143 144 static struct dm_spmi_ops msm_spmi_ops = { 145 .read = msm_spmi_read, 146 .write = msm_spmi_write, 147 }; 148 149 static int msm_spmi_probe(struct udevice *dev) 150 { 151 struct udevice *parent = dev->parent; 152 struct msm_spmi_priv *priv = dev_get_priv(dev); 153 int node = dev_of_offset(dev); 154 u32 hw_ver; 155 bool is_v1; 156 int i; 157 158 priv->arb_chnl = devfdt_get_addr(dev); 159 priv->spmi_core = fdtdec_get_addr_size_auto_parent(gd->fdt_blob, 160 dev_of_offset(parent), node, "reg", 1, NULL, false); 161 priv->spmi_obs = fdtdec_get_addr_size_auto_parent(gd->fdt_blob, 162 dev_of_offset(parent), node, "reg", 2, NULL, false); 163 164 hw_ver = readl(priv->arb_chnl + PMIC_ARB_VERSION - 0x800); 165 is_v1 = (hw_ver < PMIC_ARB_VERSION_V2_MIN); 166 167 dev_dbg(dev, "PMIC Arb Version-%d (0x%x)\n", (is_v1 ? 1 : 2), hw_ver); 168 169 if (priv->arb_chnl == FDT_ADDR_T_NONE || 170 priv->spmi_core == FDT_ADDR_T_NONE || 171 priv->spmi_obs == FDT_ADDR_T_NONE) 172 return -EINVAL; 173 174 /* Scan peripherals connected to each SPMI channel */ 175 for (i = 0; i < SPMI_MAX_PERIPH ; i++) { 176 uint32_t periph = readl(priv->arb_chnl + ARB_CHANNEL_OFFSET(i)); 177 uint8_t slave_id = (periph & 0xf0000) >> 16; 178 uint8_t pid = (periph & 0xff00) >> 8; 179 180 priv->channel_map[slave_id][pid] = i; 181 } 182 return 0; 183 } 184 185 static const struct udevice_id msm_spmi_ids[] = { 186 { .compatible = "qcom,spmi-pmic-arb" }, 187 { } 188 }; 189 190 U_BOOT_DRIVER(msm_spmi) = { 191 .name = "msm_spmi", 192 .id = UCLASS_SPMI, 193 .of_match = msm_spmi_ids, 194 .ops = &msm_spmi_ops, 195 .probe = msm_spmi_probe, 196 .priv_auto_alloc_size = sizeof(struct msm_spmi_priv), 197 }; 198