Author | Tokens | Token Proportion | Commits | Commit Proportion |
---|---|---|---|---|
Jérôme Pouiller | 1926 | 99.38% | 8 | 80.00% |
Greg Kroah-Hartman | 9 | 0.46% | 1 | 10.00% |
Michał Mirosław | 3 | 0.15% | 1 | 10.00% |
Total | 1938 | 10 |
// SPDX-License-Identifier: GPL-2.0-only /* * Low-level I/O functions. * * Copyright (c) 2017-2020, Silicon Laboratories, Inc. * Copyright (c) 2010, ST-Ericsson */ #include <linux/kernel.h> #include <linux/delay.h> #include <linux/slab.h> #include <linux/align.h> #include "hwio.h" #include "wfx.h" #include "bus.h" #include "traces.h" #define WFX_HIF_BUFFER_SIZE 0x2000 static int wfx_read32(struct wfx_dev *wdev, int reg, u32 *val) { int ret; __le32 *tmp = kmalloc(sizeof(u32), GFP_KERNEL); *val = ~0; /* Never return undefined value */ if (!tmp) return -ENOMEM; ret = wdev->hwbus_ops->copy_from_io(wdev->hwbus_priv, reg, tmp, sizeof(u32)); if (ret >= 0) *val = le32_to_cpu(*tmp); kfree(tmp); if (ret) dev_err(wdev->dev, "%s: bus communication error: %d\n", __func__, ret); return ret; } static int wfx_write32(struct wfx_dev *wdev, int reg, u32 val) { int ret; __le32 *tmp = kmalloc(sizeof(u32), GFP_KERNEL); if (!tmp) return -ENOMEM; *tmp = cpu_to_le32(val); ret = wdev->hwbus_ops->copy_to_io(wdev->hwbus_priv, reg, tmp, sizeof(u32)); kfree(tmp); if (ret) dev_err(wdev->dev, "%s: bus communication error: %d\n", __func__, ret); return ret; } static int wfx_read32_locked(struct wfx_dev *wdev, int reg, u32 *val) { int ret; wdev->hwbus_ops->lock(wdev->hwbus_priv); ret = wfx_read32(wdev, reg, val); _trace_io_read32(reg, *val); wdev->hwbus_ops->unlock(wdev->hwbus_priv); return ret; } static int wfx_write32_locked(struct wfx_dev *wdev, int reg, u32 val) { int ret; wdev->hwbus_ops->lock(wdev->hwbus_priv); ret = wfx_write32(wdev, reg, val); _trace_io_write32(reg, val); wdev->hwbus_ops->unlock(wdev->hwbus_priv); return ret; } static int wfx_write32_bits_locked(struct wfx_dev *wdev, int reg, u32 mask, u32 val) { int ret; u32 val_r, val_w; WARN_ON(~mask & val); val &= mask; wdev->hwbus_ops->lock(wdev->hwbus_priv); ret = wfx_read32(wdev, reg, &val_r); _trace_io_read32(reg, val_r); if (ret < 0) goto err; val_w = (val_r & ~mask) | val; if (val_w != val_r) { ret = wfx_write32(wdev, reg, val_w); _trace_io_write32(reg, val_w); } err: wdev->hwbus_ops->unlock(wdev->hwbus_priv); return ret; } static int wfx_indirect_read(struct wfx_dev *wdev, int reg, u32 addr, void *buf, size_t len) { int ret; int i; u32 cfg; u32 prefetch; WARN_ON(len >= WFX_HIF_BUFFER_SIZE); WARN_ON(reg != WFX_REG_AHB_DPORT && reg != WFX_REG_SRAM_DPORT); if (reg == WFX_REG_AHB_DPORT) prefetch = CFG_PREFETCH_AHB; else if (reg == WFX_REG_SRAM_DPORT) prefetch = CFG_PREFETCH_SRAM; else return -ENODEV; ret = wfx_write32(wdev, WFX_REG_BASE_ADDR, addr); if (ret < 0) goto err; ret = wfx_read32(wdev, WFX_REG_CONFIG, &cfg); if (ret < 0) goto err; ret = wfx_write32(wdev, WFX_REG_CONFIG, cfg | prefetch); if (ret < 0) goto err; for (i = 0; i < 20; i++) { ret = wfx_read32(wdev, WFX_REG_CONFIG, &cfg); if (ret < 0) goto err; if (!(cfg & prefetch)) break; usleep_range(200, 250); } if (i == 20) { ret = -ETIMEDOUT; goto err; } ret = wdev->hwbus_ops->copy_from_io(wdev->hwbus_priv, reg, buf, len); err: if (ret < 0) memset(buf, 0xFF, len); /* Never return undefined value */ return ret; } static int wfx_indirect_write(struct wfx_dev *wdev, int reg, u32 addr, const void *buf, size_t len) { int ret; WARN_ON(len >= WFX_HIF_BUFFER_SIZE); WARN_ON(reg != WFX_REG_AHB_DPORT && reg != WFX_REG_SRAM_DPORT); ret = wfx_write32(wdev, WFX_REG_BASE_ADDR, addr); if (ret < 0) return ret; return wdev->hwbus_ops->copy_to_io(wdev->hwbus_priv, reg, buf, len); } static int wfx_indirect_read_locked(struct wfx_dev *wdev, int reg, u32 addr, void *buf, size_t len) { int ret; wdev->hwbus_ops->lock(wdev->hwbus_priv); ret = wfx_indirect_read(wdev, reg, addr, buf, len); _trace_io_ind_read(reg, addr, buf, len); wdev->hwbus_ops->unlock(wdev->hwbus_priv); return ret; } static int wfx_indirect_write_locked(struct wfx_dev *wdev, int reg, u32 addr, const void *buf, size_t len) { int ret; wdev->hwbus_ops->lock(wdev->hwbus_priv); ret = wfx_indirect_write(wdev, reg, addr, buf, len); _trace_io_ind_write(reg, addr, buf, len); wdev->hwbus_ops->unlock(wdev->hwbus_priv); return ret; } static int wfx_indirect_read32_locked(struct wfx_dev *wdev, int reg, u32 addr, u32 *val) { int ret; __le32 *tmp = kmalloc(sizeof(u32), GFP_KERNEL); if (!tmp) return -ENOMEM; wdev->hwbus_ops->lock(wdev->hwbus_priv); ret = wfx_indirect_read(wdev, reg, addr, tmp, sizeof(u32)); *val = le32_to_cpu(*tmp); _trace_io_ind_read32(reg, addr, *val); wdev->hwbus_ops->unlock(wdev->hwbus_priv); kfree(tmp); return ret; } static int wfx_indirect_write32_locked(struct wfx_dev *wdev, int reg, u32 addr, u32 val) { int ret; __le32 *tmp = kmalloc(sizeof(u32), GFP_KERNEL); if (!tmp) return -ENOMEM; *tmp = cpu_to_le32(val); wdev->hwbus_ops->lock(wdev->hwbus_priv); ret = wfx_indirect_write(wdev, reg, addr, tmp, sizeof(u32)); _trace_io_ind_write32(reg, addr, val); wdev->hwbus_ops->unlock(wdev->hwbus_priv); kfree(tmp); return ret; } int wfx_data_read(struct wfx_dev *wdev, void *buf, size_t len) { int ret; WARN(!IS_ALIGNED((uintptr_t)buf, 4), "unaligned buffer"); wdev->hwbus_ops->lock(wdev->hwbus_priv); ret = wdev->hwbus_ops->copy_from_io(wdev->hwbus_priv, WFX_REG_IN_OUT_QUEUE, buf, len); _trace_io_read(WFX_REG_IN_OUT_QUEUE, buf, len); wdev->hwbus_ops->unlock(wdev->hwbus_priv); if (ret) dev_err(wdev->dev, "%s: bus communication error: %d\n", __func__, ret); return ret; } int wfx_data_write(struct wfx_dev *wdev, const void *buf, size_t len) { int ret; WARN(!IS_ALIGNED((uintptr_t)buf, 4), "unaligned buffer"); wdev->hwbus_ops->lock(wdev->hwbus_priv); ret = wdev->hwbus_ops->copy_to_io(wdev->hwbus_priv, WFX_REG_IN_OUT_QUEUE, buf, len); _trace_io_write(WFX_REG_IN_OUT_QUEUE, buf, len); wdev->hwbus_ops->unlock(wdev->hwbus_priv); if (ret) dev_err(wdev->dev, "%s: bus communication error: %d\n", __func__, ret); return ret; } int wfx_sram_buf_read(struct wfx_dev *wdev, u32 addr, void *buf, size_t len) { return wfx_indirect_read_locked(wdev, WFX_REG_SRAM_DPORT, addr, buf, len); } int wfx_ahb_buf_read(struct wfx_dev *wdev, u32 addr, void *buf, size_t len) { return wfx_indirect_read_locked(wdev, WFX_REG_AHB_DPORT, addr, buf, len); } int wfx_sram_buf_write(struct wfx_dev *wdev, u32 addr, const void *buf, size_t len) { return wfx_indirect_write_locked(wdev, WFX_REG_SRAM_DPORT, addr, buf, len); } int wfx_ahb_buf_write(struct wfx_dev *wdev, u32 addr, const void *buf, size_t len) { return wfx_indirect_write_locked(wdev, WFX_REG_AHB_DPORT, addr, buf, len); } int wfx_sram_reg_read(struct wfx_dev *wdev, u32 addr, u32 *val) { return wfx_indirect_read32_locked(wdev, WFX_REG_SRAM_DPORT, addr, val); } int wfx_ahb_reg_read(struct wfx_dev *wdev, u32 addr, u32 *val) { return wfx_indirect_read32_locked(wdev, WFX_REG_AHB_DPORT, addr, val); } int wfx_sram_reg_write(struct wfx_dev *wdev, u32 addr, u32 val) { return wfx_indirect_write32_locked(wdev, WFX_REG_SRAM_DPORT, addr, val); } int wfx_ahb_reg_write(struct wfx_dev *wdev, u32 addr, u32 val) { return wfx_indirect_write32_locked(wdev, WFX_REG_AHB_DPORT, addr, val); } int wfx_config_reg_read(struct wfx_dev *wdev, u32 *val) { return wfx_read32_locked(wdev, WFX_REG_CONFIG, val); } int wfx_config_reg_write(struct wfx_dev *wdev, u32 val) { return wfx_write32_locked(wdev, WFX_REG_CONFIG, val); } int wfx_config_reg_write_bits(struct wfx_dev *wdev, u32 mask, u32 val) { return wfx_write32_bits_locked(wdev, WFX_REG_CONFIG, mask, val); } int wfx_control_reg_read(struct wfx_dev *wdev, u32 *val) { return wfx_read32_locked(wdev, WFX_REG_CONTROL, val); } int wfx_control_reg_write(struct wfx_dev *wdev, u32 val) { return wfx_write32_locked(wdev, WFX_REG_CONTROL, val); } int wfx_control_reg_write_bits(struct wfx_dev *wdev, u32 mask, u32 val) { return wfx_write32_bits_locked(wdev, WFX_REG_CONTROL, mask, val); } int wfx_igpr_reg_read(struct wfx_dev *wdev, int index, u32 *val) { int ret; *val = ~0; /* Never return undefined value */ ret = wfx_write32_locked(wdev, WFX_REG_SET_GEN_R_W, IGPR_RW | index << 24); if (ret) return ret; ret = wfx_read32_locked(wdev, WFX_REG_SET_GEN_R_W, val); if (ret) return ret; *val &= IGPR_VALUE; return ret; } int wfx_igpr_reg_write(struct wfx_dev *wdev, int index, u32 val) { return wfx_write32_locked(wdev, WFX_REG_SET_GEN_R_W, index << 24 | val); }
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with Cregit http://github.com/cregit/cregit
Version 2.0-RC1