aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc
diff options
context:
space:
mode:
authorRichard Zhu <r65037@freescale.com>2013-10-12 03:25:58 -0400
committerNitin Garg <nitin.garg@freescale.com>2014-04-16 09:05:57 -0400
commit1abc6093bc1d0ff70af0a2d2a2e6f06a0f93b674 (patch)
tree50a7a754676c597cc443ec8d740ff899e550245d /drivers/mmc
parent1296e0073da98f7829e0553d6bc9a3cb860e9f8f (diff)
ENGR00285671 mmc: setup emmc boot partition configure methods
- Configure boot partition Expose the interfaces that used to enable the configurations of the boot mode of the eMMC cards. usage how-to and examples: Enable the boot partition 1 boot enabled. "echo 8 > /sys/devices/soc0/soc.1/2100000.aips-bus/ 219c000.usdhc/mmc_host/mmc2/mmc2\:0001/boot_config" In order to make sure that the re-read the ext-csd of card can be completed successfully, add the method to wait for the finish of the busy state. - setup boot_info message output Output bit means of important esd_csd register Read esd_csd info each time when cat boot_info becasue user may change config affect esd_csd value. - Boot partition access howto: About the details, please refer to the guidance of Documentation/mmc/mmc-dev-parts.txt To enable write access to /dev/mmcblkXbootY, disable the forced read-only access with: echo 0 > /sys/block/mmcblkXbootY/force_ro To re-enable read-only access: echo 1 > /sys/block/mmcblkXbootY/force_ro NOTE: - The definitions of the EXT_CSD_PART_CONFIG and EXT_CSD_BOOT_BUS_WIDTH +------------------------------------------------------------+ | Bit7 | Bit6 | Bit5 Bit4 Bit3 | Bit2 Bit1 Bit0 | |------|----------|-----------------------|------------------| | X | BOOT_ACK | BOOT_PARTITION_ENABLE | PARTITION_ACCESS | +------------------------------------------------------------+ Bit7: Reserved Bit6: always set to vaule '1' when boot_part is enabled Bit[5:3]: 0x0 : Device not boot enabled (default) 0x1 : Boot partition 1 enabled for boot 0x2 : Boot partition 2 enabled for boot 0x7 : User area enabled for boot Bit[2:0]: 0x0 : No access to boot partition (default) 0x1 : R/W boot partition 1 0x2 : R/W boot partition 2 +--------------------------------------------------------------------+ | Bit7 Bit6 Bit5 | Bit4 Bit3 | Bit2 | Bit1 Bit0 | |----------------|----------------------------------|----------------| | X | BOOT_MODE | RESET_BOOT_BUS_WIDTH | BOOT_BUS_WIDTH | +--------------------------------------------------------------------+ Bit [4:3] : BOOT_MODE (non-volatile) 0x0 : Use single data rate + backward compatible timings in boot operation (default) 0x1 : Use single data rate + high speed timings in boot operation mode 0x2 : Use dual data rate in boot operation 0x3 : Reserved Bit [2]: RESET_BOOT_BUS_WIDTH (non-volatile) 0x0 : Reset bus width to x1, single data rate and backward compatible timings after boot operation (default) 0x1 : Retain boot bus width and boot mode after boot operation Bit[1:0] : BOOT_BUS_WIDTH (non-volatile) 0x0 : x1 (sdr) or x4 (ddr) bus width in boot operation mode (default) 0x1 : x4 (sdr/ddr) bus width in boot operation mode 0x2 : x8 (sdr/ddr) bus width in boot operation mode 0x3 : Reserved - example of the boot_info: boot_info:0x07; ALT_BOOT_MODE:1 - Supports alternate boot method DDR_BOOT_MODE:1 - Supports alternate dual data rate during boot HS_BOOTMODE:1 - Supports high speed timing during boot boot_size:2048KB boot_partition:0x48; BOOT_ACK:1 - Boot acknowledge sent during boot operation BOOT_PARTITION-ENABLE: 1 - Boot partition 1 enabled PARTITION_ACCESS:0 - No access to boot partition boot_bus:0x00 BOOT_MODE:0 - Use single data rate + backward compatible timings in boot operation RESET_BOOT_BUS_WIDTH:0 - Reset bus width to x1, single data rate and backwardcompatible timings after boot operation BOOT_BUS_WIDTH:0 - x1 (sdr) or x4 (ddr) bus width in boot operation mode Signed-off-by: Richard Zhu <r65037@freescale.com>
Diffstat (limited to 'drivers/mmc')
-rw-r--r--drivers/mmc/core/mmc.c377
1 files changed, 377 insertions, 0 deletions
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 0cbd1effe960..13814148077e 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -316,6 +316,11 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
316 mmc_card_set_blockaddr(card); 316 mmc_card_set_blockaddr(card);
317 } 317 }
318 318
319 card->ext_csd.boot_info = ext_csd[EXT_CSD_BOOT_INFO];
320 card->ext_csd.boot_config = ext_csd[EXT_CSD_PART_CONFIG];
321 card->ext_csd.boot_size = ext_csd[EXT_CSD_BOOT_MULT];
322 card->ext_csd.boot_bus_width = ext_csd[EXT_CSD_BOOT_BUS_WIDTH];
323
319 card->ext_csd.raw_card_type = ext_csd[EXT_CSD_CARD_TYPE]; 324 card->ext_csd.raw_card_type = ext_csd[EXT_CSD_CARD_TYPE];
320 mmc_select_card_type(card); 325 mmc_select_card_type(card);
321 326
@@ -616,6 +621,372 @@ out:
616 return err; 621 return err;
617} 622}
618 623
624static ssize_t mmc_boot_info_show(struct device *dev,
625 struct device_attribute *attr, char *buf)
626{
627 char *boot_partition[8] = {
628 "Device not boot enabled",
629 "Boot partition 1 enabled",
630 "Boot partition 2 enabled",
631 "Reserved",
632 "Reserved",
633 "Reserved",
634 "Reserved",
635 "User area enabled for boot"};
636
637 char *bus_width[4] = {
638 "x1 (sdr) or x4 (ddr) bus width in boot operation mode",
639 "x4 (sdr/ddr) bus width in boot operation mode",
640 "x8 (sdr/ddr) bus width in boot operation mode",
641 "Reserved"};
642
643 char *boot_mode[4] = {
644 "Use single data rate + backward compatible timings in boot operation",
645 "Use single data rate + high speed timings in boot operation mode",
646 "Use dual data rate in boot operation",
647 "Reserved"};
648
649 int partition;
650 int width;
651 int mode;
652 int err;
653 u8 *ext_csd = NULL;
654 struct mmc_card *card = container_of(dev, struct mmc_card, dev);
655
656 /* read it again because user may change it */
657 mmc_claim_host(card->host);
658 err = mmc_get_ext_csd(card, &ext_csd);
659 mmc_release_host(card->host);
660 if (err || !ext_csd) {
661 pr_err("%s: failed to get ext_csd, err=%d\n",
662 mmc_hostname(card->host),
663 err);
664 return err;
665 }
666
667 mmc_read_ext_csd(card, ext_csd);
668 mmc_free_ext_csd(ext_csd);
669
670 partition = (card->ext_csd.boot_config >> 3) & 0x7;
671 width = card->ext_csd.boot_bus_width & 0x3;
672 mode = (card->ext_csd.boot_bus_width >> 3) & 0x3;
673
674 return sprintf(buf,
675 "boot_info:0x%02x;\n"
676 " ALT_BOOT_MODE:%x - %s\n"
677 " DDR_BOOT_MODE:%x - %s\n"
678 " HS_BOOTMODE:%x - %s\n"
679 "boot_size:%04dKB\n"
680 "boot_partition:0x%02x;\n"
681 " BOOT_ACK:%x - %s\n"
682 " BOOT_PARTITION-ENABLE: %x - %s\n"
683 "boot_bus:0x%02x\n"
684 " BOOT_MODE:%x - %s\n"
685 " RESET_BOOT_BUS_WIDTH:%x - %s\n"
686 " BOOT_BUS_WIDTH:%x - %s\n",
687
688 card->ext_csd.boot_info,
689 !!(card->ext_csd.boot_info & 0x1),
690 (card->ext_csd.boot_info & 0x1) ?
691 "Supports alternate boot method" :
692 "Does not support alternate boot method",
693 !!(card->ext_csd.boot_info & 0x2),
694 (card->ext_csd.boot_info & 0x2) ?
695 "Supports alternate dual data rate during boot" :
696 "Does not support dual data rate during boot",
697 !!(card->ext_csd.boot_info & 0x4),
698 (card->ext_csd.boot_info & 0x4) ?
699 "Supports high speed timing during boot" :
700 "Does not support high speed timing during boot",
701
702 card->ext_csd.boot_size * 128,
703
704 card->ext_csd.boot_config,
705 !!(card->ext_csd.boot_config & 0x40),
706 (card->ext_csd.boot_config & 0x40) ?
707 "Boot acknowledge sent during boot operation" :
708 "No boot acknowledge sent",
709 partition,
710 boot_partition[partition],
711
712 card->ext_csd.boot_bus_width,
713 mode,
714 boot_mode[mode],
715 !!(card->ext_csd.boot_bus_width & 0x4),
716 (card->ext_csd.boot_bus_width & 0x4) ?
717 "Retain boot bus width and boot mode after boot operation" :
718 "Reset bus width to x1, single data rate and backward"
719 "compatible timings after boot operation",
720 width,
721 bus_width[width]);
722}
723
724/* set up boot partitions */
725static ssize_t
726setup_boot_partitions(struct device *dev, struct device_attribute *attr,
727 const char *buf, size_t count)
728{
729 int err, busy = 0;
730 u32 part;
731 u8 *ext_csd, boot_config;
732 struct mmc_command cmd;
733 struct mmc_card *card = container_of(dev, struct mmc_card, dev);
734
735 BUG_ON(!card);
736
737 sscanf(buf, "%d\n", &part);
738
739 if (card->csd.mmca_vsn < CSD_SPEC_VER_4) {
740 pr_err("%s: invalid mmc version" \
741 " mmc version is below version 4!)\n",
742 mmc_hostname(card->host));
743 return -EINVAL;
744 }
745
746 /* it's a normal SD/MMC but user request to configure boot partition */
747 if (card->ext_csd.boot_size <= 0) {
748 pr_err("%s: fail to send SWITCH command to card " \
749 "to update boot_config of the EXT_CSD!\n",
750 mmc_hostname(card->host));
751 return -EINVAL;
752 }
753
754 /*
755 * partition must be -
756 * 0 - user area
757 * 1 - boot partition 1
758 * 2 - boot partition 2
759 * DO NOT switch the partitions that used to be accessed
760 * in OS layer HERE
761 */
762 if (part & EXT_CSD_BOOT_PARTITION_ACCESS_MASK) {
763 pr_err("%s: DO NOT switch the partitions that used to be\n" \
764 " accessed in OS layer HERE. please following the\n" \
765 " guidance of Documentation/mmc/mmc-dev-parts.txt.\n",
766 mmc_hostname(card->host));
767 return -EINVAL;
768 }
769
770 ext_csd = kmalloc(512, GFP_KERNEL);
771 if (!ext_csd) {
772 pr_err("%s: could not allocate a buffer to " \
773 "receive the ext_csd.\n", mmc_hostname(card->host));
774 return -ENOMEM;
775 }
776
777 mmc_claim_host(card->host);
778 err = mmc_send_ext_csd(card, ext_csd);
779 if (err) {
780 pr_err("%s: unable to read EXT_CSD.\n",
781 mmc_hostname(card->host));
782 goto err_rtn;
783 }
784
785 /* enable the boot partition in boot mode */
786 /* boot enable be -
787 * 0x00 - disable boot enable.
788 * 0x08 - boot partition 1 is enabled for boot.
789 * 0x10 - boot partition 2 is enabled for boot.
790 * 0x38 - User area is enabled for boot.
791 */
792 switch (part & EXT_CSD_BOOT_PARTITION_ENABLE_MASK) {
793 case 0:
794 boot_config = (ext_csd[EXT_CSD_PART_CONFIG]
795 & ~EXT_CSD_BOOT_PARTITION_ENABLE_MASK
796 & ~EXT_CSD_BOOT_ACK_ENABLE);
797 break;
798 case EXT_CSD_BOOT_PARTITION_PART1:
799 boot_config = ((ext_csd[EXT_CSD_PART_CONFIG]
800 & ~EXT_CSD_BOOT_PARTITION_ENABLE_MASK)
801 | EXT_CSD_BOOT_PARTITION_PART1
802 | EXT_CSD_BOOT_ACK_ENABLE);
803 break;
804 case EXT_CSD_BOOT_PARTITION_PART2:
805 boot_config = ((ext_csd[EXT_CSD_PART_CONFIG]
806 & ~EXT_CSD_BOOT_PARTITION_ENABLE_MASK)
807 | EXT_CSD_BOOT_PARTITION_PART2
808 | EXT_CSD_BOOT_ACK_ENABLE);
809 break;
810 case EXT_CSD_BOOT_PARTITION_ENABLE_MASK:
811 boot_config = ((ext_csd[EXT_CSD_PART_CONFIG]
812 | EXT_CSD_BOOT_PARTITION_ENABLE_MASK)
813 & ~EXT_CSD_BOOT_ACK_ENABLE);
814 break;
815 default:
816 pr_err("%s: wrong boot config parameter" \
817 " 00 (disable boot), 08 (enable boot1)," \
818 "16 (enable boot2), 56 (User area)\n",
819 mmc_hostname(card->host));
820 err = -EINVAL;
821 goto err_rtn;
822 }
823
824 err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
825 EXT_CSD_PART_CONFIG, boot_config, card->ext_csd.part_time);
826 if (err) {
827 pr_err("%s: fail to send SWITCH command to card " \
828 "to update boot_config of the EXT_CSD!\n",
829 mmc_hostname(card->host));
830 goto err_rtn;
831 }
832
833 /* waiting for the card to finish the busy state */
834 do {
835 memset(&cmd, 0, sizeof(struct mmc_command));
836
837 cmd.opcode = MMC_SEND_STATUS;
838 cmd.arg = card->rca << 16;
839 cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
840
841 err = mmc_wait_for_cmd(card->host, &cmd, 0);
842 if (err || busy > 100) {
843 pr_err("%s: failed to wait for" \
844 "the busy state to end.\n",
845 mmc_hostname(card->host));
846 break;
847 }
848
849 if (!busy && !(cmd.resp[0] & R1_READY_FOR_DATA)) {
850 pr_info("%s: card is in busy state" \
851 "pls wait for busy state to end.\n",
852 mmc_hostname(card->host));
853 }
854 busy++;
855 } while (!(cmd.resp[0] & R1_READY_FOR_DATA));
856
857 /* Now check whether it works */
858 err = mmc_send_ext_csd(card, ext_csd);
859 if (err) {
860 pr_err("%s: %d unable to re-read EXT_CSD.\n",
861 mmc_hostname(card->host), err);
862 goto err_rtn;
863 }
864
865 card->ext_csd.boot_config = ext_csd[EXT_CSD_PART_CONFIG];
866
867err_rtn:
868 mmc_release_host(card->host);
869 kfree(ext_csd);
870 if (err)
871 return err;
872 else
873 return count;
874}
875
876/* configure the boot bus */
877static ssize_t
878setup_boot_bus(struct device *dev, struct device_attribute *attr,
879 const char *buf, size_t count)
880{
881 int err, busy = 0;
882 u32 boot_bus, new_bus;
883 u8 *ext_csd;
884 struct mmc_command cmd;
885 struct mmc_card *card = container_of(dev, struct mmc_card, dev);
886
887 BUG_ON(!card);
888
889 sscanf(buf, "%d\n", &boot_bus);
890
891 if (card->csd.mmca_vsn < CSD_SPEC_VER_4) {
892 pr_err("%s: invalid mmc version" \
893 " mmc version is below version 4!)\n",
894 mmc_hostname(card->host));
895 return -EINVAL;
896 }
897
898 /* it's a normal SD/MMC but user request to configure boot bus */
899 if (card->ext_csd.boot_size <= 0) {
900 pr_err("%s: this is a normal SD/MMC card" \
901 " but you request to configure boot bus !\n",
902 mmc_hostname(card->host));
903 return -EINVAL;
904 }
905
906 ext_csd = kmalloc(512, GFP_KERNEL);
907 if (!ext_csd) {
908 pr_err("%s: could not allocate a buffer to " \
909 "receive the ext_csd.\n", mmc_hostname(card->host));
910 return -ENOMEM;
911 }
912
913 mmc_claim_host(card->host);
914 err = mmc_send_ext_csd(card, ext_csd);
915 if (err) {
916 pr_err("%s: unable to read EXT_CSD.\n",
917 mmc_hostname(card->host));
918 goto err_rtn;
919 }
920
921 /* Configure the boot bus width when boot partition is enabled */
922 if (((boot_bus & EXT_CSD_BOOT_BUS_WIDTH_MODE_MASK) >> 3) > 2
923 || (boot_bus & EXT_CSD_BOOT_BUS_WIDTH_WIDTH_MASK) > 2
924 || (boot_bus & ~EXT_CSD_BOOT_BUS_WIDTH_MASK) > 0) {
925 pr_err("%s: Invalid inputs!\n",
926 mmc_hostname(card->host));
927 err = -EINVAL;
928 goto err_rtn;
929 }
930
931 err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
932 EXT_CSD_BOOT_BUS_WIDTH, boot_bus, card->ext_csd.part_time);
933 if (err) {
934 pr_err("%s: fail to send SWITCH command to card " \
935 "to update boot_config of the EXT_CSD!\n",
936 mmc_hostname(card->host));
937 goto err_rtn;
938 }
939
940 /* waiting for the card to finish the busy state */
941 do {
942 memset(&cmd, 0, sizeof(struct mmc_command));
943
944 cmd.opcode = MMC_SEND_STATUS;
945 cmd.arg = card->rca << 16;
946 cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
947
948 err = mmc_wait_for_cmd(card->host, &cmd, 0);
949 if (err || busy > 100) {
950 pr_err("%s: failed to wait for" \
951 "the busy state to end.\n",
952 mmc_hostname(card->host));
953 break;
954 }
955
956 if (!busy && !(cmd.resp[0] & R1_READY_FOR_DATA)) {
957 pr_info("%s: card is in busy state" \
958 "pls wait for busy state to end.\n",
959 mmc_hostname(card->host));
960 }
961 busy++;
962 } while (!(cmd.resp[0] & R1_READY_FOR_DATA));
963
964 /* Now check whether it works */
965 err = mmc_send_ext_csd(card, ext_csd);
966 if (err) {
967 pr_err("%s: %d unable to re-read EXT_CSD.\n",
968 mmc_hostname(card->host), err);
969 goto err_rtn;
970 }
971
972 new_bus = ext_csd[EXT_CSD_BOOT_BUS_WIDTH];
973 if (boot_bus != new_bus) {
974 pr_err("%s: after SWITCH, current boot bus mode %d" \
975 " is not same as requested bus mode %d!\n",
976 mmc_hostname(card->host), new_bus, boot_bus);
977 goto err_rtn;
978 }
979 card->ext_csd.boot_bus_width = ext_csd[EXT_CSD_BOOT_BUS_WIDTH];
980
981err_rtn:
982 mmc_release_host(card->host);
983 mmc_free_ext_csd(ext_csd);
984 if (err)
985 return err;
986 else
987 return count;
988}
989
619MMC_DEV_ATTR(cid, "%08x%08x%08x%08x\n", card->raw_cid[0], card->raw_cid[1], 990MMC_DEV_ATTR(cid, "%08x%08x%08x%08x\n", card->raw_cid[0], card->raw_cid[1],
620 card->raw_cid[2], card->raw_cid[3]); 991 card->raw_cid[2], card->raw_cid[3]);
621MMC_DEV_ATTR(csd, "%08x%08x%08x%08x\n", card->raw_csd[0], card->raw_csd[1], 992MMC_DEV_ATTR(csd, "%08x%08x%08x%08x\n", card->raw_csd[0], card->raw_csd[1],
@@ -635,6 +1006,9 @@ MMC_DEV_ATTR(enhanced_area_offset, "%llu\n",
635MMC_DEV_ATTR(enhanced_area_size, "%u\n", card->ext_csd.enhanced_area_size); 1006MMC_DEV_ATTR(enhanced_area_size, "%u\n", card->ext_csd.enhanced_area_size);
636MMC_DEV_ATTR(raw_rpmb_size_mult, "%#x\n", card->ext_csd.raw_rpmb_size_mult); 1007MMC_DEV_ATTR(raw_rpmb_size_mult, "%#x\n", card->ext_csd.raw_rpmb_size_mult);
637MMC_DEV_ATTR(rel_sectors, "%#x\n", card->ext_csd.rel_sectors); 1008MMC_DEV_ATTR(rel_sectors, "%#x\n", card->ext_csd.rel_sectors);
1009DEVICE_ATTR(boot_info, S_IRUGO, mmc_boot_info_show, NULL);
1010DEVICE_ATTR(boot_config, S_IWUGO, NULL, setup_boot_partitions);
1011DEVICE_ATTR(boot_bus_config, S_IWUGO, NULL, setup_boot_bus);
638 1012
639static struct attribute *mmc_std_attrs[] = { 1013static struct attribute *mmc_std_attrs[] = {
640 &dev_attr_cid.attr, 1014 &dev_attr_cid.attr,
@@ -653,6 +1027,9 @@ static struct attribute *mmc_std_attrs[] = {
653 &dev_attr_enhanced_area_size.attr, 1027 &dev_attr_enhanced_area_size.attr,
654 &dev_attr_raw_rpmb_size_mult.attr, 1028 &dev_attr_raw_rpmb_size_mult.attr,
655 &dev_attr_rel_sectors.attr, 1029 &dev_attr_rel_sectors.attr,
1030 &dev_attr_boot_info.attr,
1031 &dev_attr_boot_config.attr,
1032 &dev_attr_boot_bus_config.attr,
656 NULL, 1033 NULL,
657}; 1034};
658 1035