1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Copyright (c) 2015 Google, Inc 4 * Written by Simon Glass <sjg@chromium.org> 5 */ 6 7 #include <common.h> 8 #include <dm.h> 9 #include <errno.h> 10 #include <linux/libfdt.h> 11 #include <malloc.h> 12 #include <mapmem.h> 13 #include <regmap.h> 14 #include <asm/io.h> 15 #include <dm/of_addr.h> 16 #include <linux/ioport.h> 17 18 DECLARE_GLOBAL_DATA_PTR; 19 20 /** 21 * regmap_alloc() - Allocate a regmap with a given number of ranges. 22 * 23 * @count: Number of ranges to be allocated for the regmap. 24 * Return: A pointer to the newly allocated regmap, or NULL on error. 25 */ 26 static struct regmap *regmap_alloc(int count) 27 { 28 struct regmap *map; 29 30 map = malloc(sizeof(*map) + sizeof(map->ranges[0]) * count); 31 if (!map) 32 return NULL; 33 map->range_count = count; 34 35 return map; 36 } 37 38 #if CONFIG_IS_ENABLED(OF_PLATDATA) 39 int regmap_init_mem_platdata(struct udevice *dev, fdt_val_t *reg, int count, 40 struct regmap **mapp) 41 { 42 struct regmap_range *range; 43 struct regmap *map; 44 45 map = regmap_alloc(count); 46 if (!map) 47 return -ENOMEM; 48 49 for (range = map->ranges; count > 0; reg += 2, range++, count--) { 50 range->start = *reg; 51 range->size = reg[1]; 52 } 53 54 *mapp = map; 55 56 return 0; 57 } 58 #else 59 /** 60 * init_range() - Initialize a single range of a regmap 61 * @node: Device node that will use the map in question 62 * @range: Pointer to a regmap_range structure that will be initialized 63 * @addr_len: The length of the addr parts of the reg property 64 * @size_len: The length of the size parts of the reg property 65 * @index: The index of the range to initialize 66 * 67 * This function will read the necessary 'reg' information from the device tree 68 * (the 'addr' part, and the 'length' part), and initialize the range in 69 * quesion. 70 * 71 * Return: 0 if OK, -ve on error 72 */ 73 static int init_range(ofnode node, struct regmap_range *range, int addr_len, 74 int size_len, int index) 75 { 76 fdt_size_t sz; 77 struct resource r; 78 79 if (of_live_active()) { 80 int ret; 81 82 ret = of_address_to_resource(ofnode_to_np(node), 83 index, &r); 84 if (ret) { 85 debug("%s: Could not read resource of range %d (ret = %d)\n", 86 ofnode_get_name(node), index, ret); 87 return ret; 88 } 89 90 range->start = r.start; 91 range->size = r.end - r.start + 1; 92 } else { 93 int offset = ofnode_to_offset(node); 94 95 range->start = fdtdec_get_addr_size_fixed(gd->fdt_blob, offset, 96 "reg", index, 97 addr_len, size_len, 98 &sz, true); 99 if (range->start == FDT_ADDR_T_NONE) { 100 debug("%s: Could not read start of range %d\n", 101 ofnode_get_name(node), index); 102 return -EINVAL; 103 } 104 105 range->size = sz; 106 } 107 108 return 0; 109 } 110 111 int regmap_init_mem(ofnode node, struct regmap **mapp) 112 { 113 struct regmap_range *range; 114 struct regmap *map; 115 int count; 116 int addr_len, size_len, both_len; 117 int len; 118 int index; 119 120 addr_len = ofnode_read_simple_addr_cells(ofnode_get_parent(node)); 121 if (addr_len < 0) { 122 debug("%s: Error while reading the addr length (ret = %d)\n", 123 ofnode_get_name(node), addr_len); 124 return addr_len; 125 } 126 127 size_len = ofnode_read_simple_size_cells(ofnode_get_parent(node)); 128 if (size_len < 0) { 129 debug("%s: Error while reading the size length: (ret = %d)\n", 130 ofnode_get_name(node), size_len); 131 return size_len; 132 } 133 134 both_len = addr_len + size_len; 135 if (!both_len) { 136 debug("%s: Both addr and size length are zero\n", 137 ofnode_get_name(node)); 138 return -EINVAL; 139 } 140 141 len = ofnode_read_size(node, "reg"); 142 if (len < 0) { 143 debug("%s: Error while reading reg size (ret = %d)\n", 144 ofnode_get_name(node), len); 145 return len; 146 } 147 len /= sizeof(fdt32_t); 148 count = len / both_len; 149 if (!count) { 150 debug("%s: Not enough data in reg property\n", 151 ofnode_get_name(node)); 152 return -EINVAL; 153 } 154 155 map = regmap_alloc(count); 156 if (!map) 157 return -ENOMEM; 158 159 for (range = map->ranges, index = 0; count > 0; 160 count--, range++, index++) { 161 int ret = init_range(node, range, addr_len, size_len, index); 162 163 if (ret) 164 return ret; 165 } 166 167 if (ofnode_read_bool(node, "little-endian")) 168 map->endianness = REGMAP_LITTLE_ENDIAN; 169 else if (ofnode_read_bool(node, "big-endian")) 170 map->endianness = REGMAP_BIG_ENDIAN; 171 else if (ofnode_read_bool(node, "native-endian")) 172 map->endianness = REGMAP_NATIVE_ENDIAN; 173 else /* Default: native endianness */ 174 map->endianness = REGMAP_NATIVE_ENDIAN; 175 176 *mapp = map; 177 178 return 0; 179 } 180 #endif 181 182 void *regmap_get_range(struct regmap *map, unsigned int range_num) 183 { 184 struct regmap_range *range; 185 186 if (range_num >= map->range_count) 187 return NULL; 188 range = &map->ranges[range_num]; 189 190 return map_sysmem(range->start, range->size); 191 } 192 193 int regmap_uninit(struct regmap *map) 194 { 195 free(map); 196 197 return 0; 198 } 199 200 static inline u8 __read_8(u8 *addr, enum regmap_endianness_t endianness) 201 { 202 return readb(addr); 203 } 204 205 static inline u16 __read_16(u16 *addr, enum regmap_endianness_t endianness) 206 { 207 switch (endianness) { 208 case REGMAP_LITTLE_ENDIAN: 209 return in_le16(addr); 210 case REGMAP_BIG_ENDIAN: 211 return in_be16(addr); 212 case REGMAP_NATIVE_ENDIAN: 213 return readw(addr); 214 } 215 216 return readw(addr); 217 } 218 219 static inline u32 __read_32(u32 *addr, enum regmap_endianness_t endianness) 220 { 221 switch (endianness) { 222 case REGMAP_LITTLE_ENDIAN: 223 return in_le32(addr); 224 case REGMAP_BIG_ENDIAN: 225 return in_be32(addr); 226 case REGMAP_NATIVE_ENDIAN: 227 return readl(addr); 228 } 229 230 return readl(addr); 231 } 232 233 #if defined(in_le64) && defined(in_be64) && defined(readq) 234 static inline u64 __read_64(u64 *addr, enum regmap_endianness_t endianness) 235 { 236 switch (endianness) { 237 case REGMAP_LITTLE_ENDIAN: 238 return in_le64(addr); 239 case REGMAP_BIG_ENDIAN: 240 return in_be64(addr); 241 case REGMAP_NATIVE_ENDIAN: 242 return readq(addr); 243 } 244 245 return readq(addr); 246 } 247 #endif 248 249 int regmap_raw_read_range(struct regmap *map, uint range_num, uint offset, 250 void *valp, size_t val_len) 251 { 252 struct regmap_range *range; 253 void *ptr; 254 255 if (range_num >= map->range_count) { 256 debug("%s: range index %d larger than range count\n", 257 __func__, range_num); 258 return -ERANGE; 259 } 260 range = &map->ranges[range_num]; 261 262 ptr = map_physmem(range->start + offset, val_len, MAP_NOCACHE); 263 264 if (offset + val_len > range->size) { 265 debug("%s: offset/size combination invalid\n", __func__); 266 return -ERANGE; 267 } 268 269 switch (val_len) { 270 case REGMAP_SIZE_8: 271 *((u8 *)valp) = __read_8(ptr, map->endianness); 272 break; 273 case REGMAP_SIZE_16: 274 *((u16 *)valp) = __read_16(ptr, map->endianness); 275 break; 276 case REGMAP_SIZE_32: 277 *((u32 *)valp) = __read_32(ptr, map->endianness); 278 break; 279 #if defined(in_le64) && defined(in_be64) && defined(readq) 280 case REGMAP_SIZE_64: 281 *((u64 *)valp) = __read_64(ptr, map->endianness); 282 break; 283 #endif 284 default: 285 debug("%s: regmap size %zu unknown\n", __func__, val_len); 286 return -EINVAL; 287 } 288 289 return 0; 290 } 291 292 int regmap_raw_read(struct regmap *map, uint offset, void *valp, size_t val_len) 293 { 294 return regmap_raw_read_range(map, 0, offset, valp, val_len); 295 } 296 297 int regmap_read(struct regmap *map, uint offset, uint *valp) 298 { 299 return regmap_raw_read(map, offset, valp, REGMAP_SIZE_32); 300 } 301 302 static inline void __write_8(u8 *addr, const u8 *val, 303 enum regmap_endianness_t endianness) 304 { 305 writeb(*val, addr); 306 } 307 308 static inline void __write_16(u16 *addr, const u16 *val, 309 enum regmap_endianness_t endianness) 310 { 311 switch (endianness) { 312 case REGMAP_NATIVE_ENDIAN: 313 writew(*val, addr); 314 break; 315 case REGMAP_LITTLE_ENDIAN: 316 out_le16(addr, *val); 317 break; 318 case REGMAP_BIG_ENDIAN: 319 out_be16(addr, *val); 320 break; 321 } 322 } 323 324 static inline void __write_32(u32 *addr, const u32 *val, 325 enum regmap_endianness_t endianness) 326 { 327 switch (endianness) { 328 case REGMAP_NATIVE_ENDIAN: 329 writel(*val, addr); 330 break; 331 case REGMAP_LITTLE_ENDIAN: 332 out_le32(addr, *val); 333 break; 334 case REGMAP_BIG_ENDIAN: 335 out_be32(addr, *val); 336 break; 337 } 338 } 339 340 #if defined(out_le64) && defined(out_be64) && defined(writeq) 341 static inline void __write_64(u64 *addr, const u64 *val, 342 enum regmap_endianness_t endianness) 343 { 344 switch (endianness) { 345 case REGMAP_NATIVE_ENDIAN: 346 writeq(*val, addr); 347 break; 348 case REGMAP_LITTLE_ENDIAN: 349 out_le64(addr, *val); 350 break; 351 case REGMAP_BIG_ENDIAN: 352 out_be64(addr, *val); 353 break; 354 } 355 } 356 #endif 357 358 int regmap_raw_write_range(struct regmap *map, uint range_num, uint offset, 359 const void *val, size_t val_len) 360 { 361 struct regmap_range *range; 362 void *ptr; 363 364 if (range_num >= map->range_count) { 365 debug("%s: range index %d larger than range count\n", 366 __func__, range_num); 367 return -ERANGE; 368 } 369 range = &map->ranges[range_num]; 370 371 ptr = map_physmem(range->start + offset, val_len, MAP_NOCACHE); 372 373 if (offset + val_len > range->size) { 374 debug("%s: offset/size combination invalid\n", __func__); 375 return -ERANGE; 376 } 377 378 switch (val_len) { 379 case REGMAP_SIZE_8: 380 __write_8(ptr, val, map->endianness); 381 break; 382 case REGMAP_SIZE_16: 383 __write_16(ptr, val, map->endianness); 384 break; 385 case REGMAP_SIZE_32: 386 __write_32(ptr, val, map->endianness); 387 break; 388 #if defined(out_le64) && defined(out_be64) && defined(writeq) 389 case REGMAP_SIZE_64: 390 __write_64(ptr, val, map->endianness); 391 break; 392 #endif 393 default: 394 debug("%s: regmap size %zu unknown\n", __func__, val_len); 395 return -EINVAL; 396 } 397 398 return 0; 399 } 400 401 int regmap_raw_write(struct regmap *map, uint offset, const void *val, 402 size_t val_len) 403 { 404 return regmap_raw_write_range(map, 0, offset, val, val_len); 405 } 406 407 int regmap_write(struct regmap *map, uint offset, uint val) 408 { 409 return regmap_raw_write(map, offset, &val, REGMAP_SIZE_32); 410 } 411 412 int regmap_update_bits(struct regmap *map, uint offset, uint mask, uint val) 413 { 414 uint reg; 415 int ret; 416 417 ret = regmap_read(map, offset, ®); 418 if (ret) 419 return ret; 420 421 reg &= ~mask; 422 423 return regmap_write(map, offset, reg | val); 424 } 425