162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * This file is part of wl12xx 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2008 Nokia Corporation 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include "wl1251.h" 962306a36Sopenharmony_ci#include "reg.h" 1062306a36Sopenharmony_ci#include "io.h" 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci/* FIXME: this is static data nowadays and the table can be removed */ 1362306a36Sopenharmony_cistatic enum wl12xx_acx_int_reg wl1251_io_reg_table[ACX_REG_TABLE_LEN] = { 1462306a36Sopenharmony_ci [ACX_REG_INTERRUPT_TRIG] = (REGISTERS_BASE + 0x0474), 1562306a36Sopenharmony_ci [ACX_REG_INTERRUPT_TRIG_H] = (REGISTERS_BASE + 0x0478), 1662306a36Sopenharmony_ci [ACX_REG_INTERRUPT_MASK] = (REGISTERS_BASE + 0x0494), 1762306a36Sopenharmony_ci [ACX_REG_HINT_MASK_SET] = (REGISTERS_BASE + 0x0498), 1862306a36Sopenharmony_ci [ACX_REG_HINT_MASK_CLR] = (REGISTERS_BASE + 0x049C), 1962306a36Sopenharmony_ci [ACX_REG_INTERRUPT_NO_CLEAR] = (REGISTERS_BASE + 0x04B0), 2062306a36Sopenharmony_ci [ACX_REG_INTERRUPT_CLEAR] = (REGISTERS_BASE + 0x04A4), 2162306a36Sopenharmony_ci [ACX_REG_INTERRUPT_ACK] = (REGISTERS_BASE + 0x04A8), 2262306a36Sopenharmony_ci [ACX_REG_SLV_SOFT_RESET] = (REGISTERS_BASE + 0x0000), 2362306a36Sopenharmony_ci [ACX_REG_EE_START] = (REGISTERS_BASE + 0x080C), 2462306a36Sopenharmony_ci [ACX_REG_ECPU_CONTROL] = (REGISTERS_BASE + 0x0804) 2562306a36Sopenharmony_ci}; 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_cistatic int wl1251_translate_reg_addr(struct wl1251 *wl, int addr) 2862306a36Sopenharmony_ci{ 2962306a36Sopenharmony_ci /* If the address is lower than REGISTERS_BASE, it means that this is 3062306a36Sopenharmony_ci * a chip-specific register address, so look it up in the registers 3162306a36Sopenharmony_ci * table */ 3262306a36Sopenharmony_ci if (addr < REGISTERS_BASE) { 3362306a36Sopenharmony_ci /* Make sure we don't go over the table */ 3462306a36Sopenharmony_ci if (addr >= ACX_REG_TABLE_LEN) { 3562306a36Sopenharmony_ci wl1251_error("address out of range (%d)", addr); 3662306a36Sopenharmony_ci return -EINVAL; 3762306a36Sopenharmony_ci } 3862306a36Sopenharmony_ci addr = wl1251_io_reg_table[addr]; 3962306a36Sopenharmony_ci } 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci return addr - wl->physical_reg_addr + wl->virtual_reg_addr; 4262306a36Sopenharmony_ci} 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_cistatic int wl1251_translate_mem_addr(struct wl1251 *wl, int addr) 4562306a36Sopenharmony_ci{ 4662306a36Sopenharmony_ci return addr - wl->physical_mem_addr + wl->virtual_mem_addr; 4762306a36Sopenharmony_ci} 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_civoid wl1251_mem_read(struct wl1251 *wl, int addr, void *buf, size_t len) 5062306a36Sopenharmony_ci{ 5162306a36Sopenharmony_ci int physical; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci physical = wl1251_translate_mem_addr(wl, addr); 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci wl->if_ops->read(wl, physical, buf, len); 5662306a36Sopenharmony_ci} 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_civoid wl1251_mem_write(struct wl1251 *wl, int addr, void *buf, size_t len) 5962306a36Sopenharmony_ci{ 6062306a36Sopenharmony_ci int physical; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci physical = wl1251_translate_mem_addr(wl, addr); 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci wl->if_ops->write(wl, physical, buf, len); 6562306a36Sopenharmony_ci} 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ciu32 wl1251_mem_read32(struct wl1251 *wl, int addr) 6862306a36Sopenharmony_ci{ 6962306a36Sopenharmony_ci return wl1251_read32(wl, wl1251_translate_mem_addr(wl, addr)); 7062306a36Sopenharmony_ci} 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_civoid wl1251_mem_write32(struct wl1251 *wl, int addr, u32 val) 7362306a36Sopenharmony_ci{ 7462306a36Sopenharmony_ci wl1251_write32(wl, wl1251_translate_mem_addr(wl, addr), val); 7562306a36Sopenharmony_ci} 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ciu32 wl1251_reg_read32(struct wl1251 *wl, int addr) 7862306a36Sopenharmony_ci{ 7962306a36Sopenharmony_ci return wl1251_read32(wl, wl1251_translate_reg_addr(wl, addr)); 8062306a36Sopenharmony_ci} 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_civoid wl1251_reg_write32(struct wl1251 *wl, int addr, u32 val) 8362306a36Sopenharmony_ci{ 8462306a36Sopenharmony_ci wl1251_write32(wl, wl1251_translate_reg_addr(wl, addr), val); 8562306a36Sopenharmony_ci} 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci/* Set the partitions to access the chip addresses. 8862306a36Sopenharmony_ci * 8962306a36Sopenharmony_ci * There are two VIRTUAL partitions (the memory partition and the 9062306a36Sopenharmony_ci * registers partition), which are mapped to two different areas of the 9162306a36Sopenharmony_ci * PHYSICAL (hardware) memory. This function also makes other checks to 9262306a36Sopenharmony_ci * ensure that the partitions are not overlapping. In the diagram below, the 9362306a36Sopenharmony_ci * memory partition comes before the register partition, but the opposite is 9462306a36Sopenharmony_ci * also supported. 9562306a36Sopenharmony_ci * 9662306a36Sopenharmony_ci * PHYSICAL address 9762306a36Sopenharmony_ci * space 9862306a36Sopenharmony_ci * 9962306a36Sopenharmony_ci * | | 10062306a36Sopenharmony_ci * ...+----+--> mem_start 10162306a36Sopenharmony_ci * VIRTUAL address ... | | 10262306a36Sopenharmony_ci * space ... | | [PART_0] 10362306a36Sopenharmony_ci * ... | | 10462306a36Sopenharmony_ci * 0x00000000 <--+----+... ...+----+--> mem_start + mem_size 10562306a36Sopenharmony_ci * | | ... | | 10662306a36Sopenharmony_ci * |MEM | ... | | 10762306a36Sopenharmony_ci * | | ... | | 10862306a36Sopenharmony_ci * part_size <--+----+... | | {unused area) 10962306a36Sopenharmony_ci * | | ... | | 11062306a36Sopenharmony_ci * |REG | ... | | 11162306a36Sopenharmony_ci * part_size | | ... | | 11262306a36Sopenharmony_ci * + <--+----+... ...+----+--> reg_start 11362306a36Sopenharmony_ci * reg_size ... | | 11462306a36Sopenharmony_ci * ... | | [PART_1] 11562306a36Sopenharmony_ci * ... | | 11662306a36Sopenharmony_ci * ...+----+--> reg_start + reg_size 11762306a36Sopenharmony_ci * | | 11862306a36Sopenharmony_ci * 11962306a36Sopenharmony_ci */ 12062306a36Sopenharmony_civoid wl1251_set_partition(struct wl1251 *wl, 12162306a36Sopenharmony_ci u32 mem_start, u32 mem_size, 12262306a36Sopenharmony_ci u32 reg_start, u32 reg_size) 12362306a36Sopenharmony_ci{ 12462306a36Sopenharmony_ci struct wl1251_partition_set *partition; 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci partition = kmalloc(sizeof(*partition), GFP_KERNEL); 12762306a36Sopenharmony_ci if (!partition) { 12862306a36Sopenharmony_ci wl1251_error("can not allocate partition buffer"); 12962306a36Sopenharmony_ci return; 13062306a36Sopenharmony_ci } 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci wl1251_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", 13362306a36Sopenharmony_ci mem_start, mem_size); 13462306a36Sopenharmony_ci wl1251_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", 13562306a36Sopenharmony_ci reg_start, reg_size); 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci /* Make sure that the two partitions together don't exceed the 13862306a36Sopenharmony_ci * address range */ 13962306a36Sopenharmony_ci if ((mem_size + reg_size) > HW_ACCESS_MEMORY_MAX_RANGE) { 14062306a36Sopenharmony_ci wl1251_debug(DEBUG_SPI, "Total size exceeds maximum virtual" 14162306a36Sopenharmony_ci " address range. Truncating partition[0]."); 14262306a36Sopenharmony_ci mem_size = HW_ACCESS_MEMORY_MAX_RANGE - reg_size; 14362306a36Sopenharmony_ci wl1251_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", 14462306a36Sopenharmony_ci mem_start, mem_size); 14562306a36Sopenharmony_ci wl1251_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", 14662306a36Sopenharmony_ci reg_start, reg_size); 14762306a36Sopenharmony_ci } 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci if ((mem_start < reg_start) && 15062306a36Sopenharmony_ci ((mem_start + mem_size) > reg_start)) { 15162306a36Sopenharmony_ci /* Guarantee that the memory partition doesn't overlap the 15262306a36Sopenharmony_ci * registers partition */ 15362306a36Sopenharmony_ci wl1251_debug(DEBUG_SPI, "End of partition[0] is " 15462306a36Sopenharmony_ci "overlapping partition[1]. Adjusted."); 15562306a36Sopenharmony_ci mem_size = reg_start - mem_start; 15662306a36Sopenharmony_ci wl1251_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", 15762306a36Sopenharmony_ci mem_start, mem_size); 15862306a36Sopenharmony_ci wl1251_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", 15962306a36Sopenharmony_ci reg_start, reg_size); 16062306a36Sopenharmony_ci } else if ((reg_start < mem_start) && 16162306a36Sopenharmony_ci ((reg_start + reg_size) > mem_start)) { 16262306a36Sopenharmony_ci /* Guarantee that the register partition doesn't overlap the 16362306a36Sopenharmony_ci * memory partition */ 16462306a36Sopenharmony_ci wl1251_debug(DEBUG_SPI, "End of partition[1] is" 16562306a36Sopenharmony_ci " overlapping partition[0]. Adjusted."); 16662306a36Sopenharmony_ci reg_size = mem_start - reg_start; 16762306a36Sopenharmony_ci wl1251_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", 16862306a36Sopenharmony_ci mem_start, mem_size); 16962306a36Sopenharmony_ci wl1251_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", 17062306a36Sopenharmony_ci reg_start, reg_size); 17162306a36Sopenharmony_ci } 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci partition->mem.start = mem_start; 17462306a36Sopenharmony_ci partition->mem.size = mem_size; 17562306a36Sopenharmony_ci partition->reg.start = reg_start; 17662306a36Sopenharmony_ci partition->reg.size = reg_size; 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci wl->physical_mem_addr = mem_start; 17962306a36Sopenharmony_ci wl->physical_reg_addr = reg_start; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci wl->virtual_mem_addr = 0; 18262306a36Sopenharmony_ci wl->virtual_reg_addr = mem_size; 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci wl->if_ops->write(wl, HW_ACCESS_PART0_SIZE_ADDR, partition, 18562306a36Sopenharmony_ci sizeof(*partition)); 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci kfree(partition); 18862306a36Sopenharmony_ci} 189