Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 | // SPDX-License-Identifier: GPL-2.0 /* * Driver for Atmel QSPI Controller * * Copyright (C) 2015 Atmel Corporation * Copyright (C) 2018 Cryptera A/S * * Author: Cyrille Pitchen <cyrille.pitchen@atmel.com> * Author: Piotr Bugalski <bugalski.piotr@gmail.com> */ #include <malloc.h> #include <asm/gpio.h> #include <asm/io.h> #include <clk.h> #include <dm.h> #include <errno.h> #include <fdtdec.h> #include <log.h> #include <dm/device_compat.h> #include <linux/bitfield.h> #include <linux/bitops.h> #include <linux/err.h> #include <linux/io.h> #include <linux/iopoll.h> #include <linux/ioport.h> #include <mach/clk.h> #include <spi.h> #include <spi-mem.h> /* QSPI register offsets */ #define QSPI_CR 0x0000 /* Control Register */ #define QSPI_MR 0x0004 /* Mode Register */ #define QSPI_RD 0x0008 /* Receive Data Register */ #define QSPI_TD 0x000c /* Transmit Data Register */ #define QSPI_SR 0x0010 /* Status Register */ #define QSPI_SR2 0x0024 /* SAMA7G5 Status Register */ #define QSPI_IER 0x0014 /* Interrupt Enable Register */ #define QSPI_IDR 0x0018 /* Interrupt Disable Register */ #define QSPI_IMR 0x001c /* Interrupt Mask Register */ #define QSPI_SCR 0x0020 /* Serial Clock Register */ #define QSPI_IAR 0x0030 /* Instruction Address Register */ #define QSPI_ICR 0x0034 /* Instruction Code Register */ #define QSPI_WICR 0x0034 /* Write Instruction Code Register */ #define QSPI_IFR 0x0038 /* Instruction Frame Register */ #define QSPI_RICR 0x003C /* Read Instruction Code Register */ #define QSPI_SMR 0x0040 /* Scrambling Mode Register */ #define QSPI_SKR 0x0044 /* Scrambling Key Register */ #define QSPI_REFRESH 0x0050 /* Refresh Register */ #define QSPI_WRACNT 0x0054 /* Write Access Counter Register */ #define QSPI_DLLCFG 0x0058 /* DLL Configuration Register */ #define QSPI_PCALCFG 0x005C /* Pad Calibration Configuration Register */ #define QSPI_PCALBP 0x0060 /* Pad Calibration Bypass Register */ #define QSPI_TOUT 0x0064 /* Timeout Register */ #define QSPI_WPMR 0x00E4 /* Write Protection Mode Register */ #define QSPI_WPSR 0x00E8 /* Write Protection Status Register */ #define QSPI_VERSION 0x00FC /* Version Register */ /* Bitfields in QSPI_CR (Control Register) */ #define QSPI_CR_QSPIEN BIT(0) #define QSPI_CR_QSPIDIS BIT(1) #define QSPI_CR_DLLON BIT(2) #define QSPI_CR_DLLOFF BIT(3) #define QSPI_CR_STPCAL BIT(4) #define QSPI_CR_SRFRSH BIT(5) #define QSPI_CR_SWRST BIT(7) #define QSPI_CR_UPDCFG BIT(8) #define QSPI_CR_STTFR BIT(9) #define QSPI_CR_RTOUT BIT(10) #define QSPI_CR_LASTXFER BIT(24) /* Bitfields in QSPI_MR (Mode Register) */ #define QSPI_MR_SMM BIT(0) #define QSPI_MR_LLB BIT(1) #define QSPI_MR_WDRBT BIT(2) #define QSPI_MR_SMRM BIT(3) #define QSPI_MR_DQSDLYEN BIT(3) #define QSPI_MR_CSMODE_MASK GENMASK(5, 4) #define QSPI_MR_CSMODE_NOT_RELOADED (0 << 4) #define QSPI_MR_CSMODE_LASTXFER (1 << 4) #define QSPI_MR_CSMODE_SYSTEMATICALLY (2 << 4) #define QSPI_MR_NBBITS_MASK GENMASK(11, 8) #define QSPI_MR_NBBITS(n) ((((n) - 8) << 8) & QSPI_MR_NBBITS_MASK) #define QSPI_MR_OENSD BIT(15) #define QSPI_MR_DLYBCT_MASK GENMASK(23, 16) #define QSPI_MR_DLYBCT(n) (((n) << 16) & QSPI_MR_DLYBCT_MASK) #define QSPI_MR_DLYCS_MASK GENMASK(31, 24) #define QSPI_MR_DLYCS(n) (((n) << 24) & QSPI_MR_DLYCS_MASK) /* Bitfields in QSPI_SR/QSPI_IER/QSPI_IDR/QSPI_IMR */ #define QSPI_SR_RDRF BIT(0) #define QSPI_SR_TDRE BIT(1) #define QSPI_SR_TXEMPTY BIT(2) #define QSPI_SR_OVRES BIT(3) #define QSPI_SR_CSR BIT(8) #define QSPI_SR_CSS BIT(9) #define QSPI_SR_INSTRE BIT(10) #define QSPI_SR_LWRA BIT(11) #define QSPI_SR_QITF BIT(12) #define QSPI_SR_QITR BIT(13) #define QSPI_SR_CSFA BIT(14) #define QSPI_SR_CSRA BIT(15) #define QSPI_SR_RFRSHD BIT(16) #define QSPI_SR_TOUT BIT(17) #define QSPI_SR_QSPIENS BIT(24) #define QSPI_SR_CMD_COMPLETED (QSPI_SR_INSTRE | QSPI_SR_CSR) /* Bitfields in QSPI_SCR (Serial Clock Register) */ #define QSPI_SCR_CPOL BIT(0) #define QSPI_SCR_CPHA BIT(1) #define QSPI_SCR_SCBR_MASK GENMASK(15, 8) #define QSPI_SCR_SCBR(n) (((n) << 8) & QSPI_SCR_SCBR_MASK) #define QSPI_SCR_DLYBS_MASK GENMASK(23, 16) #define QSPI_SCR_DLYBS(n) (((n) << 16) & QSPI_SCR_DLYBS_MASK) /* Bitfields in QSPI_SR2 (SAMA7G5 Status Register) */ #define QSPI_SR2_SYNCBSY BIT(0) #define QSPI_SR2_QSPIENS BIT(1) #define QSPI_SR2_CSS BIT(2) #define QSPI_SR2_RBUSY BIT(3) #define QSPI_SR2_HIDLE BIT(4) #define QSPI_SR2_DLOCK BIT(5) #define QSPI_SR2_CALBSY BIT(6) /* Bitfields in QSPI_IAR (Instruction Address Register) */ #define QSPI_IAR_ADDR GENMASK(31, 0) /* Bitfields in QSPI_ICR (Read/Write Instruction Code Register) */ #define QSPI_ICR_INST_MASK GENMASK(7, 0) #define QSPI_ICR_INST(inst) (((inst) << 0) & QSPI_ICR_INST_MASK) #define QSPI_ICR_INST_MASK_SAMA7G5 GENMASK(15, 0) #define QSPI_ICR_OPT_MASK GENMASK(23, 16) #define QSPI_ICR_OPT(opt) (((opt) << 16) & QSPI_ICR_OPT_MASK) /* Bitfields in QSPI_IFR (Instruction Frame Register) */ #define QSPI_IFR_WIDTH_MASK GENMASK(2, 0) #define QSPI_IFR_WIDTH_SINGLE_BIT_SPI (0 << 0) #define QSPI_IFR_WIDTH_DUAL_OUTPUT (1 << 0) #define QSPI_IFR_WIDTH_QUAD_OUTPUT (2 << 0) #define QSPI_IFR_WIDTH_DUAL_IO (3 << 0) #define QSPI_IFR_WIDTH_QUAD_IO (4 << 0) #define QSPI_IFR_WIDTH_DUAL_CMD (5 << 0) #define QSPI_IFR_WIDTH_QUAD_CMD (6 << 0) #define QSPI_IFR_WIDTH_OCT_OUTPUT (7 << 0) #define QSPI_IFR_WIDTH_OCT_IO (8 << 0) #define QSPI_IFR_WIDTH_OCT_CMD (9 << 0) #define QSPI_IFR_INSTEN BIT(4) #define QSPI_IFR_ADDREN BIT(5) #define QSPI_IFR_OPTEN BIT(6) #define QSPI_IFR_DATAEN BIT(7) #define QSPI_IFR_OPTL_MASK GENMASK(9, 8) #define QSPI_IFR_OPTL_1BIT (0 << 8) #define QSPI_IFR_OPTL_2BIT (1 << 8) #define QSPI_IFR_OPTL_4BIT (2 << 8) #define QSPI_IFR_OPTL_8BIT (3 << 8) #define QSPI_IFR_ADDRL BIT(10) #define QSPI_IFR_ADDRL_SAMA7G5 GENMASK(11, 10) #define QSPI_IFR_TFRTYP_MEM BIT(12) #define QSPI_IFR_SAMA5D2_WRITE_TRSFR BIT(13) #define QSPI_IFR_CRM BIT(14) #define QSPI_IFR_DDREN BIT(15) #define QSPI_IFR_NBDUM_MASK GENMASK(20, 16) #define QSPI_IFR_NBDUM(n) (((n) << 16) & QSPI_IFR_NBDUM_MASK) #define QSPI_IFR_END BIT(22) #define QSPI_IFR_SMRM BIT(23) #define QSPI_IFR_APBTFRTYP_READ BIT(24) /* Defined in SAM9X60 */ #define QSPI_IFR_DQSEN BIT(25) #define QSPI_IFR_DDRCMDEN BIT(26) #define QSPI_IFR_HFWBEN BIT(27) #define QSPI_IFR_PROTTYP GENMASK(29, 28) #define QSPI_IFR_PROTTYP_STD_SPI 0 #define QSPI_IFR_PROTTYP_TWIN_QUAD 1 #define QSPI_IFR_PROTTYP_OCTAFLASH 2 #define QSPI_IFR_PROTTYP_HYPERFLASH 3 /* Bitfields in QSPI_SMR (Scrambling Mode Register) */ #define QSPI_SMR_SCREN BIT(0) #define QSPI_SMR_RVDIS BIT(1) #define QSPI_SMR_SCRKL BIT(2) /* Bitfields in QSPI_REFRESH (Refresh Register) */ #define QSPI_REFRESH_DELAY_COUNTER GENMASK(31, 0) /* Bitfields in QSPI_WRACNT (Write Access Counter Register) */ #define QSPI_WRACNT_NBWRA GENMASK(31, 0) /* Bitfields in QSPI_DLLCFG (DLL Configuration Register) */ #define QSPI_DLLCFG_RANGE BIT(0) /* Bitfields in QSPI_PCALCFG (DLL Pad Calibration Configuration Register) */ #define QSPI_PCALCFG_AAON BIT(0) #define QSPI_PCALCFG_DAPCAL BIT(1) #define QSPI_PCALCFG_DIFFPM BIT(2) #define QSPI_PCALCFG_CLKDIV GENMASK(6, 4) #define QSPI_PCALCFG_CALCNT GENMASK(16, 8) #define QSPI_PCALCFG_CALP GENMASK(27, 24) #define QSPI_PCALCFG_CALN GENMASK(31, 28) /* Bitfields in QSPI_PCALBP (DLL Pad Calibration Bypass Register) */ #define QSPI_PCALBP_BPEN BIT(0) #define QSPI_PCALBP_CALPBP GENMASK(11, 8) #define QSPI_PCALBP_CALNBP GENMASK(19, 16) /* Bitfields in QSPI_TOUT (Timeout Register) */ #define QSPI_TOUT_TCNTM GENMASK(15, 0) /* Bitfields in QSPI_WPMR (Write Protection Mode Register) */ #define QSPI_WPMR_WPEN BIT(0) #define QSPI_WPMR_WPITEN BIT(1) #define QSPI_WPMR_WPCREN BIT(2) #define QSPI_WPMR_WPKEY_MASK GENMASK(31, 8) #define QSPI_WPMR_WPKEY(wpkey) (((wpkey) << 8) & QSPI_WPMR_WPKEY_MASK) /* Bitfields in QSPI_WPSR (Write Protection Status Register) */ #define QSPI_WPSR_WPVS BIT(0) #define QSPI_WPSR_WPVSRC_MASK GENMASK(15, 8) #define QSPI_WPSR_WPVSRC(src) (((src) << 8) & QSPI_WPSR_WPVSRC) #define ATMEL_QSPI_TIMEOUT 1000000 /* us */ #define ATMEL_QSPI_SYNC_TIMEOUT 300000 /* us */ #define QSPI_DLLCFG_THRESHOLD_FREQ 90000000U #define QSPI_TOUT_MAX 0xffff /** * struct atmel_qspi_pcal - Pad Calibration Clock Division * @pclk_rate: peripheral clock rate. * @pclkdiv: calibration clock division. The clock applied to the calibration * cell is divided by pclkdiv + 1. */ struct atmel_qspi_pcal { u32 pclk_rate; u8 pclk_div; }; #define ATMEL_QSPI_PCAL_ARRAY_SIZE 8 static const struct atmel_qspi_pcal pcal[ATMEL_QSPI_PCAL_ARRAY_SIZE] = { {25000000, 0}, {50000000, 1}, {75000000, 2}, {100000000, 3}, {125000000, 4}, {150000000, 5}, {175000000, 6}, {200000000, 7}, }; struct atmel_qspi_caps { bool has_qspick; bool has_gclk; bool has_ricr; bool octal; }; struct atmel_qspi_priv_ops; #define MAX_CS_COUNT 2 struct atmel_qspi { void __iomem *regs; void __iomem *mem; resource_size_t mmap_size; const struct atmel_qspi_caps *caps; const struct atmel_qspi_priv_ops *ops; struct udevice *dev; ulong bus_clk_rate; u32 mr; struct gpio_desc cs_gpios[MAX_CS_COUNT]; }; struct atmel_qspi_priv_ops { int (*set_cfg)(struct atmel_qspi *aq, const struct spi_mem_op *op, u32 *offset); int (*transfer)(struct atmel_qspi *aq, const struct spi_mem_op *op, u32 offset); }; struct atmel_qspi_mode { u8 cmd_buswidth; u8 addr_buswidth; u8 data_buswidth; u32 config; }; static const struct atmel_qspi_mode atmel_qspi_modes[] = { { 1, 1, 1, QSPI_IFR_WIDTH_SINGLE_BIT_SPI }, { 1, 1, 2, QSPI_IFR_WIDTH_DUAL_OUTPUT }, { 1, 1, 4, QSPI_IFR_WIDTH_QUAD_OUTPUT }, { 1, 2, 2, QSPI_IFR_WIDTH_DUAL_IO }, { 1, 4, 4, QSPI_IFR_WIDTH_QUAD_IO }, { 2, 2, 2, QSPI_IFR_WIDTH_DUAL_CMD }, { 4, 4, 4, QSPI_IFR_WIDTH_QUAD_CMD }, }; static const struct atmel_qspi_mode atmel_qspi_sama7g5_modes[] = { { 1, 1, 1, QSPI_IFR_WIDTH_SINGLE_BIT_SPI }, { 1, 1, 2, QSPI_IFR_WIDTH_DUAL_OUTPUT }, { 1, 1, 4, QSPI_IFR_WIDTH_QUAD_OUTPUT }, { 1, 2, 2, QSPI_IFR_WIDTH_DUAL_IO }, { 1, 4, 4, QSPI_IFR_WIDTH_QUAD_IO }, { 2, 2, 2, QSPI_IFR_WIDTH_DUAL_CMD }, { 4, 4, 4, QSPI_IFR_WIDTH_QUAD_CMD }, { 1, 1, 8, QSPI_IFR_WIDTH_OCT_OUTPUT }, { 1, 8, 8, QSPI_IFR_WIDTH_OCT_IO }, { 8, 8, 8, QSPI_IFR_WIDTH_OCT_CMD }, }; #ifdef VERBOSE_DEBUG static const char *atmel_qspi_reg_name(u32 offset, char *tmp, size_t sz) { switch (offset) { case QSPI_CR: return "CR"; case QSPI_MR: return "MR"; case QSPI_RD: return "RD"; case QSPI_TD: return "TD"; case QSPI_SR: return "SR"; case QSPI_IER: return "IER"; case QSPI_IDR: return "IDR"; case QSPI_IMR: return "IMR"; case QSPI_SCR: return "SCR"; case QSPI_SR2: return "SR2"; case QSPI_IAR: return "IAR"; case QSPI_ICR: return "ICR/WICR"; case QSPI_IFR: return "IFR"; case QSPI_RICR: return "RICR"; case QSPI_SMR: return "SMR"; case QSPI_SKR: return "SKR"; case QSPI_REFRESH: return "REFRESH"; case QSPI_WRACNT: return "WRACNT"; case QSPI_DLLCFG: return "DLLCFG"; case QSPI_PCALCFG: return "PCALCFG"; case QSPI_PCALBP: return "PCALBP"; case QSPI_TOUT: return "TOUT"; case QSPI_WPMR: return "WPMR"; case QSPI_WPSR: return "WPSR"; case QSPI_VERSION: return "VERSION"; default: snprintf(tmp, sz, "0x%02x", offset); break; } return tmp; } #endif /* VERBOSE_DEBUG */ static u32 atmel_qspi_read(struct atmel_qspi *aq, u32 offset) { u32 value = readl(aq->regs + offset); #ifdef VERBOSE_DEBUG char tmp[16]; dev_vdbg(aq->dev, "read 0x%08x from %s\n", value, atmel_qspi_reg_name(offset, tmp, sizeof(tmp))); #endif /* VERBOSE_DEBUG */ return value; } static void atmel_qspi_write(u32 value, struct atmel_qspi *aq, u32 offset) { #ifdef VERBOSE_DEBUG char tmp[16]; dev_vdbg(aq->dev, "write 0x%08x into %s\n", value, atmel_qspi_reg_name(offset, tmp, sizeof(tmp))); #endif /* VERBOSE_DEBUG */ writel(value, aq->regs + offset); } static int atmel_qspi_reg_sync(struct atmel_qspi *aq) { u32 val; return readl_poll_timeout(aq->regs + QSPI_SR2, val, !(val & QSPI_SR2_SYNCBSY), ATMEL_QSPI_SYNC_TIMEOUT); } static int atmel_qspi_update_config(struct atmel_qspi *aq) { int ret; ret = atmel_qspi_reg_sync(aq); if (ret) return ret; atmel_qspi_write(QSPI_CR_UPDCFG, aq, QSPI_CR); return atmel_qspi_reg_sync(aq); } static inline bool atmel_qspi_is_compatible(const struct spi_mem_op *op, const struct atmel_qspi_mode *mode) { if (op->cmd.buswidth != mode->cmd_buswidth) return false; if (op->addr.nbytes && op->addr.buswidth != mode->addr_buswidth) return false; if (op->data.nbytes && op->data.buswidth != mode->data_buswidth) return false; return true; } static int atmel_qspi_find_mode(const struct spi_mem_op *op) { u32 i; for (i = 0; i < ARRAY_SIZE(atmel_qspi_modes); i++) if (atmel_qspi_is_compatible(op, &atmel_qspi_modes[i])) return i; return -ENOTSUPP; } static int atmel_qspi_sama7g5_find_mode(const struct spi_mem_op *op) { u32 i; for (i = 0; i < ARRAY_SIZE(atmel_qspi_sama7g5_modes); i++) if (atmel_qspi_is_compatible(op, &atmel_qspi_sama7g5_modes[i])) return i; return -EOPNOTSUPP; } static bool atmel_qspi_supports_op(struct spi_slave *slave, const struct spi_mem_op *op) { struct atmel_qspi *aq = dev_get_priv(slave->dev->parent); if (!spi_mem_default_supports_op(slave, op)) return false; if (aq->caps->octal) { if (atmel_qspi_sama7g5_find_mode(op) < 0) return false; else return true; } if (atmel_qspi_find_mode(op) < 0) return false; /* special case not supported by hardware */ if (op->addr.nbytes == 2 && op->cmd.buswidth != op->addr.buswidth && op->dummy.nbytes == 0) return false; return true; } /* * Switch QSPI controller between regular SPI mode or Serial Memory Mode (SMM). */ static int atmel_qspi_set_serial_memory_mode(struct atmel_qspi *aq, bool enable) { int ret = 0; /* only write if designated state differs from current state */ if (!!(aq->mr & QSPI_MR_SMM) != enable) { if (enable) aq->mr |= QSPI_MR_SMM; else aq->mr &= ~QSPI_MR_SMM; atmel_qspi_write(aq->mr, aq, QSPI_MR); if (aq->caps->has_gclk) ret = atmel_qspi_update_config(aq); } return ret; } static int atmel_qspi_set_cfg(struct atmel_qspi *aq, const struct spi_mem_op *op, u32 *offset) { u32 iar, icr, ifr; u32 dummy_cycles = 0; int mode; iar = 0; icr = QSPI_ICR_INST(op->cmd.opcode); ifr = QSPI_IFR_INSTEN; mode = atmel_qspi_find_mode(op); if (mode < 0) return mode; ifr |= atmel_qspi_modes[mode].config; if (op->dummy.nbytes) dummy_cycles = op->dummy.nbytes * 8 / op->dummy.buswidth; /* * The controller allows 24 and 32-bit addressing while NAND-flash * requires 16-bit long. Handling 8-bit long addresses is done using * the option field. For the 16-bit addresses, the workaround depends * of the number of requested dummy bits. If there are 8 or more dummy * cycles, the address is shifted and sent with the first dummy byte. * Otherwise opcode is disabled and the first byte of the address * contains the command opcode (works only if the opcode and address * use the same buswidth). The limitation is when the 16-bit address is * used without enough dummy cycles and the opcode is using a different * buswidth than the address. */ if (op->addr.buswidth) { switch (op->addr.nbytes) { case 0: break; case 1: ifr |= QSPI_IFR_OPTEN | QSPI_IFR_OPTL_8BIT; icr |= QSPI_ICR_OPT(op->addr.val & 0xff); break; case 2: if (dummy_cycles < 8 / op->addr.buswidth) { ifr &= ~QSPI_IFR_INSTEN; ifr |= QSPI_IFR_ADDREN; iar = (op->cmd.opcode << 16) | (op->addr.val & 0xffff); } else { ifr |= QSPI_IFR_ADDREN; iar = (op->addr.val << 8) & 0xffffff; dummy_cycles -= 8 / op->addr.buswidth; } break; case 3: ifr |= QSPI_IFR_ADDREN; iar = op->addr.val & 0xffffff; break; case 4: ifr |= QSPI_IFR_ADDREN | QSPI_IFR_ADDRL; iar = op->addr.val & 0x7ffffff; break; default: return -ENOTSUPP; } } /* offset of the data access in the QSPI memory space */ *offset = iar; /* Set number of dummy cycles */ if (dummy_cycles) ifr |= QSPI_IFR_NBDUM(dummy_cycles); /* Set data enable and data transfer type. */ if (op->data.nbytes) { ifr |= QSPI_IFR_DATAEN; if (op->addr.nbytes) ifr |= QSPI_IFR_TFRTYP_MEM; } mode = atmel_qspi_set_serial_memory_mode(aq, true); if (mode < 0) return mode; /* Clear pending interrupts */ (void)atmel_qspi_read(aq, QSPI_SR); /* Set QSPI Instruction Frame registers. */ if (op->addr.nbytes && !op->data.nbytes) atmel_qspi_write(iar, aq, QSPI_IAR); if (aq->caps->has_ricr) { if (op->data.dir == SPI_MEM_DATA_IN) atmel_qspi_write(icr, aq, QSPI_RICR); else atmel_qspi_write(icr, aq, QSPI_WICR); } else { if (op->data.nbytes && op->data.dir == SPI_MEM_DATA_OUT) ifr |= QSPI_IFR_SAMA5D2_WRITE_TRSFR; atmel_qspi_write(icr, aq, QSPI_ICR); } atmel_qspi_write(ifr, aq, QSPI_IFR); return 0; } static int atmel_qspi_transfer(struct atmel_qspi *aq, const struct spi_mem_op *op, u32 offset) { u32 imr, val = 0; unsigned long timeout; /* Skip to the final steps if there is no data */ if (op->data.nbytes) { /* Dummy read of QSPI_IFR to synchronize APB and AHB accesses */ (void)atmel_qspi_read(aq, QSPI_IFR); /* Send/Receive data */ if (op->data.dir == SPI_MEM_DATA_IN) memcpy_fromio(op->data.buf.in, aq->mem + offset, op->data.nbytes); else memcpy_toio(aq->mem + offset, op->data.buf.out, op->data.nbytes); /* Release the chip-select */ atmel_qspi_write(QSPI_CR_LASTXFER, aq, QSPI_CR); } /* Poll INSTruction End and Chip Select Rise flags. */ imr = QSPI_SR_INSTRE | QSPI_SR_CSR; timeout = timer_get_us() + ATMEL_QSPI_TIMEOUT; while (1) { val |= readl(aq->regs + QSPI_SR) & imr; if ((val & imr) == imr) return 0; if (time_after(timer_get_us(), timeout)) return -ETIMEDOUT; } } static int atmel_qspi_sama7g5_set_cfg(struct atmel_qspi *aq, const struct spi_mem_op *op, u32 *offset) { u32 iar, icr, ifr; int mode, ret; iar = 0; icr = FIELD_PREP(QSPI_ICR_INST_MASK_SAMA7G5, op->cmd.opcode); ifr = QSPI_IFR_INSTEN; mode = atmel_qspi_sama7g5_find_mode(op); if (mode < 0) return mode; ifr |= atmel_qspi_sama7g5_modes[mode].config; if (op->dummy.buswidth && op->dummy.nbytes) { if (op->addr.dtr && op->dummy.dtr && op->data.dtr) ifr |= QSPI_IFR_NBDUM(op->dummy.nbytes * 8 / (2 * op->dummy.buswidth)); else ifr |= QSPI_IFR_NBDUM(op->dummy.nbytes * 8 / op->dummy.buswidth); } if (op->addr.buswidth && op->addr.nbytes) { ifr |= FIELD_PREP(QSPI_IFR_ADDRL_SAMA7G5, op->addr.nbytes - 1) | QSPI_IFR_ADDREN; iar = FIELD_PREP(QSPI_IAR_ADDR, op->addr.val); } if (op->addr.dtr && op->dummy.dtr && op->data.dtr) { ifr |= QSPI_IFR_DDREN; if (op->cmd.dtr) ifr |= QSPI_IFR_DDRCMDEN; ifr |= QSPI_IFR_DQSEN; } if (op->cmd.buswidth == 8 || op->addr.buswidth == 8 || op->data.buswidth == 8) ifr |= FIELD_PREP(QSPI_IFR_PROTTYP, QSPI_IFR_PROTTYP_OCTAFLASH); /* offset of the data access in the QSPI memory space */ *offset = iar; /* Set data enable */ if (op->data.nbytes) { ifr |= QSPI_IFR_DATAEN; if (op->addr.nbytes) ifr |= QSPI_IFR_TFRTYP_MEM; } ret = atmel_qspi_set_serial_memory_mode(aq, true); if (ret < 0) return ret; /* Clear pending interrupts */ (void)atmel_qspi_read(aq, QSPI_SR); /* Set QSPI Instruction Frame registers */ if (op->addr.nbytes && !op->data.nbytes) atmel_qspi_write(iar, aq, QSPI_IAR); if (op->data.dir == SPI_MEM_DATA_IN) { atmel_qspi_write(icr, aq, QSPI_RICR); } else { atmel_qspi_write(icr, aq, QSPI_WICR); if (op->data.nbytes) atmel_qspi_write(FIELD_PREP(QSPI_WRACNT_NBWRA, op->data.nbytes), aq, QSPI_WRACNT); } atmel_qspi_write(ifr, aq, QSPI_IFR); return atmel_qspi_update_config(aq); } static int atmel_qspi_sama7g5_transfer(struct atmel_qspi *aq, const struct spi_mem_op *op, u32 offset) { int err; u32 val; if (!op->data.nbytes) { /* Start the transfer. */ err = atmel_qspi_reg_sync(aq); if (err) return err; atmel_qspi_write(QSPI_CR_STTFR, aq, QSPI_CR); return readl_poll_timeout(aq->regs + QSPI_SR, val, val & QSPI_SR_CSRA, ATMEL_QSPI_TIMEOUT); } /* Send/Receive data. */ if (op->data.dir == SPI_MEM_DATA_IN) { memcpy_fromio(op->data.buf.in, aq->mem + offset, op->data.nbytes); if (op->addr.nbytes) { err = readl_poll_timeout(aq->regs + QSPI_SR2, val, !(val & QSPI_SR2_RBUSY), ATMEL_QSPI_SYNC_TIMEOUT); if (err) return err; } } else { memcpy_toio(aq->mem + offset, op->data.buf.out, op->data.nbytes); err = readl_poll_timeout(aq->regs + QSPI_SR, val, val & QSPI_SR_LWRA, ATMEL_QSPI_TIMEOUT); if (err) return err; } /* Release the chip-select. */ err = atmel_qspi_reg_sync(aq); if (err) return err; atmel_qspi_write(QSPI_CR_LASTXFER, aq, QSPI_CR); return readl_poll_timeout(aq->regs + QSPI_SR, val, val & QSPI_SR_CSRA, ATMEL_QSPI_TIMEOUT); } static int atmel_qspi_exec_op(struct spi_slave *slave, const struct spi_mem_op *op) { struct atmel_qspi *aq = dev_get_priv(slave->dev->parent); u32 offset; int err; /* * Check if the address exceeds the MMIO window size. An improvement * would be to add support for regular SPI mode and fall back to it * when the flash memories overrun the controller's memory space. */ if (op->addr.val + op->data.nbytes > aq->mmap_size) return -ENOTSUPP; if (op->addr.nbytes > 4) return -EOPNOTSUPP; err = aq->ops->set_cfg(aq, op, &offset); if (err) return err; return aq->ops->transfer(aq, op, offset); } static int atmel_qspi_set_pad_calibration(struct udevice *bus, uint hz) { struct atmel_qspi *aq = dev_get_priv(bus); u32 status, val; int i, ret; u8 pclk_div = 0; for (i = 0; i < ATMEL_QSPI_PCAL_ARRAY_SIZE; i++) { if (aq->bus_clk_rate <= pcal[i].pclk_rate) { pclk_div = pcal[i].pclk_div; break; } } /* * Use the biggest divider in case the peripheral clock exceeds * 200MHZ. */ if (aq->bus_clk_rate > pcal[ATMEL_QSPI_PCAL_ARRAY_SIZE - 1].pclk_rate) pclk_div = pcal[ATMEL_QSPI_PCAL_ARRAY_SIZE - 1].pclk_div; /* Disable QSPI while configuring the pad calibration. */ status = atmel_qspi_read(aq, QSPI_SR2); if (status & QSPI_SR2_QSPIENS) { ret = atmel_qspi_reg_sync(aq); if (ret) return ret; atmel_qspi_write(QSPI_CR_QSPIDIS, aq, QSPI_CR); } /* * The analog circuitry is not shut down at the end of the calibration * and the start-up time is only required for the first calibration * sequence, thus increasing performance. Set the delay between the Pad * calibration analog circuitry and the calibration request to 2us. */ atmel_qspi_write(QSPI_PCALCFG_AAON | FIELD_PREP(QSPI_PCALCFG_CLKDIV, pclk_div) | FIELD_PREP(QSPI_PCALCFG_CALCNT, 2 * (aq->bus_clk_rate / 1000000)), aq, QSPI_PCALCFG); /* DLL On + start calibration. */ atmel_qspi_write(QSPI_CR_DLLON | QSPI_CR_STPCAL, aq, QSPI_CR); ret = readl_poll_timeout(aq->regs + QSPI_SR2, val, (val & QSPI_SR2_DLOCK) && !(val & QSPI_SR2_CALBSY), ATMEL_QSPI_TIMEOUT); /* Refresh analogic blocks every 1 ms.*/ atmel_qspi_write(FIELD_PREP(QSPI_REFRESH_DELAY_COUNTER, hz / 1000), aq, QSPI_REFRESH); return ret; } static int atmel_qspi_set_gclk(struct udevice *bus, uint hz) { struct atmel_qspi *aq = dev_get_priv(bus); struct clk gclk; u32 status, val; int ret; /* Disable DLL before setting GCLK */ status = atmel_qspi_read(aq, QSPI_SR2); if (status & QSPI_SR2_DLOCK) { atmel_qspi_write(QSPI_CR_DLLOFF, aq, QSPI_CR); ret = readl_poll_timeout(aq->regs + QSPI_SR2, val, !(val & QSPI_SR2_DLOCK), ATMEL_QSPI_TIMEOUT); if (ret) return ret; } if (hz > QSPI_DLLCFG_THRESHOLD_FREQ) atmel_qspi_write(QSPI_DLLCFG_RANGE, aq, QSPI_DLLCFG); else atmel_qspi_write(0, aq, QSPI_DLLCFG); ret = clk_get_by_name(bus, "gclk", &gclk); if (ret) { dev_err(bus, "Missing QSPI generic clock\n"); return ret; } ret = clk_disable(&gclk); if (ret) dev_err(bus, "Failed to disable QSPI generic clock\n"); ret = clk_set_rate(&gclk, hz); if (ret < 0) { dev_err(bus, "Failed to set generic clock rate.\n"); return ret; } ret = clk_enable(&gclk); if (ret) dev_err(bus, "Failed to enable QSPI generic clock\n"); return ret; } static int atmel_qspi_sama7g5_set_speed(struct udevice *bus, uint hz) { struct atmel_qspi *aq = dev_get_priv(bus); u32 val; int ret; ret = atmel_qspi_set_gclk(bus, hz); if (ret) return ret; if (aq->caps->octal) { ret = atmel_qspi_set_pad_calibration(bus, hz); if (ret) return ret; } else { atmel_qspi_write(QSPI_CR_DLLON, aq, QSPI_CR); ret = readl_poll_timeout(aq->regs + QSPI_SR2, val, val & QSPI_SR2_DLOCK, ATMEL_QSPI_TIMEOUT); } /* Set the QSPI controller by default in Serial Memory Mode */ aq->mr |= QSPI_MR_DQSDLYEN; ret = atmel_qspi_set_serial_memory_mode(aq, true); if (ret < 0) return ret; /* Enable the QSPI controller. */ ret = atmel_qspi_reg_sync(aq); if (ret) return ret; atmel_qspi_write(QSPI_CR_QSPIEN, aq, QSPI_CR); ret = readl_poll_timeout(aq->regs + QSPI_SR2, val, val & QSPI_SR2_QSPIENS, ATMEL_QSPI_SYNC_TIMEOUT); if (ret) return ret; if (aq->caps->octal) ret = readl_poll_timeout(aq->regs + QSPI_SR, val, val & QSPI_SR_RFRSHD, ATMEL_QSPI_TIMEOUT); atmel_qspi_write(FIELD_PREP(QSPI_TOUT_TCNTM, QSPI_TOUT_MAX), aq, QSPI_TOUT); return ret; } static int atmel_qspi_claim_bus(struct udevice *dev) { struct udevice *bus = dev_get_parent(dev); struct atmel_qspi *aq = dev_get_priv(bus); int ret; aq->mr &= ~QSPI_MR_CSMODE_MASK; aq->mr |= QSPI_MR_CSMODE_LASTXFER | QSPI_MR_WDRBT; atmel_qspi_write(aq->mr, aq, QSPI_MR); ret = atmel_qspi_set_serial_memory_mode(aq, false); if (ret) return log_ret(ret); /* de-assert all chip selects */ if (IS_ENABLED(CONFIG_DM_GPIO)) { for (int i = 0; i < ARRAY_SIZE(aq->cs_gpios); i++) { if (dm_gpio_is_valid(&aq->cs_gpios[i])) dm_gpio_set_value(&aq->cs_gpios[i], 0); } } atmel_qspi_write(QSPI_CR_QSPIEN, aq, QSPI_CR); return 0; } static int atmel_qspi_release_bus(struct udevice *dev) { struct udevice *bus = dev_get_parent(dev); struct atmel_qspi *aq = dev_get_priv(bus); /* de-assert all chip selects */ if (IS_ENABLED(CONFIG_DM_GPIO)) { for (int i = 0; i < ARRAY_SIZE(aq->cs_gpios); i++) { if (dm_gpio_is_valid(&aq->cs_gpios[i])) dm_gpio_set_value(&aq->cs_gpios[i], 0); } } atmel_qspi_write(QSPI_CR_QSPIDIS, aq, QSPI_CR); return 0; } static int atmel_qspi_set_cs(struct udevice *dev, int value) { struct udevice *bus = dev_get_parent(dev); struct atmel_qspi *aq = dev_get_priv(bus); int cs = spi_chip_select(dev); if (IS_ENABLED(CONFIG_DM_GPIO)) { if (!dm_gpio_is_valid(&aq->cs_gpios[cs])) return log_ret(-ENOENT); return dm_gpio_set_value(&aq->cs_gpios[cs], value); } else { return -ENOENT; } } static int atmel_qspi_xfer(struct udevice *dev, unsigned int bitlen, const void *dout, void *din, unsigned long flags) { struct udevice *bus = dev_get_parent(dev); struct atmel_qspi *aq = dev_get_priv(bus); unsigned int len, len_rx, len_tx; const u8 *txp = dout; u8 *rxp = din; u32 reg; int ret; if (bitlen == 0) goto out; if (bitlen % 8) { flags |= SPI_XFER_END; goto out; } len = bitlen / 8; if (flags & SPI_XFER_BEGIN) { ret = atmel_qspi_set_cs(dev, 1); if (ret) return log_ret(ret); reg = atmel_qspi_read(aq, QSPI_RD); } for (len_tx = 0, len_rx = 0; len_rx < len; ) { u32 status = atmel_qspi_read(aq, QSPI_SR); u8 value; if (status & QSPI_SR_OVRES) return log_ret(-1); if (len_tx < len && (status & QSPI_SR_TDRE)) { if (txp) value = *txp++; else value = 0; atmel_qspi_write(value, aq, QSPI_TD); len_tx++; } if (status & QSPI_SR_RDRF) { value = atmel_qspi_read(aq, QSPI_RD); if (rxp) *rxp++ = value; len_rx++; } } out: if (flags & SPI_XFER_END) { readl_poll_timeout(aq->regs + QSPI_SR, reg, reg & QSPI_SR_TXEMPTY, ATMEL_QSPI_TIMEOUT); atmel_qspi_write(QSPI_CR_LASTXFER, aq, QSPI_CR); ret = atmel_qspi_set_cs(dev, 0); if (ret) return log_ret(ret); } return 0; } static int atmel_qspi_set_speed(struct udevice *bus, uint hz) { struct atmel_qspi *aq = dev_get_priv(bus); u32 scr, scbr, mask, new_value; if (aq->caps->has_gclk) return atmel_qspi_sama7g5_set_speed(bus, hz); /* Compute the QSPI baudrate */ dev_dbg(bus, "bus_clk_rate: %lu, hz: %u\n", aq->bus_clk_rate, hz); scbr = DIV_ROUND_UP(aq->bus_clk_rate, hz); if (scbr > 0) scbr--; new_value = QSPI_SCR_SCBR(scbr); mask = QSPI_SCR_SCBR_MASK; scr = atmel_qspi_read(aq, QSPI_SCR); if ((scr & mask) == new_value) return 0; scr = (scr & ~mask) | new_value; atmel_qspi_write(scr, aq, QSPI_SCR); return 0; } static int atmel_qspi_set_mode(struct udevice *bus, uint mode) { struct atmel_qspi *aq = dev_get_priv(bus); u32 scr, mask, new_value = 0; if (mode & SPI_CPOL) new_value = QSPI_SCR_CPOL; if (mode & SPI_CPHA) new_value = QSPI_SCR_CPHA; mask = QSPI_SCR_CPOL | QSPI_SCR_CPHA; scr = atmel_qspi_read(aq, QSPI_SCR); if ((scr & mask) == new_value) return 0; scr = (scr & ~mask) | new_value; atmel_qspi_write(scr, aq, QSPI_SCR); if (aq->caps->has_gclk) return atmel_qspi_update_config(aq); return 0; } static int atmel_qspi_enable_clk(struct udevice *dev) { struct atmel_qspi *aq = dev_get_priv(dev); struct clk pclk, qspick, gclk; int ret; ret = clk_get_by_name(dev, "pclk", &pclk); if (ret) ret = clk_get_by_index(dev, 0, &pclk); if (ret) { dev_err(dev, "Missing QSPI peripheral clock\n"); return ret; } ret = clk_enable(&pclk); if (ret) { dev_err(dev, "Failed to enable QSPI peripheral clock\n"); return ret; } if (aq->caps->has_qspick) { /* Get the QSPI system clock */ ret = clk_get_by_name(dev, "qspick", &qspick); if (ret) { dev_err(dev, "Missing QSPI peripheral clock\n"); return ret; } ret = clk_enable(&qspick); if (ret) dev_err(dev, "Failed to enable QSPI system clock\n"); } else if (aq->caps->has_gclk) { ret = clk_get_by_name(dev, "gclk", &gclk); if (ret) { dev_err(dev, "Missing QSPI generic clock\n"); return ret; } ret = clk_enable(&gclk); if (ret) dev_err(dev, "Failed to enable QSPI system clock\n"); } aq->bus_clk_rate = clk_get_rate(&pclk); if (!aq->bus_clk_rate) return -EINVAL; return ret; } static int atmel_qspi_init(struct atmel_qspi *aq) { int ret; if (aq->caps->has_gclk) { ret = atmel_qspi_reg_sync(aq); if (ret) return ret; atmel_qspi_write(QSPI_CR_SWRST, aq, QSPI_CR); return 0; } /* Reset the QSPI controller */ atmel_qspi_write(QSPI_CR_SWRST, aq, QSPI_CR); /* Enable the QSPI controller */ atmel_qspi_write(QSPI_CR_QSPIEN, aq, QSPI_CR); return 0; } static const struct atmel_qspi_priv_ops atmel_qspi_priv_ops = { .set_cfg = atmel_qspi_set_cfg, .transfer = atmel_qspi_transfer, }; static const struct atmel_qspi_priv_ops atmel_qspi_sama7g5_priv_ops = { .set_cfg = atmel_qspi_sama7g5_set_cfg, .transfer = atmel_qspi_sama7g5_transfer, }; static int atmel_qspi_probe(struct udevice *dev) { struct atmel_qspi *aq = dev_get_priv(dev); struct resource res; int ret; aq->caps = (struct atmel_qspi_caps *)dev_get_driver_data(dev); if (!aq->caps) { dev_err(dev, "Could not retrieve QSPI caps\n"); return log_ret(-EINVAL); }; if (aq->caps->has_gclk) aq->ops = &atmel_qspi_sama7g5_priv_ops; else aq->ops = &atmel_qspi_priv_ops; if (IS_ENABLED(CONFIG_DM_GPIO)) { ret = gpio_request_list_by_name(dev, "cs-gpios", aq->cs_gpios, ARRAY_SIZE(aq->cs_gpios), 0); if (ret < 0) { pr_err("Can't get %s gpios! Error: %d", dev->name, ret); return log_ret(ret); } for (int i = 0; i < ARRAY_SIZE(aq->cs_gpios); i++) { if (!dm_gpio_is_valid(&aq->cs_gpios[i])) continue; dm_gpio_set_dir_flags(&aq->cs_gpios[i], GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE); } } /* Map the registers */ ret = dev_read_resource_byname(dev, "qspi_base", &res); if (ret) { dev_err(dev, "missing registers\n"); return log_ret(ret); } aq->regs = devm_ioremap(dev, res.start, resource_size(&res)); if (IS_ERR(aq->regs)) return log_ret(PTR_ERR(aq->regs)); /* Map the AHB memory */ ret = dev_read_resource_byname(dev, "qspi_mmap", &res); if (ret) { dev_err(dev, "missing AHB memory\n"); return log_ret(ret); } aq->mem = devm_ioremap(dev, res.start, resource_size(&res)); if (IS_ERR(aq->mem)) return log_ret(PTR_ERR(aq->mem)); aq->mmap_size = resource_size(&res); ret = atmel_qspi_enable_clk(dev); if (ret) return log_ret(ret); aq->dev = dev; return log_ret(atmel_qspi_init(aq)); } static const struct spi_controller_mem_ops atmel_qspi_mem_ops = { .supports_op = atmel_qspi_supports_op, .exec_op = atmel_qspi_exec_op, }; static const struct dm_spi_ops atmel_qspi_ops = { .claim_bus = atmel_qspi_claim_bus, .release_bus = atmel_qspi_release_bus, .xfer = atmel_qspi_xfer, .mem_ops = &atmel_qspi_mem_ops, .set_speed = atmel_qspi_set_speed, .set_mode = atmel_qspi_set_mode, }; static const struct atmel_qspi_caps atmel_sama5d2_qspi_caps = {}; static const struct atmel_qspi_caps atmel_sam9x60_qspi_caps = { .has_qspick = true, .has_ricr = true, }; static const struct atmel_qspi_caps atmel_sama7g5_ospi_caps = { .has_gclk = true, .octal = true, }; static const struct atmel_qspi_caps atmel_sama7g5_qspi_caps = { .has_gclk = true, }; static const struct udevice_id atmel_qspi_ids[] = { { .compatible = "atmel,sama5d2-qspi", .data = (ulong)&atmel_sama5d2_qspi_caps, }, { .compatible = "microchip,sam9x60-qspi", .data = (ulong)&atmel_sam9x60_qspi_caps, }, { .compatible = "microchip,sama7g5-ospi", .data = (ulong)&atmel_sama7g5_ospi_caps, }, { .compatible = "microchip,sama7g5-qspi", .data = (ulong)&atmel_sama7g5_qspi_caps, }, { /* sentinel */ } }; U_BOOT_DRIVER(atmel_qspi) = { .name = "atmel_qspi", .id = UCLASS_SPI, .of_match = atmel_qspi_ids, .ops = &atmel_qspi_ops, .priv_auto = sizeof(struct atmel_qspi), .probe = atmel_qspi_probe, }; |