Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 | // SPDX-License-Identifier: GPL-2.0-only /* * This file is part of wl12xx * * Copyright (C) 2008 Nokia Corporation */ #include "wl1251.h" #include "reg.h" #include "io.h" /* FIXME: this is static data nowadays and the table can be removed */ static enum wl12xx_acx_int_reg wl1251_io_reg_table[ACX_REG_TABLE_LEN] = { [ACX_REG_INTERRUPT_TRIG] = (REGISTERS_BASE + 0x0474), [ACX_REG_INTERRUPT_TRIG_H] = (REGISTERS_BASE + 0x0478), [ACX_REG_INTERRUPT_MASK] = (REGISTERS_BASE + 0x0494), [ACX_REG_HINT_MASK_SET] = (REGISTERS_BASE + 0x0498), [ACX_REG_HINT_MASK_CLR] = (REGISTERS_BASE + 0x049C), [ACX_REG_INTERRUPT_NO_CLEAR] = (REGISTERS_BASE + 0x04B0), [ACX_REG_INTERRUPT_CLEAR] = (REGISTERS_BASE + 0x04A4), [ACX_REG_INTERRUPT_ACK] = (REGISTERS_BASE + 0x04A8), [ACX_REG_SLV_SOFT_RESET] = (REGISTERS_BASE + 0x0000), [ACX_REG_EE_START] = (REGISTERS_BASE + 0x080C), [ACX_REG_ECPU_CONTROL] = (REGISTERS_BASE + 0x0804) }; static int wl1251_translate_reg_addr(struct wl1251 *wl, int addr) { /* If the address is lower than REGISTERS_BASE, it means that this is * a chip-specific register address, so look it up in the registers * table */ if (addr < REGISTERS_BASE) { /* Make sure we don't go over the table */ if (addr >= ACX_REG_TABLE_LEN) { wl1251_error("address out of range (%d)", addr); return -EINVAL; } addr = wl1251_io_reg_table[addr]; } return addr - wl->physical_reg_addr + wl->virtual_reg_addr; } static int wl1251_translate_mem_addr(struct wl1251 *wl, int addr) { return addr - wl->physical_mem_addr + wl->virtual_mem_addr; } void wl1251_mem_read(struct wl1251 *wl, int addr, void *buf, size_t len) { int physical; physical = wl1251_translate_mem_addr(wl, addr); wl->if_ops->read(wl, physical, buf, len); } void wl1251_mem_write(struct wl1251 *wl, int addr, void *buf, size_t len) { int physical; physical = wl1251_translate_mem_addr(wl, addr); wl->if_ops->write(wl, physical, buf, len); } u32 wl1251_mem_read32(struct wl1251 *wl, int addr) { return wl1251_read32(wl, wl1251_translate_mem_addr(wl, addr)); } void wl1251_mem_write32(struct wl1251 *wl, int addr, u32 val) { wl1251_write32(wl, wl1251_translate_mem_addr(wl, addr), val); } u32 wl1251_reg_read32(struct wl1251 *wl, int addr) { return wl1251_read32(wl, wl1251_translate_reg_addr(wl, addr)); } void wl1251_reg_write32(struct wl1251 *wl, int addr, u32 val) { wl1251_write32(wl, wl1251_translate_reg_addr(wl, addr), val); } /* Set the partitions to access the chip addresses. * * There are two VIRTUAL partitions (the memory partition and the * registers partition), which are mapped to two different areas of the * PHYSICAL (hardware) memory. This function also makes other checks to * ensure that the partitions are not overlapping. In the diagram below, the * memory partition comes before the register partition, but the opposite is * also supported. * * PHYSICAL address * space * * | | * ...+----+--> mem_start * VIRTUAL address ... | | * space ... | | [PART_0] * ... | | * 0x00000000 <--+----+... ...+----+--> mem_start + mem_size * | | ... | | * |MEM | ... | | * | | ... | | * part_size <--+----+... | | {unused area) * | | ... | | * |REG | ... | | * part_size | | ... | | * + <--+----+... ...+----+--> reg_start * reg_size ... | | * ... | | [PART_1] * ... | | * ...+----+--> reg_start + reg_size * | | * */ void wl1251_set_partition(struct wl1251 *wl, u32 mem_start, u32 mem_size, u32 reg_start, u32 reg_size) { struct wl1251_partition_set *partition; partition = kmalloc(sizeof(*partition), GFP_KERNEL); if (!partition) { wl1251_error("can not allocate partition buffer"); return; } wl1251_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", mem_start, mem_size); wl1251_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", reg_start, reg_size); /* Make sure that the two partitions together don't exceed the * address range */ if ((mem_size + reg_size) > HW_ACCESS_MEMORY_MAX_RANGE) { wl1251_debug(DEBUG_SPI, "Total size exceeds maximum virtual" " address range. Truncating partition[0]."); mem_size = HW_ACCESS_MEMORY_MAX_RANGE - reg_size; wl1251_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", mem_start, mem_size); wl1251_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", reg_start, reg_size); } if ((mem_start < reg_start) && ((mem_start + mem_size) > reg_start)) { /* Guarantee that the memory partition doesn't overlap the * registers partition */ wl1251_debug(DEBUG_SPI, "End of partition[0] is " "overlapping partition[1]. Adjusted."); mem_size = reg_start - mem_start; wl1251_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", mem_start, mem_size); wl1251_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", reg_start, reg_size); } else if ((reg_start < mem_start) && ((reg_start + reg_size) > mem_start)) { /* Guarantee that the register partition doesn't overlap the * memory partition */ wl1251_debug(DEBUG_SPI, "End of partition[1] is" " overlapping partition[0]. Adjusted."); reg_size = mem_start - reg_start; wl1251_debug(DEBUG_SPI, "mem_start %08X mem_size %08X", mem_start, mem_size); wl1251_debug(DEBUG_SPI, "reg_start %08X reg_size %08X", reg_start, reg_size); } partition->mem.start = mem_start; partition->mem.size = mem_size; partition->reg.start = reg_start; partition->reg.size = reg_size; wl->physical_mem_addr = mem_start; wl->physical_reg_addr = reg_start; wl->virtual_mem_addr = 0; wl->virtual_reg_addr = mem_size; wl->if_ops->write(wl, HW_ACCESS_PART0_SIZE_ADDR, partition, sizeof(*partition)); kfree(partition); } |