1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Low-level I/O functions. 4 * 5 * Copyright (c) 2017-2020, Silicon Laboratories, Inc. 6 * Copyright (c) 2010, ST-Ericsson 7 */ 8 #include <linux/kernel.h> 9 #include <linux/delay.h> 10 #include <linux/slab.h> 11 #include <linux/align.h> 12 13 #include "hwio.h" 14 #include "wfx.h" 15 #include "bus.h" 16 #include "traces.h" 17 18 #define WFX_HIF_BUFFER_SIZE 0x2000 19 20 static int wfx_read32(struct wfx_dev *wdev, int reg, u32 *val) 21 { 22 int ret; 23 __le32 *tmp = kmalloc(sizeof(u32), GFP_KERNEL); 24 25 *val = ~0; /* Never return undefined value */ 26 if (!tmp) 27 return -ENOMEM; 28 ret = wdev->hwbus_ops->copy_from_io(wdev->hwbus_priv, reg, tmp, sizeof(u32)); 29 if (ret >= 0) 30 *val = le32_to_cpu(*tmp); 31 kfree(tmp); 32 if (ret) 33 dev_err(wdev->dev, "%s: bus communication error: %d\n", __func__, ret); 34 return ret; 35 } 36 37 static int wfx_write32(struct wfx_dev *wdev, int reg, u32 val) 38 { 39 int ret; 40 __le32 *tmp = kmalloc(sizeof(u32), GFP_KERNEL); 41 42 if (!tmp) 43 return -ENOMEM; 44 *tmp = cpu_to_le32(val); 45 ret = wdev->hwbus_ops->copy_to_io(wdev->hwbus_priv, reg, tmp, sizeof(u32)); 46 kfree(tmp); 47 if (ret) 48 dev_err(wdev->dev, "%s: bus communication error: %d\n", __func__, ret); 49 return ret; 50 } 51 52 static int wfx_read32_locked(struct wfx_dev *wdev, int reg, u32 *val) 53 { 54 int ret; 55 56 wdev->hwbus_ops->lock(wdev->hwbus_priv); 57 ret = wfx_read32(wdev, reg, val); 58 _trace_io_read32(reg, *val); 59 wdev->hwbus_ops->unlock(wdev->hwbus_priv); 60 return ret; 61 } 62 63 static int wfx_write32_locked(struct wfx_dev *wdev, int reg, u32 val) 64 { 65 int ret; 66 67 wdev->hwbus_ops->lock(wdev->hwbus_priv); 68 ret = wfx_write32(wdev, reg, val); 69 _trace_io_write32(reg, val); 70 wdev->hwbus_ops->unlock(wdev->hwbus_priv); 71 return ret; 72 } 73 74 static int wfx_write32_bits_locked(struct wfx_dev *wdev, int reg, u32 mask, u32 val) 75 { 76 int ret; 77 u32 val_r, val_w; 78 79 WARN_ON(~mask & val); 80 val &= mask; 81 wdev->hwbus_ops->lock(wdev->hwbus_priv); 82 ret = wfx_read32(wdev, reg, &val_r); 83 _trace_io_read32(reg, val_r); 84 if (ret < 0) 85 goto err; 86 val_w = (val_r & ~mask) | val; 87 if (val_w != val_r) { 88 ret = wfx_write32(wdev, reg, val_w); 89 _trace_io_write32(reg, val_w); 90 } 91 err: 92 wdev->hwbus_ops->unlock(wdev->hwbus_priv); 93 return ret; 94 } 95 96 static int wfx_indirect_read(struct wfx_dev *wdev, int reg, u32 addr, void *buf, size_t len) 97 { 98 int ret; 99 int i; 100 u32 cfg; 101 u32 prefetch; 102 103 WARN_ON(len >= WFX_HIF_BUFFER_SIZE); 104 WARN_ON(reg != WFX_REG_AHB_DPORT && reg != WFX_REG_SRAM_DPORT); 105 106 if (reg == WFX_REG_AHB_DPORT) 107 prefetch = CFG_PREFETCH_AHB; 108 else if (reg == WFX_REG_SRAM_DPORT) 109 prefetch = CFG_PREFETCH_SRAM; 110 else 111 return -ENODEV; 112 113 ret = wfx_write32(wdev, WFX_REG_BASE_ADDR, addr); 114 if (ret < 0) 115 goto err; 116 117 ret = wfx_read32(wdev, WFX_REG_CONFIG, &cfg); 118 if (ret < 0) 119 goto err; 120 121 ret = wfx_write32(wdev, WFX_REG_CONFIG, cfg | prefetch); 122 if (ret < 0) 123 goto err; 124 125 for (i = 0; i < 20; i++) { 126 ret = wfx_read32(wdev, WFX_REG_CONFIG, &cfg); 127 if (ret < 0) 128 goto err; 129 if (!(cfg & prefetch)) 130 break; 131 usleep_range(200, 250); 132 } 133 if (i == 20) { 134 ret = -ETIMEDOUT; 135 goto err; 136 } 137 138 ret = wdev->hwbus_ops->copy_from_io(wdev->hwbus_priv, reg, buf, len); 139 140 err: 141 if (ret < 0) 142 memset(buf, 0xFF, len); /* Never return undefined value */ 143 return ret; 144 } 145 146 static int wfx_indirect_write(struct wfx_dev *wdev, int reg, u32 addr, 147 const void *buf, size_t len) 148 { 149 int ret; 150 151 WARN_ON(len >= WFX_HIF_BUFFER_SIZE); 152 WARN_ON(reg != WFX_REG_AHB_DPORT && reg != WFX_REG_SRAM_DPORT); 153 ret = wfx_write32(wdev, WFX_REG_BASE_ADDR, addr); 154 if (ret < 0) 155 return ret; 156 157 return wdev->hwbus_ops->copy_to_io(wdev->hwbus_priv, reg, buf, len); 158 } 159 160 static int wfx_indirect_read_locked(struct wfx_dev *wdev, int reg, u32 addr, 161 void *buf, size_t len) 162 { 163 int ret; 164 165 wdev->hwbus_ops->lock(wdev->hwbus_priv); 166 ret = wfx_indirect_read(wdev, reg, addr, buf, len); 167 _trace_io_ind_read(reg, addr, buf, len); 168 wdev->hwbus_ops->unlock(wdev->hwbus_priv); 169 return ret; 170 } 171 172 static int wfx_indirect_write_locked(struct wfx_dev *wdev, int reg, u32 addr, 173 const void *buf, size_t len) 174 { 175 int ret; 176 177 wdev->hwbus_ops->lock(wdev->hwbus_priv); 178 ret = wfx_indirect_write(wdev, reg, addr, buf, len); 179 _trace_io_ind_write(reg, addr, buf, len); 180 wdev->hwbus_ops->unlock(wdev->hwbus_priv); 181 return ret; 182 } 183 184 static int wfx_indirect_read32_locked(struct wfx_dev *wdev, int reg, u32 addr, u32 *val) 185 { 186 int ret; 187 __le32 *tmp = kmalloc(sizeof(u32), GFP_KERNEL); 188 189 if (!tmp) 190 return -ENOMEM; 191 wdev->hwbus_ops->lock(wdev->hwbus_priv); 192 ret = wfx_indirect_read(wdev, reg, addr, tmp, sizeof(u32)); 193 *val = le32_to_cpu(*tmp); 194 _trace_io_ind_read32(reg, addr, *val); 195 wdev->hwbus_ops->unlock(wdev->hwbus_priv); 196 kfree(tmp); 197 return ret; 198 } 199 200 static int wfx_indirect_write32_locked(struct wfx_dev *wdev, int reg, u32 addr, u32 val) 201 { 202 int ret; 203 __le32 *tmp = kmalloc(sizeof(u32), GFP_KERNEL); 204 205 if (!tmp) 206 return -ENOMEM; 207 *tmp = cpu_to_le32(val); 208 wdev->hwbus_ops->lock(wdev->hwbus_priv); 209 ret = wfx_indirect_write(wdev, reg, addr, tmp, sizeof(u32)); 210 _trace_io_ind_write32(reg, addr, val); 211 wdev->hwbus_ops->unlock(wdev->hwbus_priv); 212 kfree(tmp); 213 return ret; 214 } 215 216 int wfx_data_read(struct wfx_dev *wdev, void *buf, size_t len) 217 { 218 int ret; 219 220 WARN(!IS_ALIGNED((uintptr_t)buf, 4), "unaligned buffer"); 221 wdev->hwbus_ops->lock(wdev->hwbus_priv); 222 ret = wdev->hwbus_ops->copy_from_io(wdev->hwbus_priv, WFX_REG_IN_OUT_QUEUE, buf, len); 223 _trace_io_read(WFX_REG_IN_OUT_QUEUE, buf, len); 224 wdev->hwbus_ops->unlock(wdev->hwbus_priv); 225 if (ret) 226 dev_err(wdev->dev, "%s: bus communication error: %d\n", __func__, ret); 227 return ret; 228 } 229 230 int wfx_data_write(struct wfx_dev *wdev, const void *buf, size_t len) 231 { 232 int ret; 233 234 WARN(!IS_ALIGNED((uintptr_t)buf, 4), "unaligned buffer"); 235 wdev->hwbus_ops->lock(wdev->hwbus_priv); 236 ret = wdev->hwbus_ops->copy_to_io(wdev->hwbus_priv, WFX_REG_IN_OUT_QUEUE, buf, len); 237 _trace_io_write(WFX_REG_IN_OUT_QUEUE, buf, len); 238 wdev->hwbus_ops->unlock(wdev->hwbus_priv); 239 if (ret) 240 dev_err(wdev->dev, "%s: bus communication error: %d\n", __func__, ret); 241 return ret; 242 } 243 244 int wfx_sram_buf_read(struct wfx_dev *wdev, u32 addr, void *buf, size_t len) 245 { 246 return wfx_indirect_read_locked(wdev, WFX_REG_SRAM_DPORT, addr, buf, len); 247 } 248 249 int wfx_ahb_buf_read(struct wfx_dev *wdev, u32 addr, void *buf, size_t len) 250 { 251 return wfx_indirect_read_locked(wdev, WFX_REG_AHB_DPORT, addr, buf, len); 252 } 253 254 int wfx_sram_buf_write(struct wfx_dev *wdev, u32 addr, const void *buf, size_t len) 255 { 256 return wfx_indirect_write_locked(wdev, WFX_REG_SRAM_DPORT, addr, buf, len); 257 } 258 259 int wfx_ahb_buf_write(struct wfx_dev *wdev, u32 addr, const void *buf, size_t len) 260 { 261 return wfx_indirect_write_locked(wdev, WFX_REG_AHB_DPORT, addr, buf, len); 262 } 263 264 int wfx_sram_reg_read(struct wfx_dev *wdev, u32 addr, u32 *val) 265 { 266 return wfx_indirect_read32_locked(wdev, WFX_REG_SRAM_DPORT, addr, val); 267 } 268 269 int wfx_ahb_reg_read(struct wfx_dev *wdev, u32 addr, u32 *val) 270 { 271 return wfx_indirect_read32_locked(wdev, WFX_REG_AHB_DPORT, addr, val); 272 } 273 274 int wfx_sram_reg_write(struct wfx_dev *wdev, u32 addr, u32 val) 275 { 276 return wfx_indirect_write32_locked(wdev, WFX_REG_SRAM_DPORT, addr, val); 277 } 278 279 int wfx_ahb_reg_write(struct wfx_dev *wdev, u32 addr, u32 val) 280 { 281 return wfx_indirect_write32_locked(wdev, WFX_REG_AHB_DPORT, addr, val); 282 } 283 284 int wfx_config_reg_read(struct wfx_dev *wdev, u32 *val) 285 { 286 return wfx_read32_locked(wdev, WFX_REG_CONFIG, val); 287 } 288 289 int wfx_config_reg_write(struct wfx_dev *wdev, u32 val) 290 { 291 return wfx_write32_locked(wdev, WFX_REG_CONFIG, val); 292 } 293 294 int wfx_config_reg_write_bits(struct wfx_dev *wdev, u32 mask, u32 val) 295 { 296 return wfx_write32_bits_locked(wdev, WFX_REG_CONFIG, mask, val); 297 } 298 299 int wfx_control_reg_read(struct wfx_dev *wdev, u32 *val) 300 { 301 return wfx_read32_locked(wdev, WFX_REG_CONTROL, val); 302 } 303 304 int wfx_control_reg_write(struct wfx_dev *wdev, u32 val) 305 { 306 return wfx_write32_locked(wdev, WFX_REG_CONTROL, val); 307 } 308 309 int wfx_control_reg_write_bits(struct wfx_dev *wdev, u32 mask, u32 val) 310 { 311 return wfx_write32_bits_locked(wdev, WFX_REG_CONTROL, mask, val); 312 } 313 314 int wfx_igpr_reg_read(struct wfx_dev *wdev, int index, u32 *val) 315 { 316 int ret; 317 318 *val = ~0; /* Never return undefined value */ 319 ret = wfx_write32_locked(wdev, WFX_REG_SET_GEN_R_W, IGPR_RW | index << 24); 320 if (ret) 321 return ret; 322 ret = wfx_read32_locked(wdev, WFX_REG_SET_GEN_R_W, val); 323 if (ret) 324 return ret; 325 *val &= IGPR_VALUE; 326 return ret; 327 } 328 329 int wfx_igpr_reg_write(struct wfx_dev *wdev, int index, u32 val) 330 { 331 return wfx_write32_locked(wdev, WFX_REG_SET_GEN_R_W, index << 24 | val); 332 } 333