linux/drivers/staging/wfx/hwio.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Low-level I/O functions.
   4 *
   5 * Copyright (c) 2017-2019, 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
  12#include "hwio.h"
  13#include "wfx.h"
  14#include "bus.h"
  15#include "traces.h"
  16
  17/*
  18 * Internal helpers.
  19 *
  20 * About CONFIG_VMAP_STACK:
  21 * When CONFIG_VMAP_STACK is enabled, it is not possible to run DMA on stack
  22 * allocated data. Functions below that work with registers (aka functions
  23 * ending with "32") automatically reallocate buffers with kmalloc. However,
  24 * functions that work with arbitrary length buffers let's caller to handle
  25 * memory location. In doubt, enable CONFIG_DEBUG_SG to detect badly located
  26 * buffer.
  27 */
  28
  29static int read32(struct wfx_dev *wdev, int reg, u32 *val)
  30{
  31        int ret;
  32        __le32 *tmp = kmalloc(sizeof(u32), GFP_KERNEL);
  33
  34        *val = ~0; // Never return undefined value
  35        if (!tmp)
  36                return -ENOMEM;
  37        ret = wdev->hwbus_ops->copy_from_io(wdev->hwbus_priv, reg, tmp,
  38                                            sizeof(u32));
  39        if (ret >= 0)
  40                *val = le32_to_cpu(*tmp);
  41        kfree(tmp);
  42        if (ret)
  43                dev_err(wdev->dev, "%s: bus communication error: %d\n",
  44                        __func__, ret);
  45        return ret;
  46}
  47
  48static int write32(struct wfx_dev *wdev, int reg, u32 val)
  49{
  50        int ret;
  51        __le32 *tmp = kmalloc(sizeof(u32), GFP_KERNEL);
  52
  53        if (!tmp)
  54                return -ENOMEM;
  55        *tmp = cpu_to_le32(val);
  56        ret = wdev->hwbus_ops->copy_to_io(wdev->hwbus_priv, reg, tmp,
  57                                          sizeof(u32));
  58        kfree(tmp);
  59        if (ret)
  60                dev_err(wdev->dev, "%s: bus communication error: %d\n",
  61                        __func__, ret);
  62        return ret;
  63}
  64
  65static int read32_locked(struct wfx_dev *wdev, int reg, u32 *val)
  66{
  67        int ret;
  68
  69        wdev->hwbus_ops->lock(wdev->hwbus_priv);
  70        ret = read32(wdev, reg, val);
  71        _trace_io_read32(reg, *val);
  72        wdev->hwbus_ops->unlock(wdev->hwbus_priv);
  73        return ret;
  74}
  75
  76static int write32_locked(struct wfx_dev *wdev, int reg, u32 val)
  77{
  78        int ret;
  79
  80        wdev->hwbus_ops->lock(wdev->hwbus_priv);
  81        ret = write32(wdev, reg, val);
  82        _trace_io_write32(reg, val);
  83        wdev->hwbus_ops->unlock(wdev->hwbus_priv);
  84        return ret;
  85}
  86
  87static int write32_bits_locked(struct wfx_dev *wdev, int reg, u32 mask, u32 val)
  88{
  89        int ret;
  90        u32 val_r, val_w;
  91
  92        WARN_ON(~mask & val);
  93        val &= mask;
  94        wdev->hwbus_ops->lock(wdev->hwbus_priv);
  95        ret = read32(wdev, reg, &val_r);
  96        _trace_io_read32(reg, val_r);
  97        if (ret < 0)
  98                goto err;
  99        val_w = (val_r & ~mask) | val;
 100        if (val_w != val_r) {
 101                ret = write32(wdev, reg, val_w);
 102                _trace_io_write32(reg, val_w);
 103        }
 104err:
 105        wdev->hwbus_ops->unlock(wdev->hwbus_priv);
 106        return ret;
 107}
 108
 109static int indirect_read(struct wfx_dev *wdev, int reg, u32 addr, void *buf,
 110                         size_t len)
 111{
 112        int ret;
 113        int i;
 114        u32 cfg;
 115        u32 prefetch;
 116
 117        WARN_ON(len >= 0x2000);
 118        WARN_ON(reg != WFX_REG_AHB_DPORT && reg != WFX_REG_SRAM_DPORT);
 119
 120        if (reg == WFX_REG_AHB_DPORT)
 121                prefetch = CFG_PREFETCH_AHB;
 122        else if (reg == WFX_REG_SRAM_DPORT)
 123                prefetch = CFG_PREFETCH_SRAM;
 124        else
 125                return -ENODEV;
 126
 127        ret = write32(wdev, WFX_REG_BASE_ADDR, addr);
 128        if (ret < 0)
 129                goto err;
 130
 131        ret = read32(wdev, WFX_REG_CONFIG, &cfg);
 132        if (ret < 0)
 133                goto err;
 134
 135        ret = write32(wdev, WFX_REG_CONFIG, cfg | prefetch);
 136        if (ret < 0)
 137                goto err;
 138
 139        for (i = 0; i < 20; i++) {
 140                ret = read32(wdev, WFX_REG_CONFIG, &cfg);
 141                if (ret < 0)
 142                        goto err;
 143                if (!(cfg & prefetch))
 144                        break;
 145                udelay(200);
 146        }
 147        if (i == 20) {
 148                ret = -ETIMEDOUT;
 149                goto err;
 150        }
 151
 152        ret = wdev->hwbus_ops->copy_from_io(wdev->hwbus_priv, reg, buf, len);
 153
 154err:
 155        if (ret < 0)
 156                memset(buf, 0xFF, len); // Never return undefined value
 157        return ret;
 158}
 159
 160static int indirect_write(struct wfx_dev *wdev, int reg, u32 addr,
 161                          const void *buf, size_t len)
 162{
 163        int ret;
 164
 165        WARN_ON(len >= 0x2000);
 166        WARN_ON(reg != WFX_REG_AHB_DPORT && reg != WFX_REG_SRAM_DPORT);
 167        ret = write32(wdev, WFX_REG_BASE_ADDR, addr);
 168        if (ret < 0)
 169                return ret;
 170
 171        return wdev->hwbus_ops->copy_to_io(wdev->hwbus_priv, reg, buf, len);
 172}
 173
 174static int indirect_read_locked(struct wfx_dev *wdev, int reg, u32 addr,
 175                                void *buf, size_t len)
 176{
 177        int ret;
 178
 179        wdev->hwbus_ops->lock(wdev->hwbus_priv);
 180        ret = indirect_read(wdev, reg, addr, buf, len);
 181        _trace_io_ind_read(reg, addr, buf, len);
 182        wdev->hwbus_ops->unlock(wdev->hwbus_priv);
 183        return ret;
 184}
 185
 186static int indirect_write_locked(struct wfx_dev *wdev, int reg, u32 addr,
 187                                 const void *buf, size_t len)
 188{
 189        int ret;
 190
 191        wdev->hwbus_ops->lock(wdev->hwbus_priv);
 192        ret = indirect_write(wdev, reg, addr, buf, len);
 193        _trace_io_ind_write(reg, addr, buf, len);
 194        wdev->hwbus_ops->unlock(wdev->hwbus_priv);
 195        return ret;
 196}
 197
 198static int indirect_read32_locked(struct wfx_dev *wdev, int reg, u32 addr,
 199                                  u32 *val)
 200{
 201        int ret;
 202        __le32 *tmp = kmalloc(sizeof(u32), GFP_KERNEL);
 203
 204        if (!tmp)
 205                return -ENOMEM;
 206        wdev->hwbus_ops->lock(wdev->hwbus_priv);
 207        ret = indirect_read(wdev, reg, addr, tmp, sizeof(u32));
 208        *val = cpu_to_le32(*tmp);
 209        _trace_io_ind_read32(reg, addr, *val);
 210        wdev->hwbus_ops->unlock(wdev->hwbus_priv);
 211        kfree(tmp);
 212        return ret;
 213}
 214
 215static int indirect_write32_locked(struct wfx_dev *wdev, int reg, u32 addr,
 216                                   u32 val)
 217{
 218        int ret;
 219        __le32 *tmp = kmalloc(sizeof(u32), GFP_KERNEL);
 220
 221        if (!tmp)
 222                return -ENOMEM;
 223        *tmp = cpu_to_le32(val);
 224        wdev->hwbus_ops->lock(wdev->hwbus_priv);
 225        ret = indirect_write(wdev, reg, addr, tmp, sizeof(u32));
 226        _trace_io_ind_write32(reg, addr, val);
 227        wdev->hwbus_ops->unlock(wdev->hwbus_priv);
 228        kfree(tmp);
 229        return ret;
 230}
 231
 232int wfx_data_read(struct wfx_dev *wdev, void *buf, size_t len)
 233{
 234        int ret;
 235
 236        WARN((long) buf & 3, "%s: unaligned buffer", __func__);
 237        wdev->hwbus_ops->lock(wdev->hwbus_priv);
 238        ret = wdev->hwbus_ops->copy_from_io(wdev->hwbus_priv,
 239                                            WFX_REG_IN_OUT_QUEUE, buf, len);
 240        _trace_io_read(WFX_REG_IN_OUT_QUEUE, buf, len);
 241        wdev->hwbus_ops->unlock(wdev->hwbus_priv);
 242        if (ret)
 243                dev_err(wdev->dev, "%s: bus communication error: %d\n",
 244                        __func__, ret);
 245        return ret;
 246}
 247
 248int wfx_data_write(struct wfx_dev *wdev, const void *buf, size_t len)
 249{
 250        int ret;
 251
 252        WARN((long) buf & 3, "%s: unaligned buffer", __func__);
 253        wdev->hwbus_ops->lock(wdev->hwbus_priv);
 254        ret = wdev->hwbus_ops->copy_to_io(wdev->hwbus_priv,
 255                                          WFX_REG_IN_OUT_QUEUE, buf, len);
 256        _trace_io_write(WFX_REG_IN_OUT_QUEUE, buf, len);
 257        wdev->hwbus_ops->unlock(wdev->hwbus_priv);
 258        if (ret)
 259                dev_err(wdev->dev, "%s: bus communication error: %d\n",
 260                        __func__, ret);
 261        return ret;
 262}
 263
 264int sram_buf_read(struct wfx_dev *wdev, u32 addr, void *buf, size_t len)
 265{
 266        return indirect_read_locked(wdev, WFX_REG_SRAM_DPORT, addr, buf, len);
 267}
 268
 269int ahb_buf_read(struct wfx_dev *wdev, u32 addr, void *buf, size_t len)
 270{
 271        return indirect_read_locked(wdev, WFX_REG_AHB_DPORT, addr, buf, len);
 272}
 273
 274int sram_buf_write(struct wfx_dev *wdev, u32 addr, const void *buf, size_t len)
 275{
 276        return indirect_write_locked(wdev, WFX_REG_SRAM_DPORT, addr, buf, len);
 277}
 278
 279int ahb_buf_write(struct wfx_dev *wdev, u32 addr, const void *buf, size_t len)
 280{
 281        return indirect_write_locked(wdev, WFX_REG_AHB_DPORT, addr, buf, len);
 282}
 283
 284int sram_reg_read(struct wfx_dev *wdev, u32 addr, u32 *val)
 285{
 286        return indirect_read32_locked(wdev, WFX_REG_SRAM_DPORT, addr, val);
 287}
 288
 289int ahb_reg_read(struct wfx_dev *wdev, u32 addr, u32 *val)
 290{
 291        return indirect_read32_locked(wdev, WFX_REG_AHB_DPORT, addr, val);
 292}
 293
 294int sram_reg_write(struct wfx_dev *wdev, u32 addr, u32 val)
 295{
 296        return indirect_write32_locked(wdev, WFX_REG_SRAM_DPORT, addr, val);
 297}
 298
 299int ahb_reg_write(struct wfx_dev *wdev, u32 addr, u32 val)
 300{
 301        return indirect_write32_locked(wdev, WFX_REG_AHB_DPORT, addr, val);
 302}
 303
 304int config_reg_read(struct wfx_dev *wdev, u32 *val)
 305{
 306        return read32_locked(wdev, WFX_REG_CONFIG, val);
 307}
 308
 309int config_reg_write(struct wfx_dev *wdev, u32 val)
 310{
 311        return write32_locked(wdev, WFX_REG_CONFIG, val);
 312}
 313
 314int config_reg_write_bits(struct wfx_dev *wdev, u32 mask, u32 val)
 315{
 316        return write32_bits_locked(wdev, WFX_REG_CONFIG, mask, val);
 317}
 318
 319int control_reg_read(struct wfx_dev *wdev, u32 *val)
 320{
 321        return read32_locked(wdev, WFX_REG_CONTROL, val);
 322}
 323
 324int control_reg_write(struct wfx_dev *wdev, u32 val)
 325{
 326        return write32_locked(wdev, WFX_REG_CONTROL, val);
 327}
 328
 329int control_reg_write_bits(struct wfx_dev *wdev, u32 mask, u32 val)
 330{
 331        return write32_bits_locked(wdev, WFX_REG_CONTROL, mask, val);
 332}
 333
 334int igpr_reg_read(struct wfx_dev *wdev, int index, u32 *val)
 335{
 336        int ret;
 337
 338        *val = ~0; // Never return undefined value
 339        ret = write32_locked(wdev, WFX_REG_SET_GEN_R_W, IGPR_RW | index << 24);
 340        if (ret)
 341                return ret;
 342        ret = read32_locked(wdev, WFX_REG_SET_GEN_R_W, val);
 343        if (ret)
 344                return ret;
 345        *val &= IGPR_VALUE;
 346        return ret;
 347}
 348
 349int igpr_reg_write(struct wfx_dev *wdev, int index, u32 val)
 350{
 351        return write32_locked(wdev, WFX_REG_SET_GEN_R_W, index << 24 | val);
 352}
 353