1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * This file is part of wl1271 4 * 5 * Copyright (C) 2008-2010 Nokia Corporation 6 * 7 * Contact: Luciano Coelho <luciano.coelho@nokia.com> 8 */ 9 10 #include <linux/module.h> 11 #include <linux/platform_device.h> 12 #include <linux/spi/spi.h> 13 #include <linux/interrupt.h> 14 15 #include "wlcore.h" 16 #include "debug.h" 17 #include "wl12xx_80211.h" 18 #include "io.h" 19 #include "tx.h" 20 21 bool wl1271_set_block_size(struct wl1271 *wl) 22 { 23 if (wl->if_ops->set_block_size) { 24 wl->if_ops->set_block_size(wl->dev, WL12XX_BUS_BLOCK_SIZE); 25 return true; 26 } 27 28 return false; 29 } 30 31 void wlcore_disable_interrupts(struct wl1271 *wl) 32 { 33 disable_irq(wl->irq); 34 } 35 EXPORT_SYMBOL_GPL(wlcore_disable_interrupts); 36 37 void wlcore_disable_interrupts_nosync(struct wl1271 *wl) 38 { 39 disable_irq_nosync(wl->irq); 40 } 41 EXPORT_SYMBOL_GPL(wlcore_disable_interrupts_nosync); 42 43 void wlcore_enable_interrupts(struct wl1271 *wl) 44 { 45 enable_irq(wl->irq); 46 } 47 EXPORT_SYMBOL_GPL(wlcore_enable_interrupts); 48 49 void wlcore_synchronize_interrupts(struct wl1271 *wl) 50 { 51 synchronize_irq(wl->irq); 52 } 53 EXPORT_SYMBOL_GPL(wlcore_synchronize_interrupts); 54 55 int wlcore_translate_addr(struct wl1271 *wl, int addr) 56 { 57 struct wlcore_partition_set *part = &wl->curr_part; 58 59 /* 60 * To translate, first check to which window of addresses the 61 * particular address belongs. Then subtract the starting address 62 * of that window from the address. Then, add offset of the 63 * translated region. 64 * 65 * The translated regions occur next to each other in physical device 66 * memory, so just add the sizes of the preceding address regions to 67 * get the offset to the new region. 68 */ 69 if ((addr >= part->mem.start) && 70 (addr < part->mem.start + part->mem.size)) 71 return addr - part->mem.start; 72 else if ((addr >= part->reg.start) && 73 (addr < part->reg.start + part->reg.size)) 74 return addr - part->reg.start + part->mem.size; 75 else if ((addr >= part->mem2.start) && 76 (addr < part->mem2.start + part->mem2.size)) 77 return addr - part->mem2.start + part->mem.size + 78 part->reg.size; 79 else if ((addr >= part->mem3.start) && 80 (addr < part->mem3.start + part->mem3.size)) 81 return addr - part->mem3.start + part->mem.size + 82 part->reg.size + part->mem2.size; 83 84 WARN(1, "HW address 0x%x out of range", addr); 85 return 0; 86 } 87 EXPORT_SYMBOL_GPL(wlcore_translate_addr); 88 89 /* Set the partitions to access the chip addresses 90 * 91 * To simplify driver code, a fixed (virtual) memory map is defined for 92 * register and memory addresses. Because in the chipset, in different stages 93 * of operation, those addresses will move around, an address translation 94 * mechanism is required. 95 * 96 * There are four partitions (three memory and one register partition), 97 * which are mapped to two different areas of the hardware memory. 98 * 99 * Virtual address 100 * space 101 * 102 * | | 103 * ...+----+--> mem.start 104 * Physical address ... | | 105 * space ... | | [PART_0] 106 * ... | | 107 * 00000000 <--+----+... ...+----+--> mem.start + mem.size 108 * | | ... | | 109 * |MEM | ... | | 110 * | | ... | | 111 * mem.size <--+----+... | | {unused area) 112 * | | ... | | 113 * |REG | ... | | 114 * mem.size | | ... | | 115 * + <--+----+... ...+----+--> reg.start 116 * reg.size | | ... | | 117 * |MEM2| ... | | [PART_1] 118 * | | ... | | 119 * ...+----+--> reg.start + reg.size 120 * | | 121 * 122 */ 123 int wlcore_set_partition(struct wl1271 *wl, 124 const struct wlcore_partition_set *p) 125 { 126 int ret; 127 128 /* copy partition info */ 129 memcpy(&wl->curr_part, p, sizeof(*p)); 130 131 wl1271_debug(DEBUG_IO, "mem_start %08X mem_size %08X", 132 p->mem.start, p->mem.size); 133 wl1271_debug(DEBUG_IO, "reg_start %08X reg_size %08X", 134 p->reg.start, p->reg.size); 135 wl1271_debug(DEBUG_IO, "mem2_start %08X mem2_size %08X", 136 p->mem2.start, p->mem2.size); 137 wl1271_debug(DEBUG_IO, "mem3_start %08X mem3_size %08X", 138 p->mem3.start, p->mem3.size); 139 140 ret = wlcore_raw_write32(wl, HW_PART0_START_ADDR, p->mem.start); 141 if (ret < 0) 142 goto out; 143 144 ret = wlcore_raw_write32(wl, HW_PART0_SIZE_ADDR, p->mem.size); 145 if (ret < 0) 146 goto out; 147 148 ret = wlcore_raw_write32(wl, HW_PART1_START_ADDR, p->reg.start); 149 if (ret < 0) 150 goto out; 151 152 ret = wlcore_raw_write32(wl, HW_PART1_SIZE_ADDR, p->reg.size); 153 if (ret < 0) 154 goto out; 155 156 ret = wlcore_raw_write32(wl, HW_PART2_START_ADDR, p->mem2.start); 157 if (ret < 0) 158 goto out; 159 160 ret = wlcore_raw_write32(wl, HW_PART2_SIZE_ADDR, p->mem2.size); 161 if (ret < 0) 162 goto out; 163 164 /* wl12xx only: We don't need the size of the last partition, 165 * as it is automatically calculated based on the total memory 166 * size and the sizes of the previous partitions. 167 * 168 * wl18xx re-defines the HW_PART3 addresses for logger over 169 * SDIO support. wl12xx is expecting the write to 170 * HW_PART3_START_ADDR at offset 24. This creates conflict 171 * between the addresses. 172 * In order to fix this the expected value is written to 173 * HW_PART3_SIZE_ADDR instead which is at offset 24 after changes. 174 */ 175 ret = wlcore_raw_write32(wl, HW_PART3_START_ADDR, p->mem3.start); 176 if (ret < 0) 177 goto out; 178 179 ret = wlcore_raw_write32(wl, HW_PART3_SIZE_ADDR, p->mem3.size); 180 if (ret < 0) 181 goto out; 182 183 out: 184 return ret; 185 } 186 EXPORT_SYMBOL_GPL(wlcore_set_partition); 187 188 void wl1271_io_reset(struct wl1271 *wl) 189 { 190 if (wl->if_ops->reset) 191 wl->if_ops->reset(wl->dev); 192 } 193 194 void wl1271_io_init(struct wl1271 *wl) 195 { 196 if (wl->if_ops->init) 197 wl->if_ops->init(wl->dev); 198 } 199