hwio.c (8438B)
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 20static 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 37static 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 52static 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 63static 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 74static 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 } 91err: 92 wdev->hwbus_ops->unlock(wdev->hwbus_priv); 93 return ret; 94} 95 96static 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 140err: 141 if (ret < 0) 142 memset(buf, 0xFF, len); /* Never return undefined value */ 143 return ret; 144} 145 146static 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 160static 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 172static 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 184static 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 200static 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 216int 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 230int 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 244int 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 249int 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 254int 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 259int 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 264int 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 269int 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 274int 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 279int 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 284int wfx_config_reg_read(struct wfx_dev *wdev, u32 *val) 285{ 286 return wfx_read32_locked(wdev, WFX_REG_CONFIG, val); 287} 288 289int wfx_config_reg_write(struct wfx_dev *wdev, u32 val) 290{ 291 return wfx_write32_locked(wdev, WFX_REG_CONFIG, val); 292} 293 294int 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 299int wfx_control_reg_read(struct wfx_dev *wdev, u32 *val) 300{ 301 return wfx_read32_locked(wdev, WFX_REG_CONTROL, val); 302} 303 304int wfx_control_reg_write(struct wfx_dev *wdev, u32 val) 305{ 306 return wfx_write32_locked(wdev, WFX_REG_CONTROL, val); 307} 308 309int 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 314int 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 329int 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}