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