Vishalsingh Hajeri | 71fc3c5 | 2018-01-15 20:28:29 -0800 | [diff] [blame] | 1 | /* Copyright (c) 2011-2014, 2017-2018, The Linux Foundation. |
| 2 | * All rights reserved. |
Harsh Shah | bbe3374 | 2017-03-14 18:09:54 -0700 | [diff] [blame] | 3 | * |
| 4 | * This program is free software; you can redistribute it and/or modify |
| 5 | * it under the terms of the GNU General Public License version 2 and |
| 6 | * only version 2 as published by the Free Software Foundation. |
| 7 | * |
| 8 | * This program is distributed in the hope that it will be useful, |
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 11 | * GNU General Public License for more details. |
| 12 | */ |
| 13 | |
Harsh Shah | bbe3374 | 2017-03-14 18:09:54 -0700 | [diff] [blame] | 14 | #include <linux/delay.h> |
| 15 | #include <linux/io.h> |
| 16 | #include <linux/err.h> |
| 17 | #include "cam_io_util.h" |
Jigarkumar Zala | ea7e56a | 2017-07-27 10:13:06 -0700 | [diff] [blame] | 18 | #include "cam_debug_util.h" |
Harsh Shah | bbe3374 | 2017-03-14 18:09:54 -0700 | [diff] [blame] | 19 | |
| 20 | int cam_io_w(uint32_t data, void __iomem *addr) |
| 21 | { |
| 22 | if (!addr) |
| 23 | return -EINVAL; |
| 24 | |
Jigarkumar Zala | ea7e56a | 2017-07-27 10:13:06 -0700 | [diff] [blame] | 25 | CAM_DBG(CAM_UTIL, "0x%pK %08x", addr, data); |
Harsh Shah | fe102e1 | 2017-11-02 04:54:12 -0700 | [diff] [blame] | 26 | writel_relaxed_no_log(data, addr); |
Harsh Shah | bbe3374 | 2017-03-14 18:09:54 -0700 | [diff] [blame] | 27 | |
| 28 | return 0; |
| 29 | } |
| 30 | |
| 31 | int cam_io_w_mb(uint32_t data, void __iomem *addr) |
| 32 | { |
| 33 | if (!addr) |
| 34 | return -EINVAL; |
| 35 | |
Jigarkumar Zala | ea7e56a | 2017-07-27 10:13:06 -0700 | [diff] [blame] | 36 | CAM_DBG(CAM_UTIL, "0x%pK %08x", addr, data); |
Harsh Shah | bbe3374 | 2017-03-14 18:09:54 -0700 | [diff] [blame] | 37 | /* Ensure previous writes are done */ |
| 38 | wmb(); |
Harsh Shah | fe102e1 | 2017-11-02 04:54:12 -0700 | [diff] [blame] | 39 | writel_relaxed_no_log(data, addr); |
Vishalsingh Hajeri | 71fc3c5 | 2018-01-15 20:28:29 -0800 | [diff] [blame] | 40 | /* Ensure previous writes are done */ |
| 41 | wmb(); |
Harsh Shah | bbe3374 | 2017-03-14 18:09:54 -0700 | [diff] [blame] | 42 | |
| 43 | return 0; |
| 44 | } |
| 45 | |
| 46 | uint32_t cam_io_r(void __iomem *addr) |
| 47 | { |
| 48 | uint32_t data; |
| 49 | |
| 50 | if (!addr) { |
Jigarkumar Zala | ea7e56a | 2017-07-27 10:13:06 -0700 | [diff] [blame] | 51 | CAM_ERR(CAM_UTIL, "Invalid args"); |
Harsh Shah | bbe3374 | 2017-03-14 18:09:54 -0700 | [diff] [blame] | 52 | return 0; |
| 53 | } |
| 54 | |
| 55 | data = readl_relaxed(addr); |
Jigarkumar Zala | ea7e56a | 2017-07-27 10:13:06 -0700 | [diff] [blame] | 56 | CAM_DBG(CAM_UTIL, "0x%pK %08x", addr, data); |
Harsh Shah | bbe3374 | 2017-03-14 18:09:54 -0700 | [diff] [blame] | 57 | |
| 58 | return data; |
| 59 | } |
| 60 | |
| 61 | uint32_t cam_io_r_mb(void __iomem *addr) |
| 62 | { |
| 63 | uint32_t data; |
| 64 | |
| 65 | if (!addr) { |
Jigarkumar Zala | ea7e56a | 2017-07-27 10:13:06 -0700 | [diff] [blame] | 66 | CAM_ERR(CAM_UTIL, "Invalid args"); |
Harsh Shah | bbe3374 | 2017-03-14 18:09:54 -0700 | [diff] [blame] | 67 | return 0; |
| 68 | } |
| 69 | |
| 70 | /* Ensure previous read is done */ |
| 71 | rmb(); |
| 72 | data = readl_relaxed(addr); |
Jigarkumar Zala | ea7e56a | 2017-07-27 10:13:06 -0700 | [diff] [blame] | 73 | CAM_DBG(CAM_UTIL, "0x%pK %08x", addr, data); |
Vishalsingh Hajeri | 71fc3c5 | 2018-01-15 20:28:29 -0800 | [diff] [blame] | 74 | /* Ensure previous read is done */ |
| 75 | rmb(); |
Harsh Shah | bbe3374 | 2017-03-14 18:09:54 -0700 | [diff] [blame] | 76 | |
| 77 | return data; |
| 78 | } |
| 79 | |
| 80 | int cam_io_memcpy(void __iomem *dest_addr, |
| 81 | void __iomem *src_addr, uint32_t len) |
| 82 | { |
| 83 | int i; |
| 84 | uint32_t *d = (uint32_t *) dest_addr; |
| 85 | uint32_t *s = (uint32_t *) src_addr; |
| 86 | |
| 87 | if (!dest_addr || !src_addr) |
| 88 | return -EINVAL; |
| 89 | |
Jigarkumar Zala | ea7e56a | 2017-07-27 10:13:06 -0700 | [diff] [blame] | 90 | CAM_DBG(CAM_UTIL, "%pK %pK %d", dest_addr, src_addr, len); |
Harsh Shah | bbe3374 | 2017-03-14 18:09:54 -0700 | [diff] [blame] | 91 | |
| 92 | for (i = 0; i < len/4; i++) { |
Jigarkumar Zala | ea7e56a | 2017-07-27 10:13:06 -0700 | [diff] [blame] | 93 | CAM_DBG(CAM_UTIL, "0x%pK %08x", d, *s); |
Harsh Shah | bbe3374 | 2017-03-14 18:09:54 -0700 | [diff] [blame] | 94 | writel_relaxed(*s++, d++); |
| 95 | } |
| 96 | |
| 97 | return 0; |
| 98 | } |
| 99 | |
| 100 | int cam_io_memcpy_mb(void __iomem *dest_addr, |
| 101 | void __iomem *src_addr, uint32_t len) |
| 102 | { |
| 103 | int i; |
| 104 | uint32_t *d = (uint32_t *) dest_addr; |
| 105 | uint32_t *s = (uint32_t *) src_addr; |
| 106 | |
| 107 | if (!dest_addr || !src_addr) |
| 108 | return -EINVAL; |
| 109 | |
Jigarkumar Zala | ea7e56a | 2017-07-27 10:13:06 -0700 | [diff] [blame] | 110 | CAM_DBG(CAM_UTIL, "%pK %pK %d", dest_addr, src_addr, len); |
Harsh Shah | bbe3374 | 2017-03-14 18:09:54 -0700 | [diff] [blame] | 111 | |
| 112 | /* |
| 113 | * Do not use cam_io_w_mb to avoid double wmb() after a write |
| 114 | * and before the next write. |
| 115 | */ |
| 116 | wmb(); |
| 117 | for (i = 0; i < (len / 4); i++) { |
Jigarkumar Zala | ea7e56a | 2017-07-27 10:13:06 -0700 | [diff] [blame] | 118 | CAM_DBG(CAM_UTIL, "0x%pK %08x", d, *s); |
Harsh Shah | bbe3374 | 2017-03-14 18:09:54 -0700 | [diff] [blame] | 119 | writel_relaxed(*s++, d++); |
| 120 | } |
Vishalsingh Hajeri | 71fc3c5 | 2018-01-15 20:28:29 -0800 | [diff] [blame] | 121 | /* Ensure previous writes are done */ |
| 122 | wmb(); |
Harsh Shah | bbe3374 | 2017-03-14 18:09:54 -0700 | [diff] [blame] | 123 | |
| 124 | return 0; |
| 125 | } |
| 126 | |
| 127 | int cam_io_poll_value(void __iomem *addr, uint32_t wait_data, uint32_t retry, |
| 128 | unsigned long min_usecs, unsigned long max_usecs) |
| 129 | { |
| 130 | uint32_t tmp, cnt = 0; |
| 131 | int rc = 0; |
| 132 | |
| 133 | if (!addr) |
| 134 | return -EINVAL; |
| 135 | |
| 136 | tmp = readl_relaxed(addr); |
| 137 | while ((tmp != wait_data) && (cnt++ < retry)) { |
| 138 | if (min_usecs > 0 && max_usecs > 0) |
| 139 | usleep_range(min_usecs, max_usecs); |
| 140 | tmp = readl_relaxed(addr); |
| 141 | } |
| 142 | |
| 143 | if (cnt > retry) { |
Jigarkumar Zala | ea7e56a | 2017-07-27 10:13:06 -0700 | [diff] [blame] | 144 | CAM_DBG(CAM_UTIL, "Poll failed by value"); |
Harsh Shah | bbe3374 | 2017-03-14 18:09:54 -0700 | [diff] [blame] | 145 | rc = -EINVAL; |
| 146 | } |
| 147 | |
| 148 | return rc; |
| 149 | } |
| 150 | |
| 151 | int cam_io_poll_value_wmask(void __iomem *addr, uint32_t wait_data, |
| 152 | uint32_t bmask, uint32_t retry, unsigned long min_usecs, |
| 153 | unsigned long max_usecs) |
| 154 | { |
| 155 | uint32_t tmp, cnt = 0; |
| 156 | int rc = 0; |
| 157 | |
| 158 | if (!addr) |
| 159 | return -EINVAL; |
| 160 | |
| 161 | tmp = readl_relaxed(addr); |
| 162 | while (((tmp & bmask) != wait_data) && (cnt++ < retry)) { |
| 163 | if (min_usecs > 0 && max_usecs > 0) |
| 164 | usleep_range(min_usecs, max_usecs); |
| 165 | tmp = readl_relaxed(addr); |
| 166 | } |
| 167 | |
| 168 | if (cnt > retry) { |
Jigarkumar Zala | ea7e56a | 2017-07-27 10:13:06 -0700 | [diff] [blame] | 169 | CAM_DBG(CAM_UTIL, "Poll failed with mask"); |
Harsh Shah | bbe3374 | 2017-03-14 18:09:54 -0700 | [diff] [blame] | 170 | rc = -EINVAL; |
| 171 | } |
| 172 | |
| 173 | return rc; |
| 174 | } |
| 175 | |
| 176 | int cam_io_w_same_offset_block(const uint32_t *data, void __iomem *addr, |
| 177 | uint32_t len) |
| 178 | { |
| 179 | int i; |
| 180 | |
| 181 | if (!data || !len || !addr) |
| 182 | return -EINVAL; |
| 183 | |
| 184 | for (i = 0; i < len; i++) { |
Jigarkumar Zala | ea7e56a | 2017-07-27 10:13:06 -0700 | [diff] [blame] | 185 | CAM_DBG(CAM_UTIL, "i= %d len =%d val=%x addr =%pK", |
Harsh Shah | bbe3374 | 2017-03-14 18:09:54 -0700 | [diff] [blame] | 186 | i, len, data[i], addr); |
| 187 | writel_relaxed(data[i], addr); |
| 188 | } |
| 189 | |
| 190 | return 0; |
| 191 | } |
| 192 | |
| 193 | int cam_io_w_mb_same_offset_block(const uint32_t *data, void __iomem *addr, |
| 194 | uint32_t len) |
| 195 | { |
| 196 | int i; |
| 197 | |
| 198 | if (!data || !len || !addr) |
| 199 | return -EINVAL; |
| 200 | |
| 201 | for (i = 0; i < len; i++) { |
Jigarkumar Zala | ea7e56a | 2017-07-27 10:13:06 -0700 | [diff] [blame] | 202 | CAM_DBG(CAM_UTIL, "i= %d len =%d val=%x addr =%pK", |
Harsh Shah | bbe3374 | 2017-03-14 18:09:54 -0700 | [diff] [blame] | 203 | i, len, data[i], addr); |
| 204 | /* Ensure previous writes are done */ |
| 205 | wmb(); |
| 206 | writel_relaxed(data[i], addr); |
| 207 | } |
| 208 | |
| 209 | return 0; |
| 210 | } |
| 211 | |
| 212 | #define __OFFSET(__i) (data[__i][0]) |
| 213 | #define __VAL(__i) (data[__i][1]) |
| 214 | int cam_io_w_offset_val_block(const uint32_t data[][2], |
| 215 | void __iomem *addr_base, uint32_t len) |
| 216 | { |
| 217 | int i; |
| 218 | |
| 219 | if (!data || !len || !addr_base) |
| 220 | return -EINVAL; |
| 221 | |
| 222 | for (i = 0; i < len; i++) { |
Jigarkumar Zala | ea7e56a | 2017-07-27 10:13:06 -0700 | [diff] [blame] | 223 | CAM_DBG(CAM_UTIL, "i= %d len =%d val=%x addr_base =%pK reg=%x", |
Harsh Shah | bbe3374 | 2017-03-14 18:09:54 -0700 | [diff] [blame] | 224 | i, len, __VAL(i), addr_base, __OFFSET(i)); |
| 225 | writel_relaxed(__VAL(i), addr_base + __OFFSET(i)); |
| 226 | } |
| 227 | |
| 228 | return 0; |
| 229 | } |
| 230 | |
| 231 | int cam_io_w_mb_offset_val_block(const uint32_t data[][2], |
| 232 | void __iomem *addr_base, uint32_t len) |
| 233 | { |
| 234 | int i; |
| 235 | |
| 236 | if (!data || !len || !addr_base) |
| 237 | return -EINVAL; |
| 238 | |
| 239 | /* Ensure write is done */ |
| 240 | wmb(); |
| 241 | for (i = 0; i < len; i++) { |
Jigarkumar Zala | ea7e56a | 2017-07-27 10:13:06 -0700 | [diff] [blame] | 242 | CAM_DBG(CAM_UTIL, "i= %d len =%d val=%x addr_base =%pK reg=%x", |
Harsh Shah | bbe3374 | 2017-03-14 18:09:54 -0700 | [diff] [blame] | 243 | i, len, __VAL(i), addr_base, __OFFSET(i)); |
| 244 | writel_relaxed(__VAL(i), addr_base + __OFFSET(i)); |
| 245 | } |
| 246 | |
| 247 | return 0; |
| 248 | } |
| 249 | |
| 250 | #define BYTES_PER_REGISTER 4 |
| 251 | #define NUM_REGISTER_PER_LINE 4 |
| 252 | #define REG_OFFSET(__start, __i) (__start + (__i * BYTES_PER_REGISTER)) |
| 253 | int cam_io_dump(void __iomem *base_addr, uint32_t start_offset, int size) |
| 254 | { |
| 255 | char line_str[128]; |
| 256 | char *p_str; |
| 257 | int i; |
| 258 | uint32_t data; |
| 259 | |
Jigarkumar Zala | ea7e56a | 2017-07-27 10:13:06 -0700 | [diff] [blame] | 260 | CAM_DBG(CAM_UTIL, "addr=%pK offset=0x%x size=%d", |
| 261 | base_addr, start_offset, size); |
Harsh Shah | bbe3374 | 2017-03-14 18:09:54 -0700 | [diff] [blame] | 262 | |
| 263 | if (!base_addr || (size <= 0)) |
| 264 | return -EINVAL; |
| 265 | |
| 266 | line_str[0] = '\0'; |
| 267 | p_str = line_str; |
| 268 | for (i = 0; i < size; i++) { |
| 269 | if (i % NUM_REGISTER_PER_LINE == 0) { |
| 270 | snprintf(p_str, 12, "0x%08x: ", |
| 271 | REG_OFFSET(start_offset, i)); |
kartanan | 7a55bd3 | 2017-08-07 15:52:05 -0700 | [diff] [blame] | 272 | p_str += 11; |
Harsh Shah | bbe3374 | 2017-03-14 18:09:54 -0700 | [diff] [blame] | 273 | } |
| 274 | data = readl_relaxed(base_addr + REG_OFFSET(start_offset, i)); |
| 275 | snprintf(p_str, 9, "%08x ", data); |
kartanan | 7a55bd3 | 2017-08-07 15:52:05 -0700 | [diff] [blame] | 276 | p_str += 8; |
Harsh Shah | bbe3374 | 2017-03-14 18:09:54 -0700 | [diff] [blame] | 277 | if ((i + 1) % NUM_REGISTER_PER_LINE == 0) { |
Jigarkumar Zala | ea7e56a | 2017-07-27 10:13:06 -0700 | [diff] [blame] | 278 | CAM_ERR(CAM_UTIL, "%s", line_str); |
Harsh Shah | bbe3374 | 2017-03-14 18:09:54 -0700 | [diff] [blame] | 279 | line_str[0] = '\0'; |
| 280 | p_str = line_str; |
| 281 | } |
| 282 | } |
| 283 | if (line_str[0] != '\0') |
Jigarkumar Zala | ea7e56a | 2017-07-27 10:13:06 -0700 | [diff] [blame] | 284 | CAM_ERR(CAM_UTIL, "%s", line_str); |
Harsh Shah | bbe3374 | 2017-03-14 18:09:54 -0700 | [diff] [blame] | 285 | |
| 286 | return 0; |
| 287 | } |
| 288 | |