"Das U-Boot" Source Tree
at master 729 lines 16 kB view raw
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#define LOG_CATEGORY LOGC_DM 8 9#include <dm.h> 10#include <errno.h> 11#include <log.h> 12#include <asm/global_data.h> 13#include <linux/libfdt.h> 14#include <malloc.h> 15#include <mapmem.h> 16#include <regmap.h> 17#include <asm/io.h> 18#include <dm/of_addr.h> 19#include <dm/devres.h> 20#include <dm/util.h> 21#include <linux/ioport.h> 22#include <linux/compat.h> 23#include <linux/err.h> 24#include <linux/bitops.h> 25 26/* 27 * Internal representation of a regmap field. Instead of storing the MSB and 28 * LSB, store the shift and mask. This makes the code a bit cleaner and faster 29 * because the shift and mask don't have to be calculated every time. 30 */ 31struct regmap_field { 32 struct regmap *regmap; 33 unsigned int mask; 34 /* lsb */ 35 unsigned int shift; 36 unsigned int reg; 37}; 38 39DECLARE_GLOBAL_DATA_PTR; 40 41/** 42 * do_range_check() - Control whether range checks are done 43 * 44 * Returns: true to do range checks, false to skip 45 * 46 * This is used to reduce code size on SPL where range checks are known not to 47 * be needed 48 * 49 * Add this to the top of the file to enable them: #define LOG_DEBUG 50 */ 51static inline bool do_range_check(void) 52{ 53 return _LOG_DEBUG || !IS_ENABLED(CONFIG_SPL); 54 55} 56 57/** 58 * regmap_alloc() - Allocate a regmap with a given number of ranges. 59 * 60 * @count: Number of ranges to be allocated for the regmap. 61 * 62 * The default regmap width is set to REGMAP_SIZE_32. Callers can override it 63 * if they need. 64 * 65 * Return: A pointer to the newly allocated regmap, or NULL on error. 66 */ 67static struct regmap *regmap_alloc(int count) 68{ 69 struct regmap *map; 70 size_t size = sizeof(*map) + sizeof(map->ranges[0]) * count; 71 72 map = calloc(1, size); 73 if (!map) 74 return NULL; 75 map->range_count = count; 76 map->width = REGMAP_SIZE_32; 77 78 return map; 79} 80 81#if CONFIG_IS_ENABLED(OF_PLATDATA) 82int regmap_init_mem_plat(struct udevice *dev, void *reg, int size, int count, 83 struct regmap **mapp) 84{ 85 struct regmap_range *range; 86 struct regmap *map; 87 88 map = regmap_alloc(count); 89 if (!map) 90 return -ENOMEM; 91 92 if (size == sizeof(fdt32_t)) { 93 fdt32_t *ptr = (fdt32_t *)reg; 94 95 for (range = map->ranges; count > 0; 96 ptr += 2, range++, count--) { 97 range->start = *ptr; 98 range->size = ptr[1]; 99 } 100 } else if (size == sizeof(fdt64_t)) { 101 fdt64_t *ptr = (fdt64_t *)reg; 102 103 for (range = map->ranges; count > 0; 104 ptr += 2, range++, count--) { 105 range->start = *ptr; 106 range->size = ptr[1]; 107 } 108 } else { 109 return -EINVAL; 110 } 111 112 *mapp = map; 113 114 return 0; 115} 116#else 117/** 118 * init_range() - Initialize a single range of a regmap 119 * @node: Device node that will use the map in question 120 * @range: Pointer to a regmap_range structure that will be initialized 121 * @addr_len: The length of the addr parts of the reg property 122 * @size_len: The length of the size parts of the reg property 123 * @index: The index of the range to initialize 124 * 125 * This function will read the necessary 'reg' information from the device tree 126 * (the 'addr' part, and the 'length' part), and initialize the range in 127 * quesion. 128 * 129 * Return: 0 if OK, -ve on error 130 */ 131static int init_range(ofnode node, struct regmap_range *range, int addr_len, 132 int size_len, int index) 133{ 134 fdt_size_t sz; 135 struct resource r; 136 137 if (of_live_active()) { 138 int ret; 139 140 ret = of_address_to_resource(ofnode_to_np(node), 141 index, &r); 142 if (ret) { 143 dm_warn("%s: Could not read resource of range %d (ret = %d)\n", 144 ofnode_get_name(node), index, ret); 145 return ret; 146 } 147 148 range->start = r.start; 149 range->size = r.end - r.start + 1; 150 } else { 151 int offset = ofnode_to_offset(node); 152 153 range->start = fdtdec_get_addr_size_fixed(gd->fdt_blob, offset, 154 "reg", index, 155 addr_len, size_len, 156 &sz, true); 157 if (range->start == FDT_ADDR_T_NONE) { 158 dm_warn("%s: Could not read start of range %d\n", 159 ofnode_get_name(node), index); 160 return -EINVAL; 161 } 162 163 range->size = sz; 164 } 165 166 return 0; 167} 168 169int regmap_init_mem_index(ofnode node, struct regmap **mapp, int index) 170{ 171 ofnode parent; 172 struct regmap *map; 173 int addr_len, size_len; 174 int ret; 175 176 parent = ofnode_get_parent(node); 177 178 addr_len = ofnode_read_simple_addr_cells(parent); 179 if (addr_len < 0) { 180 dm_warn("%s: Error while reading the addr length (ret = %d)\n", 181 ofnode_get_name(node), addr_len); 182 return addr_len; 183 } 184 185 size_len = ofnode_read_simple_size_cells(parent); 186 if (size_len < 0) { 187 dm_warn("%s: Error while reading the size length: (ret = %d)\n", 188 ofnode_get_name(node), size_len); 189 return size_len; 190 } 191 192 map = regmap_alloc(1); 193 if (!map) 194 return -ENOMEM; 195 196 ret = init_range(node, map->ranges, addr_len, size_len, index); 197 if (ret) 198 goto err; 199 200 if (ofnode_read_bool(node, "little-endian")) 201 map->endianness = REGMAP_LITTLE_ENDIAN; 202 else if (ofnode_read_bool(node, "big-endian")) 203 map->endianness = REGMAP_BIG_ENDIAN; 204 else if (ofnode_read_bool(node, "native-endian")) 205 map->endianness = REGMAP_NATIVE_ENDIAN; 206 else /* Default: native endianness */ 207 map->endianness = REGMAP_NATIVE_ENDIAN; 208 209 *mapp = map; 210 211 return 0; 212err: 213 regmap_uninit(map); 214 215 return ret; 216} 217 218int regmap_init_mem_range(ofnode node, ulong r_start, ulong r_size, 219 struct regmap **mapp) 220{ 221 struct regmap *map; 222 struct regmap_range *range; 223 224 map = regmap_alloc(1); 225 if (!map) 226 return -ENOMEM; 227 228 range = &map->ranges[0]; 229 range->start = r_start; 230 range->size = r_size; 231 232 if (ofnode_read_bool(node, "little-endian")) 233 map->endianness = REGMAP_LITTLE_ENDIAN; 234 else if (ofnode_read_bool(node, "big-endian")) 235 map->endianness = REGMAP_BIG_ENDIAN; 236 else if (ofnode_read_bool(node, "native-endian")) 237 map->endianness = REGMAP_NATIVE_ENDIAN; 238 else /* Default: native endianness */ 239 map->endianness = REGMAP_NATIVE_ENDIAN; 240 241 *mapp = map; 242 return 0; 243} 244 245int regmap_init_mem(ofnode node, struct regmap **mapp) 246{ 247 ofnode parent; 248 struct regmap_range *range; 249 struct regmap *map; 250 int count; 251 int addr_len, size_len, both_len; 252 int len; 253 int index; 254 int ret; 255 256 parent = ofnode_get_parent(node); 257 258 addr_len = ofnode_read_simple_addr_cells(parent); 259 if (addr_len < 0) { 260 dm_warn("%s: Error while reading the addr length (ret = %d)\n", 261 ofnode_get_name(node), addr_len); 262 return addr_len; 263 } 264 265 size_len = ofnode_read_simple_size_cells(parent); 266 if (size_len < 0) { 267 dm_warn("%s: Error while reading the size length: (ret = %d)\n", 268 ofnode_get_name(node), size_len); 269 return size_len; 270 } 271 272 both_len = addr_len + size_len; 273 if (!both_len) { 274 dm_warn("%s: Both addr and size length are zero\n", 275 ofnode_get_name(node)); 276 return -EINVAL; 277 } 278 279 len = ofnode_read_size(node, "reg"); 280 if (len < 0) { 281 dm_warn("%s: Error while reading reg size (ret = %d)\n", 282 ofnode_get_name(node), len); 283 return len; 284 } 285 len /= sizeof(fdt32_t); 286 count = len / both_len; 287 if (!count) { 288 dm_warn("%s: Not enough data in reg property\n", 289 ofnode_get_name(node)); 290 return -EINVAL; 291 } 292 293 map = regmap_alloc(count); 294 if (!map) 295 return -ENOMEM; 296 297 for (range = map->ranges, index = 0; count > 0; 298 count--, range++, index++) { 299 ret = init_range(node, range, addr_len, size_len, index); 300 if (ret) 301 goto err; 302 } 303 304 if (ofnode_read_bool(node, "little-endian")) 305 map->endianness = REGMAP_LITTLE_ENDIAN; 306 else if (ofnode_read_bool(node, "big-endian")) 307 map->endianness = REGMAP_BIG_ENDIAN; 308 else if (ofnode_read_bool(node, "native-endian")) 309 map->endianness = REGMAP_NATIVE_ENDIAN; 310 else /* Default: native endianness */ 311 map->endianness = REGMAP_NATIVE_ENDIAN; 312 313 *mapp = map; 314 315 return 0; 316err: 317 regmap_uninit(map); 318 319 return ret; 320} 321 322static void devm_regmap_release(struct udevice *dev, void *res) 323{ 324 regmap_uninit(*(struct regmap **)res); 325} 326 327struct regmap *devm_regmap_init(struct udevice *dev, 328 const struct regmap_bus *bus, 329 void *bus_context, 330 const struct regmap_config *config) 331{ 332 int rc; 333 struct regmap **mapp, *map; 334 335 /* this looks like a leak, but devres takes care of it */ 336 mapp = devres_alloc(devm_regmap_release, sizeof(struct regmap *), 337 __GFP_ZERO); 338 if (unlikely(!mapp)) 339 return ERR_PTR(-ENOMEM); 340 341 if (config && config->r_size != 0) 342 rc = regmap_init_mem_range(dev_ofnode(dev), config->r_start, 343 config->r_size, mapp); 344 else 345 rc = regmap_init_mem(dev_ofnode(dev), mapp); 346 if (rc) 347 return ERR_PTR(rc); 348 349 map = *mapp; 350 if (config) { 351 map->width = config->width; 352 map->reg_offset_shift = config->reg_offset_shift; 353 } 354 355 devres_add(dev, mapp); 356 return *mapp; 357} 358#endif 359 360void *regmap_get_range(struct regmap *map, unsigned int range_num) 361{ 362 struct regmap_range *range; 363 364 if (range_num >= map->range_count) 365 return NULL; 366 range = &map->ranges[range_num]; 367 368 return map_sysmem(range->start, range->size); 369} 370 371int regmap_uninit(struct regmap *map) 372{ 373 free(map); 374 375 return 0; 376} 377 378static inline u8 __read_8(u8 *addr, enum regmap_endianness_t endianness) 379{ 380 return readb(addr); 381} 382 383static inline u16 __read_16(u16 *addr, enum regmap_endianness_t endianness) 384{ 385 switch (endianness) { 386 case REGMAP_LITTLE_ENDIAN: 387 return in_le16(addr); 388 case REGMAP_BIG_ENDIAN: 389 return in_be16(addr); 390 case REGMAP_NATIVE_ENDIAN: 391 return readw(addr); 392 } 393 394 return readw(addr); 395} 396 397static inline u32 __read_32(u32 *addr, enum regmap_endianness_t endianness) 398{ 399 switch (endianness) { 400 case REGMAP_LITTLE_ENDIAN: 401 return in_le32(addr); 402 case REGMAP_BIG_ENDIAN: 403 return in_be32(addr); 404 case REGMAP_NATIVE_ENDIAN: 405 return readl(addr); 406 } 407 408 return readl(addr); 409} 410 411#if defined(in_le64) && defined(in_be64) && defined(readq) 412static inline u64 __read_64(u64 *addr, enum regmap_endianness_t endianness) 413{ 414 switch (endianness) { 415 case REGMAP_LITTLE_ENDIAN: 416 return in_le64(addr); 417 case REGMAP_BIG_ENDIAN: 418 return in_be64(addr); 419 case REGMAP_NATIVE_ENDIAN: 420 return readq(addr); 421 } 422 423 return readq(addr); 424} 425#endif 426 427int regmap_raw_read_range(struct regmap *map, uint range_num, uint offset, 428 void *valp, size_t val_len) 429{ 430 struct regmap_range *range; 431 void *ptr; 432 433 if (do_range_check() && range_num >= map->range_count) { 434 dm_warn("%s: range index %d larger than range count\n", 435 __func__, range_num); 436 return -ERANGE; 437 } 438 range = &map->ranges[range_num]; 439 440 offset <<= map->reg_offset_shift; 441 if (do_range_check() && 442 (offset + val_len > range->size || offset + val_len < offset)) { 443 dm_warn("%s: offset/size combination invalid\n", __func__); 444 return -ERANGE; 445 } 446 447 ptr = map_physmem(range->start + offset, val_len, MAP_NOCACHE); 448 449 switch (val_len) { 450 case REGMAP_SIZE_8: 451 *((u8 *)valp) = __read_8(ptr, map->endianness); 452 break; 453 case REGMAP_SIZE_16: 454 *((u16 *)valp) = __read_16(ptr, map->endianness); 455 break; 456 case REGMAP_SIZE_32: 457 *((u32 *)valp) = __read_32(ptr, map->endianness); 458 break; 459#if defined(in_le64) && defined(in_be64) && defined(readq) 460 case REGMAP_SIZE_64: 461 *((u64 *)valp) = __read_64(ptr, map->endianness); 462 break; 463#endif 464 default: 465 dm_warn("%s: regmap size %zu unknown\n", __func__, val_len); 466 return -EINVAL; 467 } 468 469 return 0; 470} 471 472int regmap_raw_read(struct regmap *map, uint offset, void *valp, size_t val_len) 473{ 474 return regmap_raw_read_range(map, 0, offset, valp, val_len); 475} 476 477int regmap_read(struct regmap *map, uint offset, uint *valp) 478{ 479 union { 480 u8 v8; 481 u16 v16; 482 u32 v32; 483 u64 v64; 484 } u; 485 int res; 486 487 res = regmap_raw_read(map, offset, &u, map->width); 488 if (res) 489 return res; 490 491 switch (map->width) { 492 case REGMAP_SIZE_8: 493 *valp = u.v8; 494 break; 495 case REGMAP_SIZE_16: 496 *valp = u.v16; 497 break; 498 case REGMAP_SIZE_32: 499 *valp = u.v32; 500 break; 501 case REGMAP_SIZE_64: 502 *valp = u.v64; 503 break; 504 default: 505 unreachable(); 506 } 507 508 return 0; 509} 510 511static inline void __write_8(u8 *addr, const u8 *val, 512 enum regmap_endianness_t endianness) 513{ 514 writeb(*val, addr); 515} 516 517static inline void __write_16(u16 *addr, const u16 *val, 518 enum regmap_endianness_t endianness) 519{ 520 switch (endianness) { 521 case REGMAP_NATIVE_ENDIAN: 522 writew(*val, addr); 523 break; 524 case REGMAP_LITTLE_ENDIAN: 525 out_le16(addr, *val); 526 break; 527 case REGMAP_BIG_ENDIAN: 528 out_be16(addr, *val); 529 break; 530 } 531} 532 533static inline void __write_32(u32 *addr, const u32 *val, 534 enum regmap_endianness_t endianness) 535{ 536 switch (endianness) { 537 case REGMAP_NATIVE_ENDIAN: 538 writel(*val, addr); 539 break; 540 case REGMAP_LITTLE_ENDIAN: 541 out_le32(addr, *val); 542 break; 543 case REGMAP_BIG_ENDIAN: 544 out_be32(addr, *val); 545 break; 546 } 547} 548 549#if defined(out_le64) && defined(out_be64) && defined(writeq) 550static inline void __write_64(u64 *addr, const u64 *val, 551 enum regmap_endianness_t endianness) 552{ 553 switch (endianness) { 554 case REGMAP_NATIVE_ENDIAN: 555 writeq(*val, addr); 556 break; 557 case REGMAP_LITTLE_ENDIAN: 558 out_le64(addr, *val); 559 break; 560 case REGMAP_BIG_ENDIAN: 561 out_be64(addr, *val); 562 break; 563 } 564} 565#endif 566 567int regmap_raw_write_range(struct regmap *map, uint range_num, uint offset, 568 const void *val, size_t val_len) 569{ 570 struct regmap_range *range; 571 void *ptr; 572 573 if (range_num >= map->range_count) { 574 dm_warn("%s: range index %d larger than range count\n", 575 __func__, range_num); 576 return -ERANGE; 577 } 578 range = &map->ranges[range_num]; 579 580 offset <<= map->reg_offset_shift; 581 if (offset + val_len > range->size || offset + val_len < offset) { 582 dm_warn("%s: offset/size combination invalid\n", __func__); 583 return -ERANGE; 584 } 585 586 ptr = map_physmem(range->start + offset, val_len, MAP_NOCACHE); 587 588 switch (val_len) { 589 case REGMAP_SIZE_8: 590 __write_8(ptr, val, map->endianness); 591 break; 592 case REGMAP_SIZE_16: 593 __write_16(ptr, val, map->endianness); 594 break; 595 case REGMAP_SIZE_32: 596 __write_32(ptr, val, map->endianness); 597 break; 598#if defined(out_le64) && defined(out_be64) && defined(writeq) 599 case REGMAP_SIZE_64: 600 __write_64(ptr, val, map->endianness); 601 break; 602#endif 603 default: 604 dm_warn("%s: regmap size %zu unknown\n", __func__, val_len); 605 return -EINVAL; 606 } 607 608 return 0; 609} 610 611int regmap_raw_write(struct regmap *map, uint offset, const void *val, 612 size_t val_len) 613{ 614 return regmap_raw_write_range(map, 0, offset, val, val_len); 615} 616 617int regmap_write(struct regmap *map, uint offset, uint val) 618{ 619 union { 620 u8 v8; 621 u16 v16; 622 u32 v32; 623 u64 v64; 624 } u; 625 626 switch (map->width) { 627 case REGMAP_SIZE_8: 628 u.v8 = val; 629 break; 630 case REGMAP_SIZE_16: 631 u.v16 = val; 632 break; 633 case REGMAP_SIZE_32: 634 u.v32 = val; 635 break; 636 case REGMAP_SIZE_64: 637 u.v64 = val; 638 break; 639 default: 640 dm_warn("%s: regmap size %zu unknown\n", __func__, 641 (size_t)map->width); 642 return -EINVAL; 643 } 644 645 return regmap_raw_write(map, offset, &u, map->width); 646} 647 648int regmap_update_bits(struct regmap *map, uint offset, uint mask, uint val) 649{ 650 uint reg; 651 int ret; 652 653 ret = regmap_read(map, offset, &reg); 654 if (ret) 655 return ret; 656 657 reg &= ~mask; 658 659 return regmap_write(map, offset, reg | (val & mask)); 660} 661 662int regmap_field_read(struct regmap_field *field, unsigned int *val) 663{ 664 int ret; 665 unsigned int reg_val; 666 667 ret = regmap_read(field->regmap, field->reg, &reg_val); 668 if (ret != 0) 669 return ret; 670 671 reg_val &= field->mask; 672 reg_val >>= field->shift; 673 *val = reg_val; 674 675 return ret; 676} 677 678int regmap_field_write(struct regmap_field *field, unsigned int val) 679{ 680 return regmap_update_bits(field->regmap, field->reg, field->mask, 681 val << field->shift); 682} 683 684static void regmap_field_init(struct regmap_field *rm_field, 685 struct regmap *regmap, 686 struct reg_field reg_field) 687{ 688 rm_field->regmap = regmap; 689 rm_field->reg = reg_field.reg; 690 rm_field->shift = reg_field.lsb; 691 rm_field->mask = GENMASK(reg_field.msb, reg_field.lsb); 692} 693 694struct regmap_field *devm_regmap_field_alloc(struct udevice *dev, 695 struct regmap *regmap, 696 struct reg_field reg_field) 697{ 698 struct regmap_field *rm_field = devm_kzalloc(dev, sizeof(*rm_field), 699 GFP_KERNEL); 700 if (!rm_field) 701 return ERR_PTR(-ENOMEM); 702 703 regmap_field_init(rm_field, regmap, reg_field); 704 705 return rm_field; 706} 707 708void devm_regmap_field_free(struct udevice *dev, struct regmap_field *field) 709{ 710 devm_kfree(dev, field); 711} 712 713struct regmap_field *regmap_field_alloc(struct regmap *regmap, 714 struct reg_field reg_field) 715{ 716 struct regmap_field *rm_field = kzalloc(sizeof(*rm_field), GFP_KERNEL); 717 718 if (!rm_field) 719 return ERR_PTR(-ENOMEM); 720 721 regmap_field_init(rm_field, regmap, reg_field); 722 723 return rm_field; 724} 725 726void regmap_field_free(struct regmap_field *field) 727{ 728 kfree(field); 729}