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